Uh oh!
There was an error while loading. Please reload this page.
fix(pm): fail the bare-root worklist self-test when a recorded verdict sits on a REACHABLE row - #12347
Conversation
…t sits on a REACHABLE row The worklist prints a live `state` beside a recorded `verdict`. When a gate carrying a refusal later declares a watch hint, the state flips to REACHABLE while the refusal stays put, and the row asserts both that its population is reachable by declaration and that it cannot be spelled. Neither existing triage assertion can see it: both audit the KEY SET. Such a row is still a row, so its verdict is not STALE, and it has left `open`, so it is not FRESH. Both halves stay satisfied and `--self-test` exits 0. Add the third direction of the same coupling — a recorded verdict may not sit on a row the sweep finds REACHABLE — and name the offending row. The pairing is general rather than restricted to the two `REFUSE-*` classes, and the failure text does NOT send the row to `DECLARED-NARROWER` as the reporting card proposed. Measured: `covered` asks whether a hint reaches an arbitrary file at the TOP of the root, so it turns true only for spellings that collapse back to the bare word; every genuinely narrower subtree leaves the row uncovered. A covered row is the bare root wearing a glob, which is the one thing `DECLARED-NARROWER` states it is not — so no covered row can honestly wear any of the three verdicts. The message names the two honest resolutions and picks neither, since choosing re-decides a verdict on a shrink-only map. No TRIAGE row's `why` or `verdict` is touched, and no row is added or removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6
yinlianghui
commented
Aug 25, 2026
ACCEPT — PM review of #12064. You corrected the card's remedy, triage's restatement of it, and my Zone 2b, all on one measurement. The mechanism the correction rests on, verified at the sourceZone 2b asked you to falsify the vocabulary half rather than rely on it — "is :482constcovered=(word)=>(entry.hints??[]).some((h)=>hintCovers(h,`${word}/probe.file`));
:531conststate=r.covered ? 'REACHABLE' : (t ? t.verdict : '⛔ UNTRIAGED');
Naming the two honest resolutions in the failure text and picking neither is the right call: choosing re-decides a verdict, which Zone 1b reserved. Widening the pairing beyond The ablation table is the leg that matters
The second row is what makes this PR worth landing rather than a guard nobody has seen do anything: it shows the tree in the broken state passing today. A two-row before/after would have proved the guard fires; the four-row grid proves it fires on the thing that used to slip. Zone 1d and 1e both honoured
Reporting Landing conditions
Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#12064
The worklist prints a live
statederived from the tree beside averdictrecorded in
TRIAGE. When a gate carrying a refusal later declares a watchhint, the state flips to
REACHABLEwhile the refusal stays put, and the rowasserts both that its population is reachable by declaration and that it cannot
be spelled.
--self-testexits 0 through it.Why neither existing assertion sees it
Both audit the key set. A row whose gate declares its root is still a row,
so its verdict is not
STALE; and it has leftopen, so it is notFRESH.Both halves stay satisfied. This was predicted in #11155's dev report and then
measured on PR #12061; it is reproduced below on this branch's own base.
What this adds
One assertion in
--self-test: a recorded verdict may not sit on a row thesweep finds
REACHABLE, naming the offending row and its recorded verdict. NoTRIAGErow'swhyorverdictis touched, and no row is added or removed —the map is shrink-only and this card adds a guard, it does not adjudicate rows.
Two deviations from the remedy as proposed, both measured
1. The pairing is general, not restricted to
REFUSE-*. Every verdict thisfile defines presupposes an uncovered row: the two refusals say a declaration
was refused, and
DECLARED-NARROWER's own definition says the bare root isstill not covered.
2.
DECLARED-NARROWERis not the destination. The card proposed that aflipped row "moves to
DECLARED-NARROWER". Measured, that is not available.coveredasks whether a hint reaches an arbitrary file at the top of theroot, so it turns true only for spellings that collapse back to the bare word:
collapseHintROOT/probe.file***Every genuinely narrower subtree leaves the row uncovered. So a covered row
is the bare root wearing a glob — precisely what
DECLARED-NARROWERstates itis not — and that holds for a
REFUSE-WIDErow taking the escape too, whosedeclaration is true of its population and narrower than nothing. The failure
text therefore names the two honest resolutions (withdraw the declaration, or
withdraw the verdict) and picks neither, since choosing re-decides a verdict.
Evidence
Ablation, on the shape PR #12061 measured — declaring a hint on a gate carrying
REFUSE-UNSPELLABLE. Mutation confirmed on disk by anchoredgrep -cand bygit hash-objectbefore/after, restored undertrap … EXIT INT TERM, and therestore proven byte-identical (
a41147efe985…both sides). No build is involved:the sweep reads gate sources from disk, so there is no
dist/leg to rebuild.cf99875ea8, guard absent, gate unmutated46 live row(s), 39 unreachable as spelled, 39 recorded verdict(s) — none stale, none missingcf99875ea8, guard absent, gate mutated46 live row(s), 38 unreachable as spelled, 39 recorded verdict(s) — none stale, none missing← the defect, reproducedCONTRADICTED: check:ratchet-remedy-authority SCRIPTS_DIR scripts [recorded REFUSE-UNSPELLABLE]On the mutated tree the report printed the card's exact defect:
REACHABLEabove
The idiom has no non-recursive spelling.The guard is green on the tree as it stands — no row is currently in the
contradictory state. Verified rather than inferred: all 7 reachable rows carry
no verdict, and the 39 verdicts sit on the 39 open rows. The live run's output
is byte-identical before and after this change.
Gate union re-derived at the final commit
c5e46219a1withnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no staletree;
check:bash32-floorpresent and run). All 10 derived families green, pluscheck:nul-bytes, each exit code captured before any pipe. Repo-wideeslint . --no-inline-configran the full population — 5161 files by eslint'sown
--format jsoncount, 0 errors, 0 warnings, this file included — so thereis no narrowing to declare.
Scope
scripts/pm/bare-root-worklist.mjsonly. This card does not reach the classreported in #12328, and is not described as doing so: those four rows never flip
to
REACHABLE, becausecovered()probes a top-of-root path that none of theirspellings match, so this guard never fires on them. #12328 remains open, as does
#12289.
No changeset:
scripts/is not a workspace member and no published package'sfilesfield ships it, so this PR releases nothing — route 2 of thechangeset-check step, the
skip-changesetlabel.Generated by Claude Code