fix(gates): manifest-l10n-coverage is gate-101, not a second gate-99 - #615
Merged
Conversation
Two different gates both declared number 99:
10818: # GATE 99 — manifest-l10n-coverage (#604, 2026-08-27)
10997: # GATE 99 — demo-data-coverage (#590, earlier)
demo-data-coverage held 99 first and COVERED-ELSEWHERE.md records it there, so
manifest-l10n-coverage is the one that moves.
WHAT IT BROKE. The declared inventory is built with
... | sort -n -k1,1 -s | awk '!seen[$1]++'
first declaration of each NUMBER wins — so one of the two gates was absent from
the inventory entirely, and `_declared_n` counted 80 where 81 gates exist. The
coverage line then printed arithmetic that cannot be true. From a real pipelinq
run:
COVERAGE: 72 of 80 declared gates reported a result (9 not applicable; 72 of 71 applicable gates ran)
72 of 71. That is the duplicate, surfacing as a number nobody can act on.
It also made `test_gate99_demo_data_scope.sh` unpassable: it greps the runner's
gate-99 output and received manifest-l10n-coverage's NOT APPLICABLE verdict on
all three arms, so `Package invariants` has been red on main — masking any real
regression in this repository behind a failure nobody could fix.
Verified:
- `bash -n` on the runner
- test_gate99_demo_data_scope.sh: ALL PASS (was 3 FAILURES) — all four arms
- test_gate_acceptance_matrix.sh: 193 passed, 0 failed
- the fixtured-gate count moves 80 -> 81, which is the shadowed gate
reappearing in the inventory
- no duplicate gate number remains
- demo-data-coverage's five call sites are untouched
rubenvdlinde
added a commit
that referenced
this pull request
Aug 28, 2026
The runner declared GATE 101 twice: manifest-l10n-coverage and demo-data-coverage, each calling _pass/_fail with the same number under different names. Both gates were introduced as gate-99 within 14 minutes of each other, and the fix for THAT collision (#615) moved l10n from 99 to 101 - onto a number demo-data-coverage already held. The collision moved rather than closing. The symptom is not a duplicate-number warning. test_gate101_demo_data_scope.sh fails with 'expected FAIL on planted, got: [gate-101] manifest-l10n-coverage: NOT APPLICABLE' - the demo-data test greps for its own gate number and reads the OTHER gate's verdict. Any PR touching hydra-gates is red on it. l10n moves rather than demo-data because demo-data has a test file whose NAME pins its number (test_gate101_demo_data_scope.sh) and l10n has none, so this is the change with no rename in it.
rubenvdlinde
added a commit
that referenced
this pull request
Aug 28, 2026
#620) * fix(gates): manifest-l10n-coverage is gate-102 - 101 was already taken The runner declared GATE 101 twice: manifest-l10n-coverage and demo-data-coverage, each calling _pass/_fail with the same number under different names. Both gates were introduced as gate-99 within 14 minutes of each other, and the fix for THAT collision (#615) moved l10n from 99 to 101 - onto a number demo-data-coverage already held. The collision moved rather than closing. The symptom is not a duplicate-number warning. test_gate101_demo_data_scope.sh fails with 'expected FAIL on planted, got: [gate-101] manifest-l10n-coverage: NOT APPLICABLE' - the demo-data test greps for its own gate number and reads the OTHER gate's verdict. Any PR touching hydra-gates is red on it. l10n moves rather than demo-data because demo-data has a test file whose NAME pins its number (test_gate101_demo_data_scope.sh) and l10n has none, so this is the change with no rename in it. * fix(gates): the l10n fixture follows its gate to 102 test_gate_acceptance_matrix.sh keys a fixture to its gate by NUMBER, so moving manifest-l10n-coverage off the duplicated 101 orphaned its own acceptance bundle: 'gate-102 is DECLARED by the runner but has neither a planted/clean fixture nor a reasoned row in UNCOVERED.md'. The fixture, its two arms and its reasoning are unchanged - only the number it is filed under. * docs(gates): record that the 99 -> 101 fix collided a second time The note explained the first collision and stopped there, so it read as closed. It was not: moving l10n 99 -> 101 landed on the number this gate had just taken, and the identical failure reappeared hours later. Both times the tell was this suite failing while the gate it names was fine, because a test that greps [gate-N] reads whichever gate printed that number last. Recording the second occurrence is the part that stops a third.
rubenvdlinde
added a commit
that referenced
this pull request
Aug 28, 2026
… checked (#623) TWO SESSIONS FIXED ONE COLLISION AND MADE IT WORSE. gate-99 was claimed by `manifest-l10n-coverage` and `demo-data-coverage` at once. #612 moved demo-data-coverage to 101. #615 moved manifest-l10n-coverage to 101. Both diffs were correct in isolation; together they relocated the collision from 99 to 101 and left gate-99 orphaned. Nothing noticed until the same acceptance suite failed again with the number changed: FAIL — expected FAIL on planted, got: [gate-101] manifest-l10n-coverage: NOT APPLICABLE ... demo-data-coverage takes 102. manifest-l10n-coverage keeps 101, because #615 says so in its title and its own suite keys on it; mine is the newer claim in conflict, so mine moves. gate-99 stays vacant rather than being reused: its history now points at two different gates, and a number that has meant two things is worse than a gap. 🔴 MY OWN VERIFICATION MISSED IT. After the first renumbering I checked the `# GATE N — name` COMMENT headers and confirmed "no duplicates". The headers were distinct (99 and 101) while both gates called `_pass 101`. I verified the labels and not the behaviour. So the new check reads the CALL SITES, which are what the report, the COVERAGE tally and every acceptance suite actually key on. There is a gate-95 for ADR number collisions and nothing for GATE numbers; this is that check. Five arms, and ARM 2 reconstructs the exact state that reached main and asserts both gate names appear in the error. ARM 3 plants distinct headers over colliding calls — the precise thing my manual check waved through. ARM 4 pins that a runner with no gates exits 2, because a silent zero is how this class hides. 81 gates, every number claimed once. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two different gates both declared number 99:
demo-data-coverageheld 99 first andCOVERED-ELSEWHERE.mdrecords it there, somanifest-l10n-coverageis the one that moves.What the collision broke
The declared inventory silently dropped a gate. It is built with
First declaration of each number wins — so one of the two gates was absent from the inventory entirely and
_declared_ncounted 80 where 81 exist. The coverage line then printed arithmetic that cannot be true. From a real pipelinq run:72 of 71. That is the duplicate surfacing as a number nobody can act on.
It also made
Package invariantsunpassable onmain.test_gate99_demo_data_scope.shgreps the runner for gate-99 output and receivedmanifest-l10n-coverage'sNOT APPLICABLEverdict on every arm:So this repo's own CI has been red on
main, masking any real regression behind a failure nobody could fix by editing the test.Verification
bash -non the runnertest_gate99_demo_data_scope.shtest_gate_acceptance_matrix.shdemo-data-coveragecall sites