Repository navigation
The release protocol's own reporting lied three ways: a fabricated 95% coverage note, a note-picker hijacked by crate names, and gate() keeping no log #3844
Description
Three defects in the release protocol's own reporting, all fixed in e8c341cca on release/0.69.1-batch-2. Found by @aprender-45 rehearsing the pre-publish dogfood on yoga. Filed after the fact because the commit cites #3841 in error — that number belongs to the PMAT-272 fold row. This is the correct issue for that commit.
1. The coverage DEFER note fabricated a PASSING number (mine)
[DEFER] coverage measured 95% against floor 88; owed by #3839 ...
Coverage was never measured. 95 is COV_THRESHOLD from the Makefile's own banner:
Makefile:495 COV_THRESHOLD := 95
Makefile:610 @echo "📊 Running coverage ($(COV_THRESHOLD)%+ threshold)..."The extractor was grep -oE '[0-9]+(\.[0-9]+)?%' | tail -1, so on any aborted run the banner was the only percentage present. Two compounding failures:
- The fallback was dead code.
${cov_pct:-NO PERCENTAGE (the run died before parsing LCOV)}fires only whencov_pctis empty, and the banner guarantees a match on every run. The one guard written against exactly this could never trigger. - The fabricated number is ABOVE the floor. 95 > 88, so the row reads as comfortably passing. That inverts the stated rationale for the deferral — "a deferral that does not say what it measured is indistinguishable from a gate that passed" — into something worse: indistinguishable from a gate that passed well.
Host-independent. Makefile line 3 of the recipe is which cargo-llvm-cov || cargo install ... || exit 1, so an abort is live on any box.
Fixed by anchoring to the line that exists only when LCOV was parsed. Measured both ways:
| input | old | new |
|---|---|---|
| banner only (aborted run) | 95% |
"" → fallback fires |
TOTAL: 824853/939270 lines covered (87.82%) |
87.82% |
87.82% |
2. gate() discarded its output, and its note-picker matched dependency names
out=$("$@" 2>&1) went into a shell variable and was thrown away. gate() was the only row family writing nothing into $WORKLOG — fmt, clippy, test, bashrs. So the keep-the-worklog-on-NO-GO fix could not reach them: they never put anything there to keep. A red test row's real output was simply gone.
And on a red row the note is the row's entire visible output, picked by an unanchored grep -iE 'error|fail|warning:|denied|✗|regression' | head -1 — which matches substrings inside crate names. Three instances on one run:
| row | note it printed | why |
|---|---|---|
clippy |
Compiling thiserror v1.0.69 |
"error" in thiserror |
test |
Compiling proc-macro-error-attr2 v2.0.0 |
"error" in the crate name |
dogfood-use |
2 pass / 0 fail / 2 skip |
"fail" inside "0 fail" |
The third is the clearest: a failing row whose whole explanation is a line stating there are zero failures. The real reason (FAIL: no model was exercised) was on the next line and discarded.
Fixed: writes $WORKLOG/<name>.log, appends [log: …] to a failing note, anchored picker. Case table:
old=1 new=0 Compiling thiserror v1.0.69
old=1 new=0 Compiling proc-macro-error-attr2 v2.0.0
old=1 new=0 2 pass / 0 fail / 2 skip
old=1 new=1 error[E0308]: mismatched types
old=1 new=1 test result: FAILED. 3 passed; 1 failed
old=1 new=1 FAIL: no model was exercised
3. The judge now reconciles the red scalar against the rows
See #3842 for the receipt-side defect this guards. check_model_ladder.sh refuses any receipt where red disagrees with the count of non-green rows, naming both numbers. New case red-receipt-red-not-recorded; the mutant increments red with no matching row and the gate goes rc=1. Self-test 55 cases, 0 bad.
It reports and keeps judging rather than continue-ing — a continue suppresses every real per-row refusal behind it, which is the same suppression the check exists to expose. Three fixtures went red before that was noticed.
Why these three belong together
Each makes a gate assert something untrue about its own run, and none changes a verdict — which is exactly why they survived. rc was always correct; only the explanations were untrustworthy. Their whole cost lands at the moment a gate goes red and someone is deciding whether to spend another 40-minute cycle.
🤖 Generated with Claude Code
Activity
fix(dogfood): keep the coverage log, and correct the record on the co…
fix(guards): the FP8 merge tripped THREE guards, and I only looked fo…
fix(ci): three guard-tree failures — a ratchet, a stale ledger, and a…
docs(cascade): the drain comment cited #3893, which does not exist — …
noahgift commentedon Sep 23, 2026
Milestone moved 0.69.1 → 0.70.0. Reason: the release protocol's own reporting (0.70 FT-10: the train measures itself). Source: the #3988 disposition table (#3988 (comment)), row MISLABELED. Approval: operator, 2026-09-23 (relayed by cop aprender-cf: "yes apply both"). Applied by aprender-cb. Nothing was closed.
fix(dogfood): keep every gate log and pick anchored failure notes; la…
noahgift commentedon Sep 24, 2026
Ported e8c341c to 0.70.0 as 5ce3b14 on relgate/e6-0.70.0 (the batch/0.70.0 fold). Defect 1 (coverage DEFER) does not apply on main because the #3839 DEFER block never landed there. Defects 2 and 3 are ported: dogfood.sh gate() keeps its logs and uses an anchored note picker, and check_model_ladder reconciles a red receipt against its recorded scalar (new case red-receipt-red-not-recorded; self-test 48 cases, 0 bad).
docs(dogfood): gate() comments cite #3844, not #3841 (#3844)
noahgift commentedon Sep 25, 2026
a2 (0.70.0): verified on batch/0.70.0. Defects 2 and 3 are present via 5ce3b14. The picker case table passes 6/6, and
check_model_ladder.sh --self-testreports 48 cases, 0 bad, including red-receipt-red-not-recorded (rc=1). Defect 1 has no code on 0.70.0: the batch has no coverage-DEFER extractor. a49b6f3 changes the gate() comments to cite #3844 instead of #3841 (comment-only). This closes when the batch merges.9 remaining items
noahgift commentedon Oct 10, 2026
Parked from #3863: the epic is at 5 open children against a budget of 4, after new tickets were linked. This ticket has no pushed branch and no open PR. It stays open, keeps its owner and milestone, and re-enters when a child of that epic closes (1-in-1-out). Nothing reads sub-issue membership (checked: no code, workflow or contract), so no gate changes.
noahgift commentedon Oct 12, 2026
Status (aprender-clerk, owner): all three defects are fixed on
mainat cc71bde. Checked by reading the tree, not the PR history.tag_coverage_gate.sh --resolveand logs the output tocoverage-gate.log. A missing receipt is FAIL, and there is no percentage to scrape. DEFER is also abolished (markturns DEFER into FAIL).scripts/dogfood.shgate()(from the v0.69.3 merge-back, 5fa13fe).gate()writes$WORKLOG/<name>.logand puts the log path in the note of every red row. Thered-receipt-red-not-recordedladder fixture from e8c341c is on main too.e8c341c itself is not an ancestor of main; its content reached main through the merge-back. Fix shas on main: a719e1a (#4886) and 5fa13fe (#4338). Nothing is left to land. This issue was filed by a human, so it is left open for a human to close.
🤖 Generated with Claude Code
noahgift commentedon Oct 14, 2026
P0 to P1 (2026-10-14 P0 triage): P0 now means it blocks the next release or carries the operator's own words on it; this issue does neither, so it stays on the 0.71.0 milestone at P1.
noahgift commentedon Oct 14, 2026
Folded into #5307 as a checklist row (TRIAGE-100, 2026-10-14): the open-ticket cap is 100, so this ticket is now tracked on that master and closed as not planned. Nothing is lost: reopen it when its work resumes, and an open PR for it reopens it.
Agent: aprender-clerk