Skip to content
Merged
Show file tree
Hide file tree
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
101 changes: 101 additions & 0 deletions scripts/check-where-matcher-conformance.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,55 @@ const repoRoot = resolve(__dirname, '..');
const BASELINE_PATH = 'scripts/where-matcher-conformance.baseline.json';
const SCAN_ROOT = 'packages';

/**
* ## The dispatch-gates declaration -- the `ROOT_DIR_WATCH_HINTS` idiom (#13163)
*
* `scripts/pm/dispatch-gates.mjs` derives WHICH gates a card must run by matching the
* path literals in each gate's source against the card's changed files. This gate
* declared its population TWICE and the derivation could read NEITHER of them:
*
* 1. IN PROSE, in the discovery section above -- "a function in `packages/**\/*.test.ts`
* whose body...". `extractWatchHints` masks comment ranges by construction, so a
* population documented in a comment is invisible to it BY DESIGN. ⛔ Rewording that
* comment fixes nothing. (The separator is escaped only so the glob cannot close
* this block comment -- the same spelling rule the PM's bare-root worklist follows.)
* 2. IN CODE, as `SCAN_ROOT` above -- a bare single-segment word, which `looksPathy`
* refuses as no hint at all (a measured refusal: admitting the bare-top-level-word
* class costs +139084 fabricated pairs, and it stays). The one narrow re-admission,
* `moduleRelativeDirectoryHint`, resolves a single-segment literal against the
* SCRIPT'S OWN directory, so `'packages'` resolves under `scripts/`, which is not
* tracked ⇒ null.
*
* Measured before this declaration, `extractWatchHints` over this file returned exactly
* ONE hint: `scripts/where-matcher-conformance.baseline.json`, this gate's own ledger.
* ⇒ the derivation could name this gate only for a change set that edits the set of
* files ALREADY KNOWN to be wrong, and never for a NEW silently-wrong matcher anywhere
* under the root it scans -- the exact inverse of what it guards. The live specimen is a
* PR that derived 30 of 30 green gates locally, whole-repo lint included, and still went
* RED in CI on a test file it ADDS.
*
* The spelling below is measured on this tree at 2889 of the 2889 files this gate's own
* `testFilesUnder()` walk admits -- set-equal in BOTH directions against `hintCovers`,
* nothing walked left uncovered and nothing covered left unwalked, so 100% precise and
* complete -- against 5509 tracked files under the bare root. Its liveness and precision
* carry a second, independent pin in the PM's bare-root worklist, whose recorded verdict
* for this row moves to DECLARED-NARROWER with this change.
*
* ⛔ It must be spelled as a LITERAL, not built from `SCAN_ROOT` -- the hint extractor
* reads source text, so a computed template of the root would produce no hint and leave
* the gate exactly as invisible. Both directions are pinned in `--self-test` below. A
* declaration that can drift from the scan is worse than none -- it replaces a silent
* gate with a lying one.
*
* ⚠️ This does NOT retire the convention-KIND entry that names this gate for "adds or
* edits a test file" in the dispatch tool: that entry is a different authority, pinned by
* that tool's own self-test, and it reaches a card dispatched BEFORE its code exists,
* which no path derivation can. What changes is that the high-signal MATCHED column --
* the one a dev pastes and runs -- now names this gate for the test files it really
* walks, instead of only for edits to its own baseline.
*/
const ROOT_DIR_WATCH_HINTS = ['packages/**/*.test.ts'];

// ---------------------------------------------------------------------------
// The probe vocabulary. Field names are deliberately synthetic so no matcher
// can special-case them (several doubles branch on `organization_id`, `id`,
Expand Down Expand Up @@ -872,6 +921,58 @@ function selfTest() {
expect('a fallen count is an error (ratchet down)', reconcile(fakeMeasured, { 'a.test.ts': { silent: 2 } }).length === 1);
expect('a stale entry is an error', reconcile(new Map(), { 'gone.test.ts': { silent: 1 } }).length === 1);

// -- the dispatch-gates declaration (#13163's landing obligation) ---------
//
// Enforcement cannot hold either half here: the declaration is read by ANOTHER TOOL
// (the PM's dispatch derivation), so a wrong or stale one runs green in this file
// forever and pays itself out as a dev dispatched on a test-file card with this gate
// missing from the brief -- the CI round trip #13163 was filed for. A missing
// declaration is a silent gate; a surplus one is a LYING gate, and the price the
// derivation records for a fabricated lead is higher than for a missing one. Driven
// through this gate's OWN corpus walk, never a copy of its regex.
const DECLARED_TAIL = '.test.ts';
const walked = testFilesUnder(join(repoRoot, SCAN_ROOT))
.map((abs) => relative(repoRoot, abs).replace(/\\/g, '/'));
// The needle is ASSEMBLED, never spelled. Written as a literal here it would appear in
// this assertion's own source text, so `includes` would find it in the CHECK rather
// than in the declaration and stay green with the declaration deleted -- a phantom pin.
const declNeedle = `'${SCAN_ROOT}/` + '*'.repeat(2) + `/*${DECLARED_TAIL}'`;
const ownSource = readFileSync(fileURLToPath(import.meta.url), 'utf8');
expect(
'the declaration is spelled as a LITERAL in this source, not computed -- the hint '
+ 'extractor reads source text, so a computed root would build no hint at all',
ownSource.includes(declNeedle),
);
expect(
'the declared hint is rooted at the population constant this gate actually walks',
ROOT_DIR_WATCH_HINTS.length === 1 && ROOT_DIR_WATCH_HINTS[0].startsWith(`${SCAN_ROOT}/`),
);
expect(
'the corpus walk is non-empty, so the two directions below judge something',
walked.length > 0,
);
expect(
'nothing is declared that this gate does not walk -- every file testFilesUnder admits '
+ 'lies under the declared root and ends in the declared extension',
ROOT_DIR_WATCH_HINTS.every((h) => h.endsWith(DECLARED_TAIL))
&& walked.every((f) => f.startsWith(`${SCAN_ROOT}/`) && f.endsWith(DECLARED_TAIL)),
);
// ...and the declared filter is a NARROWING rather than the bare root wearing a glob:
// a non-test sibling sitting in the same directory as an admitted file is NOT admitted.
const admitted = new Set(walked);
const siblingDir = walked.length ? dirname(join(repoRoot, walked[0])) : null;
const nonTestSibling = siblingDir
? readdirSync(siblingDir)
.map((e) => relative(repoRoot, join(siblingDir, e)).replace(/\\/g, '/'))
.find((f) => !f.endsWith(DECLARED_TAIL) && statSync(join(repoRoot, f)).isFile())
: null;
expect('a non-test sibling exists to prove the filter discriminates', Boolean(nonTestSibling));
expect(
'and the declaration is a NARROWING, not the bare root wearing a glob -- that sibling '
+ 'is under the same root and is NOT in the walk',
Boolean(nonTestSibling) && !admitted.has(nonTestSibling),
);

if (failures.length > 0) {
console.error(`✗ check-where-matcher-conformance --self-test (${failures.length} failure(s)):\n`);
for (const f of failures) console.error(` • ${f}`);
Expand Down
38 changes: 34 additions & 4 deletions scripts/pm/bare-root-worklist.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,19 @@ const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|POPULATION|[
* covered. A withdrawn verdict that deleted the row would land it back as an
* untriaged FRESH row on the next run, which is the assertion below saying so.
*
* ⭐ An EIGHTEENTH row was re-decided on 2026-08-29 under that same authorisation
* sentence and no wider one: `check:where-matcher SCAN_ROOT packages`, whose refusal
* rested on the identical retired collapse and whose population is the identical
* `.test.ts` corpus as the `check:objectql-double-limit` row. It was left standing on
* 2026-08-26 because it had no recorded consumer, which is the criterion that split that
* class in two; #13163 is that consumer, and it is MEASURED rather than argued — the
* derivation reached this gate for 0 of the test corpus, so a dev adding a
* silently-wrong matcher ran a 30-of-30 green local union and lost a CI round anyway. So
* this row takes the DECLARED-NARROWER half of the split rather than
* SPELLABLE-UNDECLARED, and its gate now carries the declaration. ⛔ Its numbers are
* re-measured on the 2026-08-29 tree and NOT carried from its sibling, which this
* docblock forbids by name.
*
* ⚠️ 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 @@ -325,6 +338,27 @@ const TRIAGE = new Map([
+ 'bare root is still not covered — the spelling reaches no arbitrary file at the top of '
+ 'the root — which is what this verdict says and is correct, not outstanding debt',
}],
['check:where-matcher SCAN_ROOT packages', {
verdict: 'DECLARED-NARROWER',
spelling: 'package test files',
why: 'REFUSED as unspellable on the reading that every glob form of this population '
+ 'collapses to a malformed double-separator prefix reaching nothing. #12300 retired that '
+ 'collapse — a glob in a non-final segment is MATCHED now — so the refusal was FALSE of '
+ 'this tree, in the same way and for the same reason as its identically-populated sibling '
+ 'check:objectql-double-limit above. Re-measured HERE rather than inherited from that row: '
+ 'the recorded spelling reaches 2889 of the 2889 files this gate own testFilesUnder() walk '
+ 'admits, SET-EQUAL in both directions — nothing walked left uncovered, nothing covered '
+ 'left unwalked — so 100% precise and complete, against 5509 tracked files under the bare '
+ 'root. Declared beside SCAN_ROOT under the ROOT_DIR_WATCH_HINTS idiom for consumer '
+ '#13163, the measured downstream pull this row lacked when the seventeen were '
+ 're-adjudicated: before it, extractWatchHints over the gate returned ONE hint, the gate '
+ 'own baseline JSON, so the derivation could name this gate only for a change set editing '
+ 'the files ALREADY KNOWN to be wrong and never for a NEW silently-wrong matcher — the '
+ 'inverse of what it guards, paid as a CI round trip by a PR that derived 30 of 30 green '
+ 'gates locally. The row STAYS in the sweep because the bare root is still not covered — '
+ 'the spelling reaches no arbitrary file at the top of the root — which is what this '
+ 'verdict says and is correct, not outstanding debt',
}],
['check:skill-refs SKILLS_DIR skills', {
verdict: 'DECLARED-NARROWER',
spelling: 'skill reference folders',
Expand Down Expand Up @@ -451,10 +485,6 @@ const TRIAGE = new Map([
why: 'test files only, 2510 of 4903 (51%) — and already refused in that gate own docblock, '
+ 'measured there at 76 real couplings out of 4861 (1.6%)',
}],
['check:where-matcher SCAN_ROOT packages', {
verdict: 'REFUSE-UNSPELLABLE',
why: 'test files only, 2510 of 4903 (51%)',
}],
['check:runner-env-posture SCANNED_ROOTS packages', {
verdict: 'REFUSE-UNSPELLABLE',
why: 'non-test source beneath a `src` SEGMENT — 1812 of 5241 (35%), re-derived from the gate '
Expand Down
Loading