Skip to content

fix(tooling): error-status gate names the real cause when a code leaves the ungraded set (#9563) - #9577

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-9563-gate-diagnosis-split
Aug 18, 2026
Merged

fix(tooling): error-status gate names the real cause when a code leaves the ungraded set (#9563)#9577
os-steve merged 1 commit into
mainfrom
claude/issue-9563-gate-diagnosis-split

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#9563

check-error-status-conformance.mjs's nowPinnedMessage() computed the
ratchet-down trigger as a subtraction (baselined \ result.unpinned) but
hard-coded a single cause for it: "a producer now declares its status."
result.unpinned drops a code for either of two unrelated reasons —
reconcile()'s own branch at documented.has(code) shows why:

if(runtime.size>0){reconciledCodes++;
...
}elseif(documented.has(code)){unpinned.push(code);}

A baselined code leaves unpinned because a producer appeared
(runtime.size > 0), or because its doc entry was removed
(!documented.has(code), with no producer either). Only the first cause had
a sentence.

Before — the false diagnosis, reproduced

Per the issue's counterfactual: temporarily deleted the ## Batch Operation Errors section from content/docs/api/error-catalog.mdx (its three entries
BATCH_PARTIAL_FAILURE, BATCH_COMPLETE_FAILURE, TRANSACTION_FAILED
are all in scripts/error-status-unpinned-baseline.json and none has a real
producer) and ran the gate on main, before this fix:

$ node scripts/check-error-status-conformance.mjs
unpinned: 34 documented code(s) with no derivable producer (baselined: 37).
x BATCH_COMPLETE_FAILURE: baselined as unpinned, but a producer now declares its status — ratchet the baseline down with --update.
x BATCH_PARTIAL_FAILURE: baselined as unpinned, but a producer now declares its status — ratchet the baseline down with --update.
x TRANSACTION_FAILED: baselined as unpinned, but a producer now declares its status — ratchet the baseline down with --update.
x check:error-status-conformance — 3 finding(s).

No producer declares a status for any of the three (verified by grep across
packages/, examples/, apps/ — the only hits outside the enum
declaration are two spec tests). The message is simply false on this route.
Restored the doc file (git restore --source=HEAD) before touching any code.

After — the same counterfactual, this fix applied

$ node scripts/check-error-status-conformance.mjs
unpinned: 34 documented code(s) with no derivable producer (baselined: 37).
x BATCH_COMPLETE_FAILURE: baselined as unpinned, but its doc entry was removed, so nothing claims a status for it any more — ratchet the baseline down with --update.
x BATCH_PARTIAL_FAILURE: baselined as unpinned, but its doc entry was removed, so nothing claims a status for it any more — ratchet the baseline down with --update.
x TRANSACTION_FAILED: baselined as unpinned, but its doc entry was removed, so nothing claims a status for it any more — ratchet the baseline down with --update.
x check:error-status-conformance — 3 finding(s).

Truthful now, and --update is still the correct remedy either way — the
ratchet direction and remedy are unchanged, only the stated cause. Doc file
restored to a clean tree again afterward; git status --porcelain is empty
on main HEAD for that path throughout.

What changed (scripts/ only)

  • nowPinnedMessage() -> split into nowPinnedProducerMessage() and
    nowPinnedDocRemovedMessage(), each naming its real cause.
  • New pure nowPinned({ baselined, unpinned, vocabulary, documented }),
    placed beside reconcile(): derives { code, reason }[] at the same
    documented.has(code) juncture reconcile() branches on, so the message
    selection isn't guessing — it reuses the same fact reconcile() already
    computed.
  • runFixture() now also returns documented (the parsed doc-side set), so
    fixture-level self-tests can call nowPinned() directly.
  • No baseline semantics change, no catalog change, no grading-model change —
    diagnosis text + self-tests only.

Self-test — 2 new cases per branch (36 -> 40)

check-error-status-conformance --self-test: 40 cases pass — …

Reverse verification

Committed the fix, then temporarily forced nowPinned()'s branch to always
return reason: 'producer' (reverting only the causal split, keeping the new
self-test cases) and re-ran --self-test. Predicted: case 22 (doc-removed
branch) goes red, everything else stays green. Observed exactly that:

 x self-test: 22 nowPinned names the doc-removed branch when nothing documents the code any more — [{"code":"TRANSACTION_FAILED","reason":"producer"}]
x check-error-status-conformance --self-test: 1/40 case(s) failed.

Restored the fix from the branch (git checkout claude/issue-9563-gate-diagnosis-split -- scripts/check-error-status-conformance.mjs); re-ran --self-test, back to 40/40 green.

Gates

Serial constraint (#9266)

#9266 (needs-user-decision, same file's subject matter) is still open with
no linked PR as of this branch's base — no re-run of the observation was
needed. No content/docs/releases/ edits, no baseline rewrite, no catalog
edit landed by this PR.


Generated by Claude Code

…es the ungraded set (#9563)
check-error-status-conformance.mjs's nowPinnedMessage() hard-coded a single
cause ("a producer now declares its status") for ANY baselined-unpinned code
that left result.unpinned -- but that subtraction has two distinct causes,
split at the documented.has(code) juncture reconcile() already branches on:
- a producer appeared (runtime.size > 0), or
- the code's doc entry was removed, so documented.has(code) went false,
with no producer either.
Split the derivation into a pure nowPinned() function returning a reason per
code, and two message functions (nowPinnedProducerMessage /
nowPinnedDocRemovedMessage) so each cause gets its own accurate sentence.
Both remedies stay `--update`; no baseline, catalog, or grading-model change.
Added self-test cases 21/21b (producer branch) and 22/22b (doc-removed
branch), following the file's own ENTRY_HEADING_SHAPES precedent that an
unexercised branch is the defect. CASES: 36 -> 40.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-steve@claude