From 9117bcdcbc0ad9e2330278eb963d68d40f0f128c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 22:56:21 +0000 Subject: [PATCH 1/2] fix(devx): check-declaration-mirrors declares the .d.mts/.mjs population it discovers, so a mirror edit derives it (#15553) Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk --- scripts/check-declaration-mirrors.mjs | 121 +++++++++++++++++++++++++- scripts/pm/dispatch-gates.mjs | 17 ++-- 2 files changed, 131 insertions(+), 7 deletions(-) diff --git a/scripts/check-declaration-mirrors.mjs b/scripts/check-declaration-mirrors.mjs index 016e2efd3d..a017fc90cf 100644 --- a/scripts/check-declaration-mirrors.mjs +++ b/scripts/check-declaration-mirrors.mjs @@ -118,6 +118,61 @@ const HERE = dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = resolve(HERE, '..'); const SCRIPTS_DIR = join(REPO_ROOT, 'scripts'); +/** + * POPULATION DECLARATION -- the corpus this gate's verdict is ABOUT, in the + * subtree spelling `scripts/pm/dispatch-gates.mjs` compares in. + * + * Nothing here reads it; `mirrorFiles()` and `checkPair()` do. It is declared + * anyway, because the dispatch derivation reads SOURCE TEXT and this gate's + * population is discovered by EXTENSION with no path literal anywhere: the walk + * is rooted at `SCRIPTS_DIR`, whose only spelled component is the bare + * single-segment word `scripts` -- no separator, so `extractWatchHints` + * recovers nothing from it, and `hintCovers` would refuse a bare word anyway. + * + * Measured on `ca46f8f12` before this constant existed, on the exact change set + * the defect was filed from: + * + * dispatch-gates --commands -- scripts/js-comment-mask.d.mts \ + * scripts/js-comment-mask.mjs + * -> 31 commands, ZERO of them this gate + * + * So the one class of change this gate exists for -- a hand-written `.d.mts` + * moving out of step with the module it mirrors -- was the class the derivation + * never sent here, and the red arrived in CI a cycle late (#15553; the specimen + * is PR #15532, whose 32 derived commands were all green while this gate went + * red on an arity mismatch). + * + * BOTH SIDES are declared, because either side moving breaks the mirror: the + * declaration side is what `mirrorFiles()` walks, and the module side is what + * `checkPair()` imports to read `Function.length` off. A change set naming only + * `js-comment-mask.mjs` can turn this gate red without touching a `.d.mts` at + * all. + * + * ⛔ NOT a hand list of the four mirror pairs: the corpus is DISCOVERED on + * purpose (see this file's header), and a hint list that enumerated today's + * pairs would go quiet on the fifth exactly as the walk would not. + * + * ## The precision this costs, measured rather than asserted + * + * `scripts/**\/*.d.mts` reaches 4 tracked files and this gate reads all 4 -- + * 100% precise. `scripts/**\/*.mjs` reaches 214 and this gate reads 4 of them + * -- 1.9%. That second hint is the price of keeping the module side declared + * without a hand list, and it is small in the only currency that matters here: + * the pair of commands `lint.yml` runs costs ~0.18 s of wall clock, and over + * the 36 open PRs on the day this landed it newly named this gate on 10 of them + * (1 through the `.d.mts` hint, 9 through the `.mjs` one). ~1.6 s of fleet + * compute per 36 cards, against a defect class whose alternative is a CI red a + * cycle late. Under `hintCovers`' recorded ruling -- over-naming is loud and + * self-limiting, under-naming is silent -- that trade runs the right way. + * + * Spelled as a LITERAL array, never computed from the walk's extension test: + * the extractor reads SOURCE TEXT, so a built spelling keeps this value + * identical at runtime, keeps every assertion about it green, and contributes + * ZERO hints. `check-watch-hint-literal.mjs` holds that rule fleet-wide; the + * self-test below holds the own-source half. + */ +const ROOT_DIR_WATCH_HINTS = ['scripts/**/*.d.mts', 'scripts/**/*.mjs']; + /** * The export spellings this parser recognises, in the words a declaration * author would write them. Published for the same reason the cross-package @@ -429,7 +484,7 @@ const SELF_TEST_VERDICT = 'check-declaration-mirrors self-test reached its verdi // not red. A battery BELOW its floor means cases stopped running; the remedy is // to find what stopped registering. const SELF_TEST_BATTERIES = Object.freeze({ - 'check-declaration-mirrors self-test': 23, + 'check-declaration-mirrors self-test': 29, }); // DELETING an entry silences that battery's floor exactly as effectively as @@ -603,6 +658,70 @@ async function selfTest() { mirrorFiles().every((f) => f.endsWith('.d.mts')), ); + // ── the population this gate DECLARES to the dispatch derivation (#15553) ── + // + // The walk above is discovered by EXTENSION and spells no path, so before the + // declaration beside `SCRIPTS_DIR` existed a change set naming a mirror -- + // either half of one -- derived every other `scripts/` family and not this + // one. Nothing in THIS file can ENFORCE the declaration: `extractWatchHints` + // and `hintCovers` live in another tool entirely, so a wrong or missing one + // runs green here forever. What CAN be held here are the properties a wrong + // one breaks -- it is a live literal the extractor can read, it is not the + // bare root the consumer refuses or over-names on, and its extensions still + // admit every file the walk really opens, on BOTH sides of a mirror. + const declaredRoots = ROOT_DIR_WATCH_HINTS.map((h) => h.split('/')[0]); + const declaredSuffixes = ROOT_DIR_WATCH_HINTS.map((h) => h.slice(h.lastIndexOf('*') + 1)); + const admits = (repoRelative) => + ROOT_DIR_WATCH_HINTS.some((h, i) => + repoRelative.split('/')[0] === declaredRoots[i] && repoRelative.endsWith(declaredSuffixes[i])); + ok( + 'the gate declares a population at all', + Array.isArray(ROOT_DIR_WATCH_HINTS) && ROOT_DIR_WATCH_HINTS.length > 0, + ); + ok( + 'every declared hint is multi-segment, so the consumer does not refuse it as a bare word', + ROOT_DIR_WATCH_HINTS.every((h) => h.split('/').filter(Boolean).length > 1), + ); + ok( + 'and none of them is the bare subtree or the repo root, which would name this gate for every ' + + 'JSON, Markdown and text file the walk never opens', + ROOT_DIR_WATCH_HINTS.every((h) => !h.endsWith('/**') && h !== '.' && h !== '**'), + ); + // The card's own point, held against the LIVE walk rather than a fixture: the + // declaration side of every mirror this tree really has is admitted by the + // extensions declared. A fifth pair added tomorrow is walked by `mirrorFiles` + // and covered by the same hint, which is the property a hand list would lose. + ok( + 'every declaration the walk discovers is admitted by a declared hint', + mirrorFiles().length > 0 + && mirrorFiles().every((f) => admits(relative(REPO_ROOT, f).split(sep).join('/'))), + ); + // And the MODULE side, which `checkPair` imports to read `Function.length` + // off: an arity change there reds this gate with no `.d.mts` edited at all, + // so a declaration naming only the declarations would miss half the class. + ok( + 'and so is the module each declaration mirrors, whose arity the gate reads', + mirrorFiles().length > 0 + && mirrorFiles().every((f) => + admits(relative(REPO_ROOT, f.replace(/\.d\.mts$/, '.mjs')).split(sep).join('/'))), + ); + // Read from THIS file's own source, comment-masked and scoped to the + // declaration STATEMENT: a whole-file search finds the spellings the docblock + // above writes and passes on a computed declaration, which is the one + // spelling that keeps every case above green while contributing ZERO hints. + const ownDeclaration = (() => { + const code = maskComments(readFileSync(fileURLToPath(import.meta.url), 'utf8')); + const sites = [...code.matchAll(/\bconst\s+ROOT_DIR_WATCH_HINTS\s*=\s*([^;]*);/g)]; + return sites.length === 1 ? sites[0][1] : null; + })(); + ok( + 'the declaration is ONE literal array of quoted strings — a computed spelling keeps this value ' + + 'identical at runtime and contributes ZERO hints to the derivation', + ownDeclaration !== null + && ROOT_DIR_WATCH_HINTS.every((h) => ownDeclaration.includes(`'${h}'`)) + && /^\s*\[\s*(?:'[^'\\]*'\s*,\s*)*'[^'\\]*'\s*,?\s*\]\s*$/.test(ownDeclaration), + ); + // ── The floor: every declared battery RAN, and ran its cases (#13489) ──── // // Evaluated after every battery has had its chance and BEFORE the verdict, so diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index 24f7c95487..41238c9c78 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -11805,12 +11805,17 @@ export function bannerLines({ identity, paths = [], drift = null }) { * "1288 cases pass" to zero bytes of output and exit 0 — a self-test that never * finished, reported as one that passed. * - * The mechanical probe in `scripts/measure-self-test-floor.mjs` cannot read this - * file (its anchor matches the first `function selfTest() {` in the source, which - * here is a FIXTURE STRING, so the injection lands inside a template literal and - * only ever produces a SyntaxError). That is a limit of the instrument, not a - * property of this file, and it is why the entry is hand-read there. Anchoring an - * early return on the real definition below measures it in one run. + * The mechanical probe in `scripts/measure-self-test-floor.mjs` reaches the real + * definition below only once its anchor is taken over a comment-and-literal + * MASK. Read raw — measured on `ca46f8f12` — the first `function selfTest() {` + * in this source is that phrase quoted inside a DOCBLOCK, and the next is a + * FIXTURE STRING; the injected marker carries a comment TERMINATOR, so it ends + * that comment early and the copy only ever produces a SyntaxError. #14963 + * (PR #15580) moves the anchor onto the definition, after which the copy parses + * and runs. Either way that was a limit of the INSTRUMENT recorded as a + * property of this file: the entry stays hand-read in `ENTRY_BY_HAND`, and the + * NOT MEASURED its row keeps is the probe's own artefact (#15515), not a claim + * about this file. */ /** * The lines ONE self-test case prints — a pure renderer, so both directions can From ab5c01379f895b305a56926a274fb323387c4906 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 22:58:26 +0000 Subject: [PATCH 2/2] docs(devx): dispatch-gates' probe note reads the landed anchor, not the pre-#14963 one (#15553) Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk --- scripts/pm/dispatch-gates.mjs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index 41238c9c78..841e931eb1 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -11805,17 +11805,17 @@ export function bannerLines({ identity, paths = [], drift = null }) { * "1288 cases pass" to zero bytes of output and exit 0 — a self-test that never * finished, reported as one that passed. * - * The mechanical probe in `scripts/measure-self-test-floor.mjs` reaches the real - * definition below only once its anchor is taken over a comment-and-literal - * MASK. Read raw — measured on `ca46f8f12` — the first `function selfTest() {` - * in this source is that phrase quoted inside a DOCBLOCK, and the next is a - * FIXTURE STRING; the injected marker carries a comment TERMINATOR, so it ends - * that comment early and the copy only ever produces a SyntaxError. #14963 - * (PR #15580) moves the anchor onto the definition, after which the copy parses - * and runs. Either way that was a limit of the INSTRUMENT recorded as a - * property of this file: the entry stays hand-read in `ENTRY_BY_HAND`, and the - * NOT MEASURED its row keeps is the probe's own artefact (#15515), not a claim - * about this file. + * The mechanical probe in `scripts/measure-self-test-floor.mjs` READS this file + * since #14963: its anchor is taken over a comment-and-literal MASK and must + * begin a line, so it lands on the real definition below rather than on either + * decoy ahead of it — that phrase quoted in a docblock, then a FIXTURE STRING. + * Injected there the copy PARSES and RUNS (re-measured on the merge base of + * this change: exit 1, `selfTest() returned without reaching its verdict`), + * where the unmasked anchor could only ever produce a SyntaxError. The entry is + * still hand-read in `ENTRY_BY_HAND` — four self-test-shaped names stand in raw + * source — and the NOT MEASURED its row keeps is the probe's own artefact + * (#15515: it writes the copy under `scripts/`, where a single-site sweep + * refuses the near-duplicate), not a property of this file. */ /** * The lines ONE self-test case prints — a pure renderer, so both directions can