feat(merge-gate): auto-rebase onto current main + re-test + serialise merges (ORCH-043) #54

Merged
admin merged 7 commits from feature/ORCH-043-merge-gate-auto-rebase-re-test into main 2026-06-06 21:24:34 +03:00
Owner

Summary

  • Deterministic (no-LLM) merge-gate sub-gate on the deploy-staging → deploy edge: catches a feature branch up to the current origin/main, re-tests the combined tree, and serialises merges with a per-repo file lease — so two green parallel branches can't break main (self-hosting safety for the orchestrator repo).
  • New src/merge_gate.py (never-raise; all git ops in the per-branch worktree): branch_is_behind_main, auto_rebase_onto_main (push --force-with-lease only the task branch, never main), retest_branch, file merge-lease (atomic O_CREAT|O_EXCL, holder-aware release, stale/corrupt reclaim).
  • New QG check_branch_mergeable (src/qg/checks.py, registered in QG_CHECKS) composes the primitives under the lease. Conditional rollout: merge_gate_enabled kill-switch + merge_gate_repos CSV (default: self-hosting orchestrator only).
  • src/stage_engine.py: sub-gate hook on deploy-staging (not a new STAGE_TRANSITIONS stage). PASS → advance; merge-lock busyDEFER (re-queue with available_at, anti-deadlock at max_concurrency=1, capped by merge_defer_max_attempts); conflict / red re-test → rollback to development + developer retry (capped by MAX_DEVELOPER_RETRIES). Lease released on deploy→done / rollback / PR-merged webhook.
  • src/db.py: enqueue_job(available_at_delay_s=...) for the defer (no schema change). src/webhooks/gitea.py: holder-aware lease release on PR-merged.
  • New settings ORCH_MERGE_* (src/config.py, .env.example). Docs: README + adr-0006 already describe the design; CHANGELOG.md updated.

Test plan

  • tests/test_merge_gate.py — TC-01..11: behind-detection, rebase (clean push-with-lease / conflict abort / never pushes main), re-test (green/red/timeout), lease (busy/holder-aware/stale/missing) — real local git.
  • tests/test_qg_merge_gate.py — TC-12..17: gate composition + lease lifecycle, conditionality no-ops, never-raise.
  • tests/test_merge_gate_race.py — TC-24: parallel-merge race; origin/main SHA asserted unchanged.
  • tests/test_stage_engine.py::TestMergeGate — TC-20..23: PASS advance / busy DEFER (+exhaustion) / conflict+red rollback / retry cap / non-self-hosting no-op.
  • tests/test_config.py — TC-25: ORCH_MERGE_* defaults + env override.
  • tests/test_qg_registry_snapshot.pycheck_branch_mergeable in the registry contract.
  • Full suite: 535 passed.

🤖 Generated with Claude Code

Refs: ORCH-043

## Summary - Deterministic (no-LLM) **merge-gate** sub-gate on the `deploy-staging → deploy` edge: catches a feature branch up to the **current** `origin/main`, re-tests the combined tree, and serialises merges with a per-repo file lease — so two green parallel branches can't break `main` (self-hosting safety for the `orchestrator` repo). - New `src/merge_gate.py` (never-raise; all git ops in the per-branch worktree): `branch_is_behind_main`, `auto_rebase_onto_main` (`push --force-with-lease` **only** the task branch, **never** `main`), `retest_branch`, file merge-lease (atomic `O_CREAT|O_EXCL`, holder-aware release, stale/corrupt reclaim). - New QG `check_branch_mergeable` (`src/qg/checks.py`, registered in `QG_CHECKS`) composes the primitives under the lease. Conditional rollout: `merge_gate_enabled` kill-switch + `merge_gate_repos` CSV (default: self-hosting `orchestrator` only). - `src/stage_engine.py`: sub-gate hook on `deploy-staging` (**not** a new `STAGE_TRANSITIONS` stage). PASS → advance; `merge-lock busy` → **DEFER** (re-queue with `available_at`, anti-deadlock at `max_concurrency=1`, capped by `merge_defer_max_attempts`); conflict / red re-test → **rollback** to `development` + developer retry (capped by `MAX_DEVELOPER_RETRIES`). Lease released on `deploy→done` / rollback / PR-merged webhook. - `src/db.py`: `enqueue_job(available_at_delay_s=...)` for the defer (no schema change). `src/webhooks/gitea.py`: holder-aware lease release on PR-merged. - New settings `ORCH_MERGE_*` (`src/config.py`, `.env.example`). Docs: README + `adr-0006` already describe the design; `CHANGELOG.md` updated. ## Test plan - [x] `tests/test_merge_gate.py` — TC-01..11: behind-detection, rebase (clean push-with-lease / conflict abort / never pushes main), re-test (green/red/timeout), lease (busy/holder-aware/stale/missing) — real local git. - [x] `tests/test_qg_merge_gate.py` — TC-12..17: gate composition + lease lifecycle, conditionality no-ops, never-raise. - [x] `tests/test_merge_gate_race.py` — TC-24: parallel-merge race; `origin/main` SHA asserted unchanged. - [x] `tests/test_stage_engine.py::TestMergeGate` — TC-20..23: PASS advance / busy DEFER (+exhaustion) / conflict+red rollback / retry cap / non-self-hosting no-op. - [x] `tests/test_config.py` — TC-25: `ORCH_MERGE_*` defaults + env override. - [x] `tests/test_qg_registry_snapshot.py` — `check_branch_mergeable` in the registry contract. - [x] Full suite: **535 passed**. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Refs: ORCH-043
admin added 4 commits 2026-06-06 20:33:42 +03:00
docs: init ORCH-043 business request
All checks were successful
CI / test (push) Successful in 14s
445807dd90
analyst(ET): auto-commit from analyst run_id=182
All checks were successful
CI / test (push) Successful in 14s
77e7205ce8
architect(ET): auto-commit from architect run_id=183
All checks were successful
CI / test (push) Successful in 14s
ad1589084b
feat(merge-gate): auto-rebase onto current main + re-test + serialise merges
All checks were successful
CI / test (push) Successful in 15s
CI / test (pull_request) Successful in 17s
00d69d9e27
Deterministic (no-LLM) sub-gate on the deploy-staging -> deploy edge that
catches a feature branch up to the CURRENT origin/main, re-tests the combined
tree, and serialises merges with a per-repo file lease — so two green parallel
branches can no longer break main (self-hosting safety for the orchestrator repo).

- src/merge_gate.py: branch_is_behind_main, auto_rebase_onto_main (push
  --force-with-lease ONLY the task branch, NEVER main), retest_branch, and a
  file merge-lease (atomic O_CREAT|O_EXCL, holder-aware release, stale reclaim).
  Strict never-raise contract; all git ops in the per-branch worktree.
- src/qg/checks.py: check_branch_mergeable composes the primitives under the
  lease; registered in QG_CHECKS. Conditional rollout (merge_gate_enabled /
  merge_gate_repos, default self-hosting only).
- src/stage_engine.py: sub-gate hook on deploy-staging (not a new stage). PASS ->
  advance; "merge-lock busy" -> DEFER (re-queue with available_at, anti-deadlock
  at max_concurrency=1, capped); conflict/red re-test -> rollback to development
  + developer retry (capped by MAX_DEVELOPER_RETRIES). Lease released on
  deploy->done / rollback / PR-merged webhook.
- src/db.py: enqueue_job(available_at_delay_s=...) for the defer (no schema change).
- src/webhooks/gitea.py: holder-aware lease release on PR-merged.
- src/config.py + .env.example: ORCH_MERGE_* settings.

Docs: README + adr-0006 (architect) already cover the design; CHANGELOG updated.
Tests: test_merge_gate.py, test_qg_merge_gate.py, test_merge_gate_race.py,
test_stage_engine.py::TestMergeGate, test_config.py, QG-registry snapshot.
Full suite: 535 passed.

Refs: ORCH-043

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
admin added 1 commit 2026-06-06 20:37:06 +03:00
reviewer(ET): auto-commit from reviewer run_id=185
All checks were successful
CI / test (push) Successful in 19s
CI / test (pull_request) Successful in 18s
ba51aa17bc
admin added 1 commit 2026-06-06 20:38:39 +03:00
tester(ET): auto-commit from tester run_id=186
All checks were successful
CI / test (push) Successful in 17s
CI / test (pull_request) Successful in 15s
581a8b595a
admin added 1 commit 2026-06-06 20:41:25 +03:00
deployer(ET): auto-commit from deployer run_id=187
All checks were successful
CI / test (push) Successful in 16s
CI / test (pull_request) Successful in 16s
8447853db8
admin merged commit c21a279565 into main 2026-06-06 21:24:34 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/orchestrator#54