Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 174 additions & 24 deletions scripts/pm/bare-root-worklist.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ import { readFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { isEntrypoint } from '../invoked-as.mjs';
// The idiom's own parser, reused rather than re-implemented: a DECLARED-NARROWER
// row's whole claim is about the hint array a gate SPELLS, so the pin below has
// to read that array from the gate's source. `auditSource` already knows every
// rostered declaration name and the literal-array shape the extractor can read,
// and a second copy of either here would be a roster this file has to keep in
// step by hand -- the failure mode it exists to catch, one level up. #15201.
import { auditSource } from '../check-watch-hint-literal.mjs';
import {
collapseHint,
discoverFamilies,
Expand Down Expand Up @@ -117,6 +124,18 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
* than the bare word. The row stays in the sweep because
* the bare root is still not covered — which is correct,
* not outstanding debt.
* ⛔ A record carrying a `spelling` is pinned against the
* DECLARATION as well as the tree: `--self-test` reads the
* gate's own hint array out of its source and holds the
* recorded spelling SET-EQUAL to it at this row's root,
* with any deliberate omission NAMED in `omits` and
* re-measured. Every other pin in this file asks the TREE,
* and the tree cannot answer "did the gate widen what it
* declares" — #15201 is that gap measured: a gate grew a
* third hint, this row kept describing two, and every
* LIVE/PRECISE/COMPLETE pin stayed green because the
* recorded spelling was still true OF THE TREE. No pin, no
* verdict, the same way as below.
* REFUSE-WIDE the population really IS the whole top-level root. A
* declaration would be TRUE, and is refused anyway: it
* names the gate for every card under a root the fleet
Expand Down Expand Up @@ -236,6 +255,23 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
* gate. ⛔ Its numbers are re-measured on the 2026-09-01 tree in BOTH terms and
* NOT carried from the row they replace, which this docblock forbids by name.
*
* ⭐ That NINETEENTH row was RE-MEASURED on 2026-09-04 (#15201) — both terms
* together on one tree, never refreshed apart, at commit a23603ea. Not a
* re-decision: the verdict is the one it already carried, and no authorisation
* sentence is claimed for it. What moved is the GATE. #15179 widened
* `check-ratchet-remedy-authority`'s walk to a second directory read one level
* (`scripts/` and `scripts/pm/`), so the row's shape claim — "no nested script
* at any depth" — became false of the tree, its numbers described a smaller
* walk, and its recorded spelling named two of the three hints the gate now
* declares. ⚠️ Nothing reddened, and the reason is the point of this entry:
* every pin in this file asks the TREE, the recorded two-hint spelling stayed
* LIVE, PRECISE and COMPLETE over its own claim, and the term that had actually
* moved — what the gate DECLARES — was not a term any pin read. The repair is
* therefore two things and not one: the row re-measured, and the missing
* direction pinned for every DECLARED-NARROWER record that carries a spelling
* (see that verdict's definition above). ⛔ The gate itself is NOT edited from
* here: it is correct, and the map is what went stale.
*
* ⚠️ One row of that seventeen was re-measured into a DIFFERENT population, not
* merely fresher digits: #12392 (PR #12423, `69d0e18`) made
* `check-skills-token-ratchet`'s walk RECURSIVE over whole skill directories, so
Expand Down Expand Up @@ -371,14 +407,23 @@ const SPELLINGS = new Map([
holds: (s) => s[0] === 'packages' && s.length >= 2
&& (s[s.length - 1] === 'package.json' || s[s.length - 1] === 'tsup.config.ts'),
}],
['scripts top-level script files', {
['scripts walked-directory script files', {
// One hint per (walked directory, extension) pair the gate's walk really
// admits -- the shape its own docblock argues for, and the reason this entry
// is NOT `scripts/**`: neither directory is descended, so the recursive
// spelling would name this gate for every nested script it never opens.
// `scripts/pm/*.mts` is deliberately absent because that directory carries
// no `.mts` file, and a hint reaching nothing is a dead declaration.
segments: [
['scripts', '*.mjs'],
['scripts', '*.mts'],
['scripts', 'pm', '*.mjs'],
],
claim: 'every `.mjs` or `.mts` file directly under the scripts root (non-recursive)',
holds: (s) => s.length === 2 && s[0] === 'scripts'
&& (s[1].endsWith('.mjs') || s[1].endsWith('.mts')),
claim: 'every `.mjs` or `.mts` file directly under the scripts root, or `.mjs` directly under '
+ 'its pm directory (non-recursive in both)',
holds: (s) => s[0] === 'scripts'
&& ((s.length === 2 && (s[1].endsWith('.mjs') || s[1].endsWith('.mts')))
|| (s.length === 3 && s[1] === 'pm' && s[2].endsWith('.mjs'))),
}],
]);

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

// ── The DECLARATION a row describes, read from the gate's own SOURCE ──────
//
// The one direction every pin above is blind to. They all ask the TREE: is
// the recorded spelling live, does it over-name, does it under-name. A gate
// that WIDENS what it declares moves none of those answers -- the old
// spelling goes on covering exactly what it always covered -- so a
// DECLARED-NARROWER record can stop describing its own gate with this whole
// battery green. #15201 is that measured, not argued:
// check-ratchet-remedy-authority grew a third hint, the row here went on
// naming two, and nothing reddened anywhere.
//
// So the gate's array is read back out of its SOURCE -- through the idiom's
// own parser, never a roster retyped here -- and held SET-EQUAL to the
// recorded spelling at THIS row's bare root. Two directions, plus one field
// for the single honest asymmetry:
//
// recorded in declared the record cannot claim a hint the gate never
// spelled; that is a declaration nobody made.
// declared in recorded the record cannot pass over a hint the gate DID
// spell -- unless the row NAMES it in `omits`, which
// is a measured claim of its own and is re-checked
// every run: an omission the gate stopped declaring
// reds exactly as loudly as one it started.
//
// ⛔ Only DECLARED-NARROWER rows carrying a `spelling` are asked, and that is
// a definition rather than an exemption: a SPELLABLE-UNDECLARED row IS the
// row whose gate declares nothing for that population, so the comparison
// there has its answer built into the verdict, and a row with no spelling
// records no set to compare. ⛔ When this reds the remedy is to re-measure
// the ROW -- never to extend `omits` until it agrees again, which is the same
// move as relaxing `holds`, refused above in as many words.
const declaredHintsAt = (file, root) => {
const abs = join(ROOT, file);
if (!existsSync(abs)) return null;
return auditSource(file, readFileSync(abs, 'utf8'))
.filter((d) => d.ok)
.flatMap((d) => d.hints)
.filter((h) => h.split('/')[0] === root);
};
const sameSet = (a, b) => a.length === b.length
&& [...a].sort().join('\n') === [...b].sort().join('\n');
t('an `omits` field appears only on a DECLARED-NARROWER record that names a spelling, and is a '
+ 'non-empty list of SEGMENT ARRAYS — it records what a DECLARATION says, so there is nothing '
+ "for it to be about on any other row, and a path literal there would enter this file's own "
+ 'hint set the way a spelling literal would',
[...TRIAGE.values()].every((v) => !v.omits
|| (v.verdict === 'DECLARED-NARROWER' && Boolean(v.spelling)
&& Array.isArray(v.omits) && v.omits.length > 0
&& v.omits.every((parts) => Array.isArray(parts) && parts.length > 0
&& parts.every((p) => typeof p === 'string' && p.length > 0)))));
let declPinned = 0;
for (const [key, v] of TRIAGE) {
if (v.verdict !== 'DECLARED-NARROWER' || !v.spelling) continue;
const [file, , root] = key.split(' ');
const recorded = hintsOf(SPELLINGS.get(v.spelling).segments).map((parts) => parts.join('/'));
const declared = declaredHintsAt(file, root);
t(`the gate source the row "${key}" judges is readable from here — a row whose file moved `
+ 'cannot have its declaration read, and reporting that as agreement would be the silence '
+ 'this pin exists to break', declared !== null);
if (declared === null) continue;
t(`the spelling recorded for "${key}" is rooted at that row's own bare root (${root}) — a `
+ 'spelling paired with the wrong row would otherwise be compared against a declaration it '
+ 'was never about', recorded.length > 0 && recorded.every((h) => h.split('/')[0] === root));
const unspelled = recorded.filter((h) => !declared.includes(h));
t(`every hint the row "${key}" records is one its gate DECLARES at ${root}${unspelled.length
? ` — NOT DECLARED: ${unspelled.join(' · ')}. The record claims a declaration the gate does `
+ 'not make; re-measure the row.' : ''}`, unspelled.length === 0);
const unrecorded = declared.filter((h) => !recorded.includes(h));
const named = (v.omits ?? []).map((parts) => parts.join('/'));
t(`…and every hint that gate declares at ${root} is either recorded by "${v.spelling}" or `
+ `named in the row's \`omits\`${sameSet(unrecorded, named) ? '' : ` — DRIFT: declared and `
+ `not recorded [${unrecorded.join(' · ') || 'none'}], named as omitted `
+ `[${named.join(' · ') || 'none'}]. The gate moved under the record: re-measure BOTH `
+ 'terms of the row and re-decide it.'}`, sameSet(unrecorded, named));
declPinned += 1;
}
t('the declaration pin judges something — at least one DECLARED-NARROWER record carries a '
+ 'spelling to hold against its gate', declPinned > 0);

// Every verdict must be one of the four the docblock defines, and every one
// must carry its measured reason — a bare verdict is the allowlist row this
// file exists not to become.
Expand Down Expand Up @@ -1681,7 +1828,10 @@ function selfTest() {
+ "and no folded row's invocations disagree about reachability. "
+ `${spellingRows.length} record(s) carry a spelling and every one of ${usedSpellings.size} `
+ 'distinct spelling(s) is pinned LIVE, PRECISE and COMPLETE against the tracked corpus in '
+ "hintCovers' own terms. The recogniser is proven to speak and to discriminate (a "
+ `hintCovers' own terms. ${declPinned} DECLARED-NARROWER record(s) are held SET-EQUAL, in `
+ "both directions, to their gate's own declared hint array read from its source, with "
+ 'every deliberate omission named and re-measured. The recogniser is proven to speak and '
+ 'to discriminate (a '
+ 'separator-carrying and a dotted root are both refused as already visible), the '
+ 'constant-name restriction is proven to restrict, and neither the triage keys nor this '
+ `file declare any population of their own. ${CENSUS_REFUSE_WIDE.size} CENSUS row(s) `
Expand Down
Loading