Repository navigation
premerge: Phase 0 packs without checking the base is green, so a red main becomes the stack's problem #786
Description
The gap
Phase 0 discovers every open non-draft PR and packs them onto a combine branch. It never asks whether the base is green first.
If main is red, the stack inherits that red at commit zero. The gate then reports ci=red on work that did not cause it, the CI-repair arm classifies a failure belonging to a different change, and the run either parks red or gets quietly widened to fix someone else's bug.
Hit live on stack PR #768
main's own tip was already failing:
aa3e54cd completed/failure Tests <- main's tip, the v0.55.1 landing
tests/vendor-provenance.test.sh V46 — six measured_diff_basis.uberdev_rev records pinned b7dbe74a…, the tip of the unmerged branch fix/746-agent-description-budget, whose work had been re-cut by the #752 stack landing. Verified rather than assumed:
git merge-base --is-ancestor b7dbe74a origin/main→ rc=1 (unreachable from main)- the fixture fails identically on a clean
origin/mainworktree — 62 passed / 1 failed git diff --name-only origin/main..HEAD | grep -c vendor.json→ 0 (the stack touches no vendor register)
So the stack's only CI failure was 100% inherited. Attempt 1 spent its whole ci=red repair arm on it, the ci-failure-classifier correctly refused to route it (a ci-code-fixer dispatched against PR 768 would be editing a file the PR does not touch, to repair a pre-existing main red), and the run had to stop and ask the operator whether to widen scope past the five packed PRs.
The fix that unblocked it — re-pinning six register values to the reachable commit carrying the identical bytes — was main's work, carried in someone else's stack because there was nowhere else to put it.
Why this bites harder than it looks
- Every
/premergerun against a red base parks red, so the command silently becomes unusable until someone notices the base is the cause. - The repair budget is spent on the wrong change: one of three rounds here.
- The blame is misattributed — the stack PR's checks go red, so the five packed PRs look like the cause.
- The classifier's
AMBIGUOUSroute isstop the loop, which is correct but leaves the operator with no next step other than reading the log carefully enough to notice the red predates the stack.
Proposed change
Probe the resolved base in Phase 0a, right after review_consolidate_base resolves it and before 0b builds the branch:
- Base green → proceed silently.
- Base red → refuse by default, naming the failing check and the base SHA. A stack built on a red base cannot reach a green gate on its own merits, so packing is wasted work.
- Base has no checks / unknown → proceed, but say so in the run summary, the same way the gate already distinguishes
no_checksfromunknown.
Add a --allow-red-base escape for the deliberate case (this run would have used it, with the operator's approval already on record). When used, put it in the stack PR body and the run summary, so the inherited red is attributed to the base rather than to the packed PRs.
The probe is the same gh pr checks / statusCheckRollup machinery Phase 3 already uses against the stack PR — pointed at the base branch instead.
Related
- premerge: Phase 4 is gated on an unreachable predicate, so the simplify pass never runs on any stack that needs it #785 — Phase 4's gate is unreachable (the other end of the same run)
- /premerge output is unmergeable by /merge — add a distinct premerge trust tier #716 —
/premergeoutput is unmergeable by/merge - PR chore(stack): land #762 #763 #764 #765 #766 (v0.56.0) #768 — the measured run
Activity