Skip to content

Commit 0cbd5f2

Browse files
claude[bot]claude
andauthored
tooling(pm): re-measure the ratchet-remedy-authority worklist row, and pin the declaration it describes (#15269)
The `check-ratchet-remedy-authority SCRIPTS_DIR scripts` row recorded a walk narrower than the gate performs. When that gate's corpus walk widened to a second directory, the row went on stating "no nested script at any depth", its numbers described the one-directory walk, and its recorded spelling named two of the three hints the gate declares. Both terms are re-measured together on one tree (commit a23603e): 202 files admitted (188 top-level, 14 under the pm directory) against 324 tracked under the bare root, and the recorded spelling grows to the three hints the gate spells, set-equal to that walk in both directions. Nothing reddened for that drift, and the reason is now closed rather than noted: every pin in this file asks the TREE, so a gate that WIDENS what it DECLARES moves no answer any of them read. `--self-test` now reads each DECLARED-NARROWER row's gate source through the watch-hint idiom's own parser and holds the recorded spelling set-equal to the array it finds, at that row's bare root, with a deliberate omission named in `omits` and re-measured every run. Nine records are held that way. No other row is re-decided: the full sweep output differs in exactly this row's stated reason, and all 54 verdicts are unchanged. Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox Co-authored-by: Claude <noreply@anthropic.com>
1 parent ebb5550 commit 0cbd5f2

1 file changed

Lines changed: 174 additions & 24 deletions

File tree

scripts/pm/bare-root-worklist.mjs

Lines changed: 174 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ import { readFileSync, existsSync } from 'node:fs';
6161
import { join } from 'node:path';
6262
import { fileURLToPath } from 'node:url';
6363
import { isEntrypoint } from '../invoked-as.mjs';
64+
// The idiom's own parser, reused rather than re-implemented: a DECLARED-NARROWER
65+
// row's whole claim is about the hint array a gate SPELLS, so the pin below has
66+
// to read that array from the gate's source. `auditSource` already knows every
67+
// rostered declaration name and the literal-array shape the extractor can read,
68+
// and a second copy of either here would be a roster this file has to keep in
69+
// step by hand -- the failure mode it exists to catch, one level up. #15201.
70+
import { auditSource } from '../check-watch-hint-literal.mjs';
6471
import {
6572
collapseHint,
6673
discoverFamilies,
@@ -117,6 +124,18 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
117124
* than the bare word. The row stays in the sweep because
118125
* the bare root is still not covered — which is correct,
119126
* not outstanding debt.
127+
* ⛔ A record carrying a `spelling` is pinned against the
128+
* DECLARATION as well as the tree: `--self-test` reads the
129+
* gate's own hint array out of its source and holds the
130+
* recorded spelling SET-EQUAL to it at this row's root,
131+
* with any deliberate omission NAMED in `omits` and
132+
* re-measured. Every other pin in this file asks the TREE,
133+
* and the tree cannot answer "did the gate widen what it
134+
* declares" — #15201 is that gap measured: a gate grew a
135+
* third hint, this row kept describing two, and every
136+
* LIVE/PRECISE/COMPLETE pin stayed green because the
137+
* recorded spelling was still true OF THE TREE. No pin, no
138+
* verdict, the same way as below.
120139
* REFUSE-WIDE the population really IS the whole top-level root. A
121140
* declaration would be TRUE, and is refused anyway: it
122141
* names the gate for every card under a root the fleet
@@ -236,6 +255,23 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
236255
* gate. ⛔ Its numbers are re-measured on the 2026-09-01 tree in BOTH terms and
237256
* NOT carried from the row they replace, which this docblock forbids by name.
238257
*
258+
* ⭐ That NINETEENTH row was RE-MEASURED on 2026-09-04 (#15201) — both terms
259+
* together on one tree, never refreshed apart, at commit a23603ea. Not a
260+
* re-decision: the verdict is the one it already carried, and no authorisation
261+
* sentence is claimed for it. What moved is the GATE. #15179 widened
262+
* `check-ratchet-remedy-authority`'s walk to a second directory read one level
263+
* (`scripts/` and `scripts/pm/`), so the row's shape claim — "no nested script
264+
* at any depth" — became false of the tree, its numbers described a smaller
265+
* walk, and its recorded spelling named two of the three hints the gate now
266+
* declares. ⚠️ Nothing reddened, and the reason is the point of this entry:
267+
* every pin in this file asks the TREE, the recorded two-hint spelling stayed
268+
* LIVE, PRECISE and COMPLETE over its own claim, and the term that had actually
269+
* moved — what the gate DECLARES — was not a term any pin read. The repair is
270+
* therefore two things and not one: the row re-measured, and the missing
271+
* direction pinned for every DECLARED-NARROWER record that carries a spelling
272+
* (see that verdict's definition above). ⛔ The gate itself is NOT edited from
273+
* here: it is correct, and the map is what went stale.
274+
*
239275
* ⚠️ One row of that seventeen was re-measured into a DIFFERENT population, not
240276
* merely fresher digits: #12392 (PR #12423, `69d0e18`) made
241277
* `check-skills-token-ratchet`'s walk RECURSIVE over whole skill directories, so
@@ -371,14 +407,23 @@ const SPELLINGS = new Map([
371407
holds: (s) => s[0] === 'packages' && s.length >= 2
372408
&& (s[s.length - 1] === 'package.json' || s[s.length - 1] === 'tsup.config.ts'),
373409
}],
374-
['scripts top-level script files', {
410+
['scripts walked-directory script files', {
411+
// One hint per (walked directory, extension) pair the gate's walk really
412+
// admits -- the shape its own docblock argues for, and the reason this entry
413+
// is NOT `scripts/**`: neither directory is descended, so the recursive
414+
// spelling would name this gate for every nested script it never opens.
415+
// `scripts/pm/*.mts` is deliberately absent because that directory carries
416+
// no `.mts` file, and a hint reaching nothing is a dead declaration.
375417
segments: [
376418
['scripts', '*.mjs'],
377419
['scripts', '*.mts'],
420+
['scripts', 'pm', '*.mjs'],
378421
],
379-
claim: 'every `.mjs` or `.mts` file directly under the scripts root (non-recursive)',
380-
holds: (s) => s.length === 2 && s[0] === 'scripts'
381-
&& (s[1].endsWith('.mjs') || s[1].endsWith('.mts')),
422+
claim: 'every `.mjs` or `.mts` file directly under the scripts root, or `.mjs` directly under '
423+
+ 'its pm directory (non-recursive in both)',
424+
holds: (s) => s[0] === 'scripts'
425+
&& ((s.length === 2 && (s[1].endsWith('.mjs') || s[1].endsWith('.mts')))
426+
|| (s.length === 3 && s[1] === 'pm' && s[2].endsWith('.mjs'))),
382427
}],
383428
]);
384429

@@ -513,36 +558,47 @@ const TRIAGE = new Map([
513558
}],
514559
['scripts/check-ratchet-remedy-authority.mjs SCRIPTS_DIR scripts', {
515560
verdict: 'DECLARED-NARROWER',
516-
spelling: 'scripts top-level script files',
561+
spelling: 'scripts walked-directory script files',
517562
why: 'RE-DECIDED 2026-09-01 (#13813) from REFUSE-UNSPELLABLE, whose stated reason — "the idiom '
518563
+ 'has no non-recursive spelling" — was TRUE when written and is FALSE of this tree. It '
519564
+ 'rested on the deletion-collapse: a glob carrying a literal SUFFIX in the final segment '
520565
+ 'was spliced WITHIN the segment, so the only non-recursive spelling reduced to a string no '
521566
+ 'tree can hold and reached nothing. #13448 retired that collapse for exactly this shape — '
522567
+ 'judgedAsPattern routes it to triggerCovers now — which is the same retired collapse the '
523568
+ 'seventeen rows of 2026-08-26 and the eighteenth of 2026-08-29 were re-decided under, one '
524-
+ 'refinement finer, and this row is re-decided under that authorisation sentence and no '
525-
+ 'wider one. Both terms re-measured together on this tree, never refreshed apart: the gate '
526-
+ 'own corpusFiles() walk admits 183 files, against 310 tracked under the bare root (59%). '
527-
+ 'The gate now declares ONE hint per admitted extension beside SCRIPTS_DIR under the '
528-
+ 'ROOT_DIR_WATCH_HINTS idiom, and the pair is SET-EQUAL to that walk in both directions — '
529-
+ '183 of 183, nothing read left uncovered, nothing covered left unread — so 100% precise '
530-
+ 'and complete. The coupling described above was, at the time this row was decided, held '
531-
+ "only in the gate's own --self-test (which pins the hints against SCRIPTS_DIR and "
532-
+ 'CORPUS_EXTENSIONS and refuses both the subtree spelling and the brace form its own '
533-
+ 'messages print), because SPELLINGS held ONE hint per entry and this population needs one '
534-
+ 'per extension — the same shape as the check:logger-receiver-detach and '
535-
+ 'check:dual-build-cjs-loads rows above, and the gap #14233 measured and closed: SPELLINGS '
536-
+ 'now holds a LIST of segment arrays, so the pair is pinned HERE too, LIVE, PRECISE and '
537-
+ 'COMPLETE (183 of 310 tracked files under the bare root, matching the gate own walk exactly, '
538-
+ "re-measured 2026-09-01) — the gate's own pin and this one now independently corroborate "
539-
+ 'the same declaration rather than only one of them re-measuring it. The consumer is '
569+
+ 'refinement finer, and this row was re-decided under that authorisation sentence and no '
570+
+ 'wider one. RE-MEASURED 2026-09-04 (#15201) at commit a23603ea — both terms together on '
571+
+ 'one tree and never refreshed apart — because #15179 widened the WALK under the row: '
572+
+ 'corpusFiles() reads the scripts root AND its pm directory, one level each, and admits '
573+
+ '202 files (188 at the top level, 14 in pm) against 324 tracked under the bare root, 62%. '
574+
+ '⛔ The previous reading, 183 of 310, described the one-directory walk that preceded it '
575+
+ 'and is superseded WHOLE — neither term is carried forward, which this docblock forbids '
576+
+ 'by name. The gate declares ONE hint per (walked directory, extension) pair the walk '
577+
+ 'admits, beside SCRIPTS_DIR under the ROOT_DIR_WATCH_HINTS idiom — three today, the pm '
578+
+ 'mts pair deliberately absent because that directory holds no such file and a hint '
579+
+ 'reaching nothing is a dead declaration — and the set is SET-EQUAL to that walk in both '
580+
+ 'directions: 202 of 202, nothing read left uncovered, nothing covered left unread, so '
581+
+ '100% precise and complete. SPELLINGS holds a LIST of segment arrays since #14233, so '
582+
+ 'that set is pinned HERE too, LIVE, PRECISE and COMPLETE (202 of 324 tracked files under '
583+
+ 'the bare root, matching the gate own walk exactly) — the same multi-hint shape as the '
584+
+ 'check:logger-receiver-detach and check:dual-build-cjs-loads rows above. ⚠️ Those pins '
585+
+ 'ask the TREE, and #15201 is the measurement that they are not sufficient alone: the walk '
586+
+ 'widened, this row went on describing two hints, and every one of them stayed GREEN '
587+
+ 'because the two-hint spelling was still true of the tree it was asked about. So the '
588+
+ 'declaration is now pinned from both sides — the gate own --self-test derives its '
589+
+ 'expected hints from corpusFiles() and holds its array to them (refusing the subtree '
590+
+ 'spelling and the brace form its own messages print), while this file reads that same '
591+
+ 'array out of the gate SOURCE and holds the recorded spelling set-equal to it, so the '
592+
+ 'next widening of that walk reds in both places instead of neither. The consumer is '
540593
+ 'MEASURED, not argued: before this, the derivation placed this family in the residue '
541594
+ 'undetermined bucket, absent from the matched list a brief prints, and a PR that ran its '
542595
+ 'whole derived family green locally lost a CI round to this gate. The row STAYS in the '
543596
+ 'sweep because the bare root is still not covered — no arbitrary file at the top of the '
544-
+ 'root is reached, and no nested script at any depth — which is what this verdict says and '
545-
+ 'is correct, not outstanding debt',
597+
+ 'root is reached, no nested directory other than pm is walked, and no level below either '
598+
+ 'walked directory is descended — which is what this verdict says and is correct, not '
599+
+ 'outstanding debt. ⚠️ The scripts one level down in pm ARE reached now: the flat "no '
600+
+ 'nested script at any depth" this row carried until 2026-09-04 was true of the walk it '
601+
+ 'was written about and false of this one',
546602
}],
547603
// ── Refused: the population is the whole root, and the root is saturated ──
548604
['scripts/check-skill-identifier-liveness.mjs IMPL_ROOTS packages', {
@@ -793,6 +849,18 @@ const TRIAGE = new Map([
793849
['packages/spec/scripts/build-skill-docs.ts SKILLS_DIR skills', {
794850
verdict: 'DECLARED-NARROWER',
795851
spelling: 'skill entrypoints',
852+
// The one hint this gate declares at this root that the recorded spelling
853+
// does NOT name, restated where the declaration pin can read it (#15201).
854+
// Its reason is the `why` below, unchanged and not re-decided: no single
855+
// spelling of the idiom reaches both a per-skill SKILL.md and a file at the
856+
// root beside those directories. Naming it here is what keeps the pin
857+
// two-sided for this row — a hint the gate ADDS later is not covered by
858+
// this omission and reds, which is the whole point.
859+
// ⚠️ SEGMENTS, joined at runtime — the rule SPELLINGS states above, and it
860+
// is not decoration: spelled as a path literal this entry enters THIS
861+
// file's own hint set and hands a reporting tool a population it never
862+
// reads. The self-test that forbids it caught this exact line.
863+
omits: [['skills', 'README.md']],
796864
why: 'RE-POINTED 2026-09-01 (#13519) from SPELLABLE-UNDECLARED, and the deferral it replaces '
797865
+ 'is not merely overruled — its own premise stopped holding. That record read: the '
798866
+ 'population is 12 of 50 (24%), the recorded spelling is 100% PRECISE and deliberately '
@@ -1617,6 +1685,85 @@ function selfTest() {
16171685
rootFiles.length > 0 && covered.length < rootFiles.length);
16181686
}
16191687

1688+
// ── The DECLARATION a row describes, read from the gate's own SOURCE ──────
1689+
//
1690+
// The one direction every pin above is blind to. They all ask the TREE: is
1691+
// the recorded spelling live, does it over-name, does it under-name. A gate
1692+
// that WIDENS what it declares moves none of those answers -- the old
1693+
// spelling goes on covering exactly what it always covered -- so a
1694+
// DECLARED-NARROWER record can stop describing its own gate with this whole
1695+
// battery green. #15201 is that measured, not argued:
1696+
// check-ratchet-remedy-authority grew a third hint, the row here went on
1697+
// naming two, and nothing reddened anywhere.
1698+
//
1699+
// So the gate's array is read back out of its SOURCE -- through the idiom's
1700+
// own parser, never a roster retyped here -- and held SET-EQUAL to the
1701+
// recorded spelling at THIS row's bare root. Two directions, plus one field
1702+
// for the single honest asymmetry:
1703+
//
1704+
// recorded in declared the record cannot claim a hint the gate never
1705+
// spelled; that is a declaration nobody made.
1706+
// declared in recorded the record cannot pass over a hint the gate DID
1707+
// spell -- unless the row NAMES it in `omits`, which
1708+
// is a measured claim of its own and is re-checked
1709+
// every run: an omission the gate stopped declaring
1710+
// reds exactly as loudly as one it started.
1711+
//
1712+
// ⛔ Only DECLARED-NARROWER rows carrying a `spelling` are asked, and that is
1713+
// a definition rather than an exemption: a SPELLABLE-UNDECLARED row IS the
1714+
// row whose gate declares nothing for that population, so the comparison
1715+
// there has its answer built into the verdict, and a row with no spelling
1716+
// records no set to compare. ⛔ When this reds the remedy is to re-measure
1717+
// the ROW -- never to extend `omits` until it agrees again, which is the same
1718+
// move as relaxing `holds`, refused above in as many words.
1719+
const declaredHintsAt = (file, root) => {
1720+
const abs = join(ROOT, file);
1721+
if (!existsSync(abs)) return null;
1722+
return auditSource(file, readFileSync(abs, 'utf8'))
1723+
.filter((d) => d.ok)
1724+
.flatMap((d) => d.hints)
1725+
.filter((h) => h.split('/')[0] === root);
1726+
};
1727+
const sameSet = (a, b) => a.length === b.length
1728+
&& [...a].sort().join('\n') === [...b].sort().join('\n');
1729+
t('an `omits` field appears only on a DECLARED-NARROWER record that names a spelling, and is a '
1730+
+ 'non-empty list of SEGMENT ARRAYS — it records what a DECLARATION says, so there is nothing '
1731+
+ "for it to be about on any other row, and a path literal there would enter this file's own "
1732+
+ 'hint set the way a spelling literal would',
1733+
[...TRIAGE.values()].every((v) => !v.omits
1734+
|| (v.verdict === 'DECLARED-NARROWER' && Boolean(v.spelling)
1735+
&& Array.isArray(v.omits) && v.omits.length > 0
1736+
&& v.omits.every((parts) => Array.isArray(parts) && parts.length > 0
1737+
&& parts.every((p) => typeof p === 'string' && p.length > 0)))));
1738+
let declPinned = 0;
1739+
for (const [key, v] of TRIAGE) {
1740+
if (v.verdict !== 'DECLARED-NARROWER' || !v.spelling) continue;
1741+
const [file, , root] = key.split(' ');
1742+
const recorded = hintsOf(SPELLINGS.get(v.spelling).segments).map((parts) => parts.join('/'));
1743+
const declared = declaredHintsAt(file, root);
1744+
t(`the gate source the row "${key}" judges is readable from here — a row whose file moved `
1745+
+ 'cannot have its declaration read, and reporting that as agreement would be the silence '
1746+
+ 'this pin exists to break', declared !== null);
1747+
if (declared === null) continue;
1748+
t(`the spelling recorded for "${key}" is rooted at that row's own bare root (${root}) — a `
1749+
+ 'spelling paired with the wrong row would otherwise be compared against a declaration it '
1750+
+ 'was never about', recorded.length > 0 && recorded.every((h) => h.split('/')[0] === root));
1751+
const unspelled = recorded.filter((h) => !declared.includes(h));
1752+
t(`every hint the row "${key}" records is one its gate DECLARES at ${root}${unspelled.length
1753+
? ` — NOT DECLARED: ${unspelled.join(' · ')}. The record claims a declaration the gate does `
1754+
+ 'not make; re-measure the row.' : ''}`, unspelled.length === 0);
1755+
const unrecorded = declared.filter((h) => !recorded.includes(h));
1756+
const named = (v.omits ?? []).map((parts) => parts.join('/'));
1757+
t(`…and every hint that gate declares at ${root} is either recorded by "${v.spelling}" or `
1758+
+ `named in the row's \`omits\`${sameSet(unrecorded, named) ? '' : ` — DRIFT: declared and `
1759+
+ `not recorded [${unrecorded.join(' · ') || 'none'}], named as omitted `
1760+
+ `[${named.join(' · ') || 'none'}]. The gate moved under the record: re-measure BOTH `
1761+
+ 'terms of the row and re-decide it.'}`, sameSet(unrecorded, named));
1762+
declPinned += 1;
1763+
}
1764+
t('the declaration pin judges something — at least one DECLARED-NARROWER record carries a '
1765+
+ 'spelling to hold against its gate', declPinned > 0);
1766+
16201767
// Every verdict must be one of the four the docblock defines, and every one
16211768
// must carry its measured reason — a bare verdict is the allowlist row this
16221769
// file exists not to become.
@@ -1681,7 +1828,10 @@ function selfTest() {
16811828
+ "and no folded row's invocations disagree about reachability. "
16821829
+ `${spellingRows.length} record(s) carry a spelling and every one of ${usedSpellings.size} `
16831830
+ 'distinct spelling(s) is pinned LIVE, PRECISE and COMPLETE against the tracked corpus in '
1684-
+ "hintCovers' own terms. The recogniser is proven to speak and to discriminate (a "
1831+
+ `hintCovers' own terms. ${declPinned} DECLARED-NARROWER record(s) are held SET-EQUAL, in `
1832+
+ "both directions, to their gate's own declared hint array read from its source, with "
1833+
+ 'every deliberate omission named and re-measured. The recogniser is proven to speak and '
1834+
+ 'to discriminate (a '
16851835
+ 'separator-carrying and a dotted root are both refused as already visible), the '
16861836
+ 'constant-name restriction is proven to restrict, and neither the triage keys nor this '
16871837
+ `file declare any population of their own. ${CENSUS_REFUSE_WIDE.size} CENSUS row(s) `

0 commit comments

Comments
 (0)