Skip to content

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

Closed as not planned
2 of 2 issues completed

Description

@noahgift

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 when cov_pct is 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.

Refs #3842, #3839

🤖 Generated with Claude Code

Activity

  1. added this to the 0.69.1 milestone on Sep 22, 2026
  2. added
    P0Critical priority
    bugSomething isn't working
    on Sep 22, 2026
  3. added a commit that references this issue on Sep 22, 2026
  4. modified the milestones: 0.69.1, 0.70.0 on Sep 23, 2026
  5. noahgift commented on Sep 23, 2026

    @noahgift
    ContributorAuthor

    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.

  6. noahgift commented on Sep 24, 2026

    @noahgift
    ContributorAuthor

    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).

  7. added a commit that references this issue on Sep 25, 2026
  8. noahgift commented on Sep 25, 2026

    @noahgift
    ContributorAuthor

    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-test reports 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. 9 remaining items

  10. noahgift commented on Oct 10, 2026

    @noahgift
    ContributorAuthor

    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.

  11. noahgift commented on Oct 12, 2026

    @noahgift
    ContributorAuthor

    Status (aprender-clerk, owner): all three defects are fixed on main at cc71bde. Checked by reading the tree, not the PR history.

    1. Fabricated coverage note. The output-scraping extractor no longer exists. Since a719e1a (dogfood: pre-publish reads fmt, clippy, test and coverage from the commit's CI (#4672) #4886), the coverage row reads the commit's coverage-nightly receipt through tag_coverage_gate.sh --resolve and logs the output to coverage-gate.log. A missing receipt is FAIL, and there is no percentage to scrape. DEFER is also abolished (mark turns DEFER into FAIL).
    2. Note picker hijacked by crate names. The anchored picker and its last-line fallback are on main in scripts/dogfood.sh gate() (from the v0.69.3 merge-back, 5fa13fe).
    3. gate() kept no log. On main, gate() writes $WORKLOG/<name>.log and puts the log path in the note of every red row. The red-receipt-red-not-recorded ladder 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

  12. added
    P1High priority
    and removed
    P0Critical priority
    on Oct 14, 2026
  13. noahgift commented on Oct 14, 2026

    @noahgift
    ContributorAuthor

    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.

  14. noahgift commented on Oct 14, 2026

    @noahgift
    ContributorAuthor

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High prioritybugSomething isn't workingowner:aprender-clerkowner: aprender-clerk (aprender-3e)size:MK̂ 3-4 h

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions