@@ -124,8 +124,18 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
124124 * than the bare word. The row stays in the sweep because
125125 * the bare root is still not covered — which is correct,
126126 * not outstanding debt.
127- * ⛔ A record carrying a `spelling` is pinned against the
128- * DECLARATION as well as the tree: `--self-test` reads the
127+ * ⛔ Every record MUST carry a `spelling` naming a
128+ * `SPELLINGS` entry, for the reason this verdict is the
129+ * one where the requirement bites hardest: its whole
130+ * content is a claim about a DECLARATION, and a record
131+ * naming no set records nothing for the declaration pin
132+ * to compare — it sits outside that pin by construction,
133+ * not by oversight, keeping its verdict while the gate
134+ * moves under it. Measured, at the one row that did:
135+ * #15270. The requirement is held by `--self-test`, the
136+ * same way it is held for SPELLABLE-UNDECLARED below.
137+ * ⛔ That record is then pinned against the DECLARATION
138+ * as well as the tree: `--self-test` reads the
129139 * gate's own hint array out of its source and holds the
130140 * recorded spelling SET-EQUAL to it at this row's root,
131141 * with any deliberate omission NAMED in `omits` and
@@ -272,6 +282,21 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
272282 * (see that verdict's definition above). ⛔ The gate itself is NOT edited from
273283 * here: it is correct, and the map is what went stale.
274284 *
285+ * ⭐ The TENTH DECLARED-NARROWER row was brought INSIDE that pin on 2026-09-04
286+ * (#15270), and it is a repair rather than a re-decision: the verdict is the one
287+ * it has carried since it was written and no authorisation sentence is claimed
288+ * for it. `check-driver-conformance DRIVERS_DIR packages` carried no `spelling`,
289+ * so the declaration pin skipped it by its own scoping rule — while its gate DID
290+ * declare a hint at that root, which the row named in PROSE and nothing held to
291+ * the array. Both terms are re-measured together on one tree in the row itself,
292+ * against the gate's own walk driven under an fs recorder rather than reproduced
293+ * by hand. What changes here is the FLOOR: the requirement to carry a spelling
294+ * now extends from SPELLABLE-UNDECLARED to DECLARED-NARROWER, so a record whose
295+ * whole content is a claim about a declaration may no longer decline to record
296+ * the set that claim is about, and the class cannot grow back one unspelled row
297+ * at a time. ⛔ The gate is not edited from here either: it is correct, and what
298+ * went stale is the MAP, which recorded less than it judged.
299+ *
275300 * ⚠️ One row of that seventeen was re-measured into a DIFFERENT population, not
276301 * merely fresher digits: #12392 (PR #12423, `69d0e18`) made
277302 * `check-skills-token-ratchet`'s walk RECURSIVE over whole skill directories, so
@@ -371,6 +396,17 @@ const SPELLINGS = new Map([
371396 claim : "every file inside a skill's references folder, at any depth" ,
372397 holds : ( s ) => s [ 0 ] === 'skills' && s . length >= 4 && s [ 2 ] === 'references' ,
373398 } ] ,
399+ [ 'driver package files' , {
400+ // The WHOLE subtree, which is what the gate declares -- and the widest of
401+ // the entries here for that reason. Its row's `why` records the direction
402+ // that declaration errs in, measured against the gate's own walk: it names
403+ // 30 files the gate neither opens nor stats. Recording anything narrower
404+ // here would be a claim about a declaration nobody made, which the pin
405+ // below refuses in both directions.
406+ segments : [ 'packages' , 'drivers' , '**' ] ,
407+ claim : 'every file at any depth under the drivers directory of the packages root' ,
408+ holds : ( s ) => s [ 0 ] === 'packages' && s [ 1 ] === 'drivers' && s . length >= 3 ,
409+ } ] ,
374410 // ── Multi-hint entries (#14233) — a gate whose declared population is more
375411 // than one glob at the same root. `holds` accepts whatever any member hint
376412 // covers; see `hintsOf` and the pin loop below for how the union is asked.
@@ -446,8 +482,37 @@ const TRIAGE = new Map([
446482 // ── Taken: a strictly narrower subtree ────────────────────────────────────
447483 [ 'scripts/check-driver-conformance.mjs DRIVERS_DIR packages' , {
448484 verdict : 'DECLARED-NARROWER' ,
449- why : 'the literal is a join() component; the real population is the driver subtree, declared '
450- + 'there at 259 of 291 files (89%) instead of 259 of 4903 (5.3%) at the bare root' ,
485+ spelling : 'driver package files' ,
486+ why : 'the literal is a join() component: the gate assembles its scan root from bare '
487+ + 'single-segment words, so the extractor sees the top-level word and nothing else, and the '
488+ + 'real population is the driver subtree, declared there beside the constant under the '
489+ + 'ROOT_DIR_WATCH_HINTS idiom. RE-MEASURED 2026-09-04 (#15270) at commit 2200f8ec, tree '
490+ + 'b8ebad25 — both terms together on one tree, never refreshed apart — and the previous '
491+ + 'reading (259 of 291, against 4903 at the bare root) is superseded WHOLE, neither term '
492+ + 'carried forward. The walk was driven under an fs recorder rather than reproduced by hand, '
493+ + 'this gate exporting none of it: discovery takes the immediate children of the drivers '
494+ + 'root that carry a manifest and the driver- prefix (five packages today), and every `.ts` '
495+ + "file at any depth under each package's src directory is OPENED, node_modules and dist "
496+ + 'skipped — 344 of the 379 tracked files under the declared subtree, 90.8%, against 5979 '
497+ + 'tracked under the bare root, 5.8%. The five per-package manifests are STATTED rather than '
498+ + 'opened, as the existence test that admits a package to the matrix, so 349 of 379 are '
499+ + 'reached one way or the other. ⚠️ The DIRECTION the declaration errs is stated rather than '
500+ + 'left to the ratio: it errs WIDE, naming 30 files the gate neither opens nor stats — 11 '
501+ + 'markdown, 6 tsconfig JSON, 6 config `.ts` sitting beside the manifests rather than under '
502+ + 'src, 5 LICENSE, one `.mjs` and one dotfile — and it is nevertheless the only spellable '
503+ + 'claim, since collapseHint can express a SUBTREE and not "the src trees inside it". ⛔ The '
504+ + 'record is what the gate SPELLS and is not narrowed to the walk: the pin holds it against '
505+ + 'the DECLARATION, so a spelling narrower than the array would be a claim about a '
506+ + 'declaration nobody made. Until 2026-09-04 this row named that subtree in PROSE only and '
507+ + 'was the one DECLARED-NARROWER record with no spelling, so it sat outside the declaration '
508+ + 'pin #15201 landed — the gate could widen or drop the hint with every pin in this file '
509+ + 'green — which is why the spelling requirement now extends to this verdict. The other '
510+ + 'root this gate reads, the case-set directory under the spec package (8 files), stays '
511+ + 'deliberately undeclared on its own docblock reasoning: that is a population absent from '
512+ + 'the array, not a declared hint the record passes over, so this row carries no `omits`. '
513+ + '⛔ The gate is NOT edited from here. The row STAYS in the sweep because the bare root is '
514+ + 'still not covered — no arbitrary file at the top of packages/ is reached — which is what '
515+ + 'this verdict says and is correct, not outstanding debt' ,
451516 } ] ,
452517 [ 'scripts/check-logger-receiver-detach.mjs SCAN_ROOTS packages' , {
453518 verdict : 'DECLARED-NARROWER' ,
@@ -1648,9 +1713,31 @@ function selfTest() {
16481713 // describing the tree. ⛔ The remedy is to re-measure the ROW, never to relax
16491714 // `holds` until it agrees again.
16501715 const spellingRows = [ ...TRIAGE . entries ( ) ] . filter ( ( [ , v ] ) => v . spelling ) ;
1651- t ( 'every SPELLABLE-UNDECLARED record names a spelling — the verdict is DEFINED only with one, '
1652- + 'and the ruling that created it rejects the whole option on an unpinned value' ,
1653- [ ...TRIAGE . values ( ) ] . every ( ( v ) => v . verdict !== 'SPELLABLE-UNDECLARED' || Boolean ( v . spelling ) ) ) ;
1716+ // The two verdicts whose whole content is a claim only a spelling records, so
1717+ // a record without one records nothing for the pins to hold. SPELLABLE-
1718+ // UNDECLARED says a precise live spelling EXISTS, unpinnable while unspoken;
1719+ // DECLARED-NARROWER says the GATE DECLARES one, which the declaration pin
1720+ // below can compare only against a recorded set. #15270 measured what the
1721+ // second gap costs: the tenth DECLARED-NARROWER record named its subtree in
1722+ // PROSE only, so it sat outside that pin by construction while its gate did
1723+ // declare a hint at that very root — and nothing in this file reddened.
1724+ const SPELLING_REQUIRED = new Set ( [ 'SPELLABLE-UNDECLARED' , 'DECLARED-NARROWER' ] ) ;
1725+ const spellingHeld = ( v ) => ! SPELLING_REQUIRED . has ( v . verdict ) || Boolean ( v . spelling ) ;
1726+ const unspelled = [ ...TRIAGE . entries ( ) ] . filter ( ( [ , v ] ) => ! spellingHeld ( v ) ) . map ( ( [ k ] ) => k ) ;
1727+ t ( 'every SPELLABLE-UNDECLARED and every DECLARED-NARROWER record names a spelling — both '
1728+ + 'verdicts are DEFINED only with one, and the ruling that created the first rejects the '
1729+ + `whole option on an unpinned value${ unspelled . length
1730+ ? ` — UNSPELLED: ${ unspelled . join ( ' · ' ) } . Record the population as a SPELLINGS entry and `
1731+ + 'point the row at it, re-measuring BOTH terms on one tree; a row that cannot be spelled '
1732+ + 'is a row whose verdict is one of the two refusals.' : '' } `,
1733+ unspelled . length === 0 ) ;
1734+ t ( '…and that rule can FAIL, asked of FIXTURE records rather than of the map it judges: a '
1735+ + 'record carrying either verdict and no spelling is REFUSED, while the two refusals — which '
1736+ + 'have no spelling to record — are not' ,
1737+ ! spellingHeld ( { verdict : 'DECLARED-NARROWER' } )
1738+ && ! spellingHeld ( { verdict : 'SPELLABLE-UNDECLARED' } )
1739+ && spellingHeld ( { verdict : 'REFUSE-WIDE' } )
1740+ && spellingHeld ( { verdict : 'REFUSE-UNSPELLABLE' } ) ) ;
16541741 t ( 'every recorded spelling names a SPELLINGS entry' ,
16551742 spellingRows . every ( ( [ , v ] ) => SPELLINGS . has ( v . spelling ) ) ) ;
16561743 t ( 'the pins below judge something — at least one record carries a spelling' ,
@@ -1709,11 +1796,13 @@ function selfTest() {
17091796 // every run: an omission the gate stopped declaring
17101797 // reds exactly as loudly as one it started.
17111798 //
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
1799+ // ⛔ Only DECLARED-NARROWER rows are asked, and that is a definition rather
1800+ // than an exemption: a SPELLABLE-UNDECLARED row IS the row whose gate
1801+ // declares nothing for that population, so the comparison there has its
1802+ // answer built into the verdict. The `spelling` test in the loop is belt to
1803+ // the braces above, which now REFUSE such a record rather than let it pass
1804+ // over this pin unjudged (#15270) — reaching it would mean that rule had
1805+ // been removed. ⛔ When this reds the remedy is to re-measure
17171806 // the ROW -- never to extend `omits` until it agrees again, which is the same
17181807 // move as relaxing `holds`, refused above in as many words.
17191808 const declaredHintsAt = ( file , root ) => {
0 commit comments