Filed by DEV5. ⚠ Not #321, and folding it there would blur both (DEVOPS's ruling, and I agree):
#321 a control CI never invokes -> the INVOCATION is missing
this a control whose trigger is another PR landing -> the SEQUENCING has no owner
⇒ Running more controls per-PR does not fix this one. Both PRs below ran every control they had, and both were green.
The specimen, from this repository, today
#354 added a derived estate predicate. #359 added a control asserting that predicate did not exist — deliberately, as a tripwire: "the failure is the notification." Both correct. Both green. Merged minutes apart.
#354 alone --self-test green
#359 alone --self-test green
main, both --self-test rc=3 29 ok / 1 FAIL
⛔ Neither PR's CI ever saw both trees. CI tests PR head + main-at-PR-time, and nothing re-tests when main moves underneath an already-green PR. The interaction existed only in the merged result, which is the one tree no check ran against.
⛔ Why "be more careful" is not the remedy
We both knew the interlock, in writing, in advance. DEVOPS: "land yours after mine, rebase, flip the control." DEV5: "held for your merge — applying now would drag your unmerged work into mine." Two agents, explicit agreement, correct plan.
⇒ It still failed, because the ordering existed only as an intention in two agents' heads while the merge queue had no representation of it at all. A dependency that is real, known, agreed and written down still had no owner and no gate. ★ That is precisely why a resolution to be careful is worthless here: care is what we already applied, in full, and it was not a mechanism.
What made it invisible, which is the compounding half
main did not go red. It went broken and green:
15066a0 ./scripts/exit-code-gate.sh scripts '*.py' -> rc=0 <- what CI runs
15066a0 python3 scripts/check-tools-index.py --self-test -> rc=3
scripts/exit-code-gate.sh:70 runs python3 "$f" bare and never passes --self-test; scripts/gate-selftests.sh is in #369, unmerged. ⇒ Every subsequent PR would have merged clean over a failing control. The sequencing defect broke it; #321's defect hid it. Distinct causes, one incident — which is why they need separate issues and separate fixes.
Remedy — NAMED, ROUTED, NOT TOUCHED
The mechanism has a standard fix: GitHub's "require branches to be up to date before merging." It forces a re-test against the moved main, which is exactly the tree no check saw.
⛔ That is branch protection, and docs/MERGE-AUTHORITY.md rule 2 makes it operator-only — "No pane weakens, removes or re-scopes a required check, whatever a gate's redness is costing it." Adding a requirement is the same surface as re-scoping one. ⇒ Routed to the operator. No pane should action this, including me.
⚠ And it is not a free fix — the operator is choosing between two failure modes, not accepting a win. Requiring up-to-date branches serialises the merge queue: with nine panes merging, every merge invalidates every other open PR and forces a rebase-and-rewait. The cost is real and may exceed the defect. Naming it so the trade-off is visible rather than presenting a one-sided recommendation.
Done when
⇒ RUNNABLE in part, ASSERTED at leg 1. Leg 1 closes on an operator ruling and no command can make it — ASSERTED, with the reason stated. Legs 2–3 are checkable by reading docs/MERGE-AUTHORITY.md and this issue's own recorded specimen. ⛔ NO CALLER: nothing in CI invokes a check for this.
⚠ Heading was ## Closure condition — correct in substance, invisible to close-condition-scan.py, which accepts Done when / Closes when at line start. Renamed, not rewritten: the legs below are unchanged.
- Operator has ruled on up-to-date-before-merge — adopted or declined. A decline closes this, provided 2 and 3 land.
- The mechanism is written where a pane will meet it (
docs/MERGE-AUTHORITY.md or prompts/README.md): CI tests PR head + main-at-PR-time; a green PR is not evidence about the merged result.
- ⛔ Demonstrated on real data — a specimen where two independently-green PRs are red together. This incident is that specimen, at
15066a0; it needs recording rather than reproducing, since reproducing it costs a deliberate breakage of main.
⚠ Proxy test — what is still true if all three pass and the defect is not fixed? Up-to-date-before-merge closes the window where main moves between CI and merge. It does not close the case where two PRs are merged so close together that both re-tests pass and the interaction still only exists afterward, nor the case where the interlock crosses repositories. ⇒ It narrows the window; it does not establish that a green PR predicts a green main. That proposition stays false, and anything relying on it stays unsafe.
Filed by DEV5. Diagnosis with DEVOPS; the "broken and green" half is theirs, measured independently by me before filing.
Filed by DEV5. ⚠ Not #321, and folding it there would blur both (DEVOPS's ruling, and I agree):
⇒ Running more controls per-PR does not fix this one. Both PRs below ran every control they had, and both were green.
The specimen, from this repository, today
#354added a derived estate predicate.#359added a control asserting that predicate did not exist — deliberately, as a tripwire: "the failure is the notification." Both correct. Both green. Merged minutes apart.⛔ Neither PR's CI ever saw both trees. CI tests
PR head + main-at-PR-time, and nothing re-tests whenmainmoves underneath an already-green PR. The interaction existed only in the merged result, which is the one tree no check ran against.⛔ Why "be more careful" is not the remedy
We both knew the interlock, in writing, in advance. DEVOPS: "land yours after mine, rebase, flip the control." DEV5: "held for your merge — applying now would drag your unmerged work into mine." Two agents, explicit agreement, correct plan.
⇒ It still failed, because the ordering existed only as an intention in two agents' heads while the merge queue had no representation of it at all. A dependency that is real, known, agreed and written down still had no owner and no gate. ★ That is precisely why a resolution to be careful is worthless here: care is what we already applied, in full, and it was not a mechanism.
What made it invisible, which is the compounding half
maindid not go red. It went broken and green:scripts/exit-code-gate.sh:70runspython3 "$f"bare and never passes--self-test;scripts/gate-selftests.shis in #369, unmerged. ⇒ Every subsequent PR would have merged clean over a failing control. The sequencing defect broke it; #321's defect hid it. Distinct causes, one incident — which is why they need separate issues and separate fixes.Remedy — NAMED, ROUTED, NOT TOUCHED
The mechanism has a standard fix: GitHub's "require branches to be up to date before merging." It forces a re-test against the moved
main, which is exactly the tree no check saw.⛔ That is branch protection, and
docs/MERGE-AUTHORITY.mdrule 2 makes it operator-only — "No pane weakens, removes or re-scopes a required check, whatever a gate's redness is costing it." Adding a requirement is the same surface as re-scoping one. ⇒ Routed to the operator. No pane should action this, including me.⚠ And it is not a free fix — the operator is choosing between two failure modes, not accepting a win. Requiring up-to-date branches serialises the merge queue: with nine panes merging, every merge invalidates every other open PR and forces a rebase-and-rewait. The cost is real and may exceed the defect. Naming it so the trade-off is visible rather than presenting a one-sided recommendation.
Done when
⇒ RUNNABLE in part, ASSERTED at leg 1. Leg 1 closes on an operator ruling and no command can make it — ASSERTED, with the reason stated. Legs 2–3 are checkable by reading
docs/MERGE-AUTHORITY.mdand this issue's own recorded specimen. ⛔ NO CALLER: nothing in CI invokes a check for this.⚠ Heading was
## Closure condition— correct in substance, invisible toclose-condition-scan.py, which acceptsDone when/Closes whenat line start. Renamed, not rewritten: the legs below are unchanged.docs/MERGE-AUTHORITY.mdorprompts/README.md): CI tests PR head + main-at-PR-time; a green PR is not evidence about the merged result.15066a0; it needs recording rather than reproducing, since reproducing it costs a deliberate breakage ofmain.⚠ Proxy test — what is still true if all three pass and the defect is not fixed? Up-to-date-before-merge closes the window where
mainmoves between CI and merge. It does not close the case where two PRs are merged so close together that both re-tests pass and the interaction still only exists afterward, nor the case where the interlock crosses repositories. ⇒ It narrows the window; it does not establish that a green PR predicts a greenmain. That proposition stays false, and anything relying on it stays unsafe.Filed by DEV5. Diagnosis with DEVOPS; the "broken and green" half is theirs, measured independently by me before filing.