fix(merge-gate): SHA-in-main as sole merge-verify criterion + main regression guard
Root-cause fix for main erosion (phantom merge): code of ORCH-067/069 reached `done` while absent from origin/main (only their auto docs-PRs landed). - FR-1: verify_merged_to_main confirms merge ONLY by `git merge-base --is-ancestor <validated_sha> origin/main`; the OR-branch pr_already_merged is removed (a merged PR no longer confirms). Empty SHA / git error -> False. - FR-2: pr_already_merged demoted to merge_pr idempotency-guard; counts a PR only when merged & head.ref==<branch> & base.ref=="main" (explicit in-loop filter). - FR-3: merge_pr selects the open code-PR by head==<branch> AND base==main. - FR-5: new deterministic check_main_regression in _handle_merge_verify (after confirmed SHA-in-main, before done) verifies MAIN_REGRESSION_MARKERS still in origin/main; deterministic count==0 -> alert "main regressed" + HOLD (NOT done, no rollback); git error of the grep -> fail-open. Kill-switch ORCH_REGRESSION_GUARD_ENABLED; non-self -> no-op. - FR-4: root .gitattributes `CHANGELOG.md merge=union` so Unreleased edits auto-merge on rebase without conflict (branch not rolled back). Invariants unchanged (STAGE_TRANSITIONS, QG_CHECKS, deploy-status, merge-gate, image-freshness, DB schema, external HTTP API); non-self repos no-op (INV-5); never-raise (INV-1); merge only via Gitea PR-API (INV-2). Docs: CHANGELOG, .env.example (README/ADR updated by architect). Tests: tests/test_orch073_*.py (TC-01..18); existing merge-gate tests updated for the new code-PR filter. Refs: ORCH-073 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -49,17 +49,22 @@ def test_tc01_verify_true_when_sha_is_ancestor(monkeypatch):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TC-02: PR.merged==true short-circuits to True even if git is unavailable.
|
||||
# TC-02 (ORCH-073 FR-1): PR.merged==true NO LONGER confirms a merge. The former
|
||||
# OR-branch was the phantom-merge root cause (a merged docs-PR turned verify green).
|
||||
# SHA-in-main is now the SINGLE criterion; an empty SHA -> inconclusive -> False.
|
||||
# ---------------------------------------------------------------------------
|
||||
def test_tc02_verify_true_when_pr_merged_even_without_git(monkeypatch):
|
||||
def test_tc02_pr_merged_does_not_confirm_without_sha_in_main(monkeypatch):
|
||||
# Even if a (docs-)PR is reported merged, that must NOT short-circuit to True.
|
||||
monkeypatch.setattr(merge_gate, "pr_already_merged", lambda r, b: True)
|
||||
|
||||
def boom(*a, **k):
|
||||
raise RuntimeError("git must NOT be consulted when PR is already merged")
|
||||
|
||||
monkeypatch.setattr(merge_gate, "ensure_worktree", boom)
|
||||
monkeypatch.setattr(merge_gate.subprocess, "run", boom)
|
||||
assert merge_gate.verify_merged_to_main("orchestrator", "feature/ORCH-071-x", "") is True
|
||||
monkeypatch.setattr(merge_gate, "ensure_worktree", lambda r, b: "/wt")
|
||||
# SHA not an ancestor of origin/main (rc=1) -> not confirmed despite merged PR.
|
||||
monkeypatch.setattr(
|
||||
merge_gate.subprocess, "run",
|
||||
lambda cmd, *a, **k: _R(1) if "merge-base" in cmd else _R(0),
|
||||
)
|
||||
assert merge_gate.verify_merged_to_main("orchestrator", "feature/ORCH-071-x", "abc123") is False
|
||||
# And an empty SHA is inconclusive -> False (cannot prove SHA-in-main).
|
||||
assert merge_gate.verify_merged_to_main("orchestrator", "feature/ORCH-071-x", "") is False
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -93,11 +98,13 @@ def test_tc04_verify_never_raises_on_git_error(monkeypatch):
|
||||
assert merge_gate.verify_merged_to_main("orchestrator", "feature/ORCH-071-x", "abc123") is False
|
||||
|
||||
|
||||
def test_tc04_verify_never_raises_on_http_error(monkeypatch):
|
||||
def boom(r, b):
|
||||
raise RuntimeError("gitea down")
|
||||
def test_tc04_verify_never_raises_on_worktree_error(monkeypatch):
|
||||
# ORCH-073: verify no longer consults pr_already_merged; a worktree/git error
|
||||
# on the SHA-in-main path is the failure to swallow -> conservative False.
|
||||
def boom(*a, **k):
|
||||
raise RuntimeError("worktree exploded")
|
||||
|
||||
monkeypatch.setattr(merge_gate, "pr_already_merged", boom)
|
||||
monkeypatch.setattr(merge_gate, "ensure_worktree", boom)
|
||||
assert merge_gate.verify_merged_to_main("orchestrator", "feature/ORCH-071-x", "abc123") is False
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user