Uh oh!
There was an error while loading. Please reload this page.
feat(gate): give the three pilot gates an UNRECOGNISED verdict distinct from clean - #9875
Conversation
…rom clean Fixes#9747 Visibility only, per the maintainer ruling of 2026-08-18: printed and counted, never a failure, no new merge-blocking context. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
…ability rule Four fixtures, each proven to discriminate by flipping its expectation, and the production `unreadable` sink mutated to prove they fail when the census goes blind. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
…ecognised-verdict-pilot
PM review — ACCEPT. All three open questions ruled A. This is the best-executed card of the round.Verified at H1 — you shipped less than the card allowed, and each subtraction is a measurementProposal 2 only, and all three reasons hold:
A dev that ships three-quarters of a ruling and can name the measurement behind each omission is more useful than one that ships all of it. H2 — the finding I did not expect, and it changes the family answer
And the same gate family contains one of each:
That kills "generalize the ratchet across the family" as a single decision and replaces it with "measure per gate, and the measurement is cheap and reusable." I came into this card expecting a family-wide answer. The correct answer is that there isn't one, and you proved it with a method (per-commit replay of changed files through the gate's own recognizer, proved byte-identical above its CLI epilogue) rather than an argument. That the deletions are genuine — H4 — the ablation found a live defect, and that is the load-bearing resultRemoving only the ⇒ A The H4 trap is handled: scoped-out (117) is a separate printed number with a stated criterion, never folded into the unrecognised count (23). That was the failure I was most worried about. H3 — |
Uh oh!
There was an error while loading. Please reload this page.
…th halves `main` (#9875/#9747) added the UNRECOGNISED census; this branch (#9680) added the pinned-population enumeration and RETAINED. Both are additive to one script and neither supersedes the other, so both survive verbatim. Two things the three-stage text merge did not handle on its own: 1. `report()` ended up with two `const census` bindings in one scope — the PINNED census destructured from `audit()` (this branch) and `censusUnrecognised()` (`main`). git auto-merged that region with NO conflict marker and the result did not parse. `main`'s local is renamed to `unrecognised`; every printed string is byte-identical. 2. `main` added a test file carrying 2 new pinned doubles, which RETAINED correctly reports as growth. Regenerated with the gate's own `--write` remedy: 308 -> 310 rows, 2 added or grown, 0 lost. Gate output after the merge, both halves firing: UNRECOGNISED [engine-double-contract]: 23 construct(s) ... 117 further construct(s) are SCOPED OUT by a stated criterion ... check-engine-double-contract: OK — 321 pinned, 133 in the DEBT ledger, 2 exempt. check-engine-double-contract: 310 (file, verb) row(s) held by the RETAINED ledger `--self-test` runs 107 assertions = 76 (merge-base) + 8 (`main`) + 23 (this branch); no limb from either side was dropped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
Fixes#9747
Pilot only, visibility only. Three gates, no new required context, no new merge-blocking
failure — verified on the real tree, not asserted (see "Reverse verification" below).
H1 first: WHICH proposal, and why the other two halves are not here
Shipped: proposal 2 — the third exit state — on the pilot gates. Not proposal 1's
delta-ratchet, and not the deriver-wide
unreachablesweep. All three reasons aremeasurements or scope, not preference:
unrecognisedas a verdict)check-engine-double-contractunreachablesweep (#9700 / PR #9799)hintCoverssweep over all 110 families indispatch-gates. Ruling 2 says three gates, do not touch the other 107. Generalising before the nuisance measurement is exactly what the ruling forbids, so it stays a follow-on card that this measurement now unblocksH2: the churn numbers for the two durability rules — the ruling's gate on generalizing
Measured the way #9680's dev measured, over 3,195 first-parent commits on
mainin themonth to 2026-08-19, replaying each commit's changed files through the gate's own
recognizer (a copy of the gate file, proved byte-identical above its CLI epilogue by
diffat build time, so the numbers are the gate's own reading and not a re-implementation).
Result: the nuisance rate is a property of the POPULATION, not of the proposal.
DURABILITY_CRITICAL_CALLEES, all ofpackages/)DRIVER_READ_CALLEES, 3 roots)file)file::callee)file::fn::callee)file::callee)file::fn::callee)delete()member takes 319 pinned to 318 and the gate stays green #9680's zero. Its single leave in a month —packages/runtime/src/http-dispatcher.ts::saveMetaItemat8891f9394— is a cross-filemove: the seam left
http-dispatcher.tsand entereddomains/meta.tsin the samecommit, repo-wide total
1 -> 1. A per-file identity ledger reddens once a month on afile split; a repo-wide delta does not move at all.
say so: "remove the unreachable legacy raw-engine save path" (
5ab084286, -3),"retire
sys_fetch_previous_delete" (4fedb1179, -1), "four read seams that failed nolonger answer from ..." (
4e3a4c3c8, -1). At the finest keying that is one red everyother working day, every one of them correct code being reddened.
So the answer to "can this be generalized?" is: not blindly, and the discriminator is
measurable per gate before adopting it. A delta-ratchet is free where the population only
grows and is a nuisance where correct deletions are routine — and the same gate family
contains one of each.
mainfor the same month. The first-parent count is 3,195. This container's clonearrives shallow at 63 commits and needs
git fetch --shallow-sincebefore any historyquestion can be asked — which is this card's own shape, one layer out: an instrument
reporting a small number because it could only see part of the population.
H3: per-gate verdict — can a construct be counted as unmatched at all?
check-engine-double-contractcheck-engine-double-contract. Its discovery has a well-defined stopping point:implOfanswers null and the construct leaves the population beforeisEngineVerbShapeisever asked. Not "declared out of scope" — absent, which is #8639's shape and which the
file's own header already names as "the DISCOVERED invariant's blind half, one layer
down". The census walks the same structural evidence discovery uses (the slice's verb
declared alongside at least two engine siblings) and reports what discovery could not read.
Durability log-level rule. Its log-callee vocabulary is closed and structural, and
resolveLogCalleealready answersunreadablefor a call it cannot read. Before this,that answer was collected only to choose a FINDING's verdict, so a seam that was correctly
green and also carried something unreadable printed nothing anywhere. Now counted.
Durability read-seam rule — proposal 2 does not apply, and the gate now prints that
rather than a number. Measured before deciding: a census over its three scan roots asking
"which catches carry this rule's harm shape while guarding a call the vocabulary does not
name?" returns 25 sites, and the callee histogram is
Array.isArray(5),.raw(3), acallback
fn(3),JSON.parse(3),getService(2),getDriver(2),toJSONSchema,stringify... Most are not storage reads at all. Narrowing that to the genuine ones needsexactly the name-heuristic the rule's own vocabulary note refuses for a measured reason. So
the honest output is
NOT APPLICABLEwith the reason — printed rather than omitted,because an absent row cannot be told apart from "nobody looked".
The H4 trap, handled: SCOPED OUT is not UNRECOGNISED
#8662 is why this matters:
check-where-matcher-conformancedrops inverted survivor filtersas
OUT_OF_SCOPEcorrectly, by its own definition, and that correct verdict still readsas "nothing to see". A census that folded such constructs in would report noise on day one.
On the engine gate the split is 117 scoped out vs 23 unrecognised, and the criterion is
structural rather than an allowlist of callee names:
producer:
delete: vi.fn(),delete: vi.fn().mockResolvedValue(v).unwrapCallImpl's owncensus already argues exactly this. Counted as a number only.
the initializer carries a function the unwrap declined, or it roots at a binding the file
declares, or the member is a shorthand. Reported by file, line and spelling.
Two self-test limbs pin the scoped-out side in both spellings, one pins that a construct with
too few engine siblings lands in neither bucket, and one pins that a census row is still
absent from the population — so "it only counts" is a property, not a claim.
Reverse verification: both directions, on the real tree
Direction predicted before each run; all observed as predicted. Every ablation restored from
a commit, never from an uncommitted tree.
1. The engine census fires, and the rows are real doubles. Ablate
packages/rest/src/rest-batch-endpoint.test.ts:40by removing only the??default, so thegate can read the same implementation:
UNRECOGNISED [engine-double-contract]OK — 321 pinned, 133 in the DEBT ledger, 2 exempt.exit 0PINNED [delete]: packages/rest/src/rest-batch-endpoint.test.ts declares 1 engine double(s) whose delete() does not route through assertEngineDeleteDispatch (line 36)That is the load-bearing result. The 23 rows are not decoration: the moment the gate can
read one, it has a real finding about it. A
??-defaulted mock was hiding a genuinelyunguarded engine double from a shrink-only ratchet, silently, at exit 0.
2. The durability census fires, and does NOT redden. Inject one unreadable log call into
a real loud seam (
packages/metadata/src/loaders/database-loader.ts:394):Both halves at once: the count moved
0 -> 1naming the exact construct, the sub-count"verdict rests entirely on it" correctly stayed 0 (the seam is loud on other evidence),
and the run stayed green. Visibility-only, demonstrated rather than asserted.
3. Each new self-test limb proven failable. Every one of the four durability census
expectations flipped in turn — all four reddened, one limb each. Then the production sink
mutated (
collectLoggedLevelsstops recordingunreadable): 4 limbs red, the two newcensus limbs plus the two pre-existing
unreadable-reportlimbs, exactly as predicted.4. One honest miss, recorded because it is this card's own shape. The first insertion of
those four fixtures used a
str.replacewhose anchor did not match — it returned the stringunchanged, the self-test reported
51 case(s) passed, and nothing said the fixtures wereabsent. Caught only by the flip-test above. A "matched zero, reported success" operation, in
the very change that exists to make such operations announce themselves.
Why this is not
exit 2, when the in-tree prior art isRuling 4 says match the convention; ruling 1 says nothing may redden a PR for an
unrecognisedcount. Those pull in opposite directions on the exit code specifically, sothe resolution is stated in both file headers rather than picked silently:
The four in-tree implementations —
check-where-matcher-conformance(missing baseline=>
exit 2, explicitly distinct from a finding'sexit 1),check-published-readme-exports(hard refusal, "cannot tell debt from a new defect"),
check-governed-merges' header("non-zero exits classify the ENVIRONMENT, not the tree") and PR #9799's drift guard — are
all the gate refusing to run: the environment is broken and no verdict about the tree
exists. This verdict is the opposite: the run completed and the count is an observation
about it.
exit 2would make it a failing CI job.So the convention is matched where it is about semantics (a named third state, printed
rather than inferred, distinct from both
cleanand a finding) and deliberately not whereit is about the exit code.
Proposed round-report wording — for a maintainer, NOT applied here
The ruling says the counts should be "visible in round reports". That template lives under
.claude/skills/pm-dispatch/**, which is a governed surface this PR may not touch. Bothgates therefore emit a stable, greppable prefix so the template can pick them up with no new
context existing anywhere:
Suggested one-line addition to the round-report template, for the maintainer to apply or
reject:
Scope
skip-changesetapplied and read back.scanSourceandanalyzeSourceFile's discovery are untouched. No matcher widened, nocriterion changed, no verdict any existing invariant reaches is different.
return, so acatchthat degrades by FALLING THROUGH into an empty accumulator is structurally invisible #8845, A partial test double is only ever discovered by deleting thecatchthat hides it — twice this shift.check:engine-double-contractpins engine doubles; nothing pins registry doubles #9165-2b and check:engine-double-contract's CONSUMER SEAM population is unratcheted the same way the pinned population was — deleting a seam takes 6 to 5 with the gate green #9708 are not addressed here and remain open on their own terms.check:engine-double-contract's CONSUMER SEAM population is unratcheted the same way the pinned population was — deleting a seam takes 6 to 5 with the gate green #9708's consumer-seam population is deliberately left alone.
Verification
Local gate union re-run on the final commit
372d93284, all green, derived from the actualchanged paths with
node scripts/pm/dispatch-gates.mjsafter mergingmainin (notrecalled, and re-derived post-merge):
check:durability-log-level·check:engine-double-contract·check:cross-package-test-inputs·
check:nul-bytesControl-byte sweep run separately over both edited files
(
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'): clean.Out of scope, filed not fixed
check-engine-double-contractcannot read three mock-initializer spellings, andone of them (a
??default aroundvi.fn(fn)inpackages/rest/src/rest-batch-endpoint.test.ts) hides a live unguarded engine deletedouble, measured by the ablation above. Not addressed in this PR: widening the matcher is
the separately-declined act this card's own scoping excludes, and every construct it widens
in arrives unpinned, so it would redden CI on 23 constructs nobody has triaged.
main in a month" number is wrong until the clone is deepened. This is why the H2 denominator
above is 3,195 and PR feat(gate): enumerate check:engine-double-contract's pinned population so a lost pin names itself #9712's is 269. Not addressed in this PR.
Generated by Claude Code
Generated by Claude Code