From 4747fe28a32bad16d8c504461bd4dccc1398f347 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 17:54:03 +0000 Subject: [PATCH 1/2] test(pm): pin the test-file kind entry for check:cross-package-test-inputs against its own deletion criterion The convention-trigger entry this card asked for has been in the table since #10542. What the re-measurement found instead is that the entry now READS redundant against its own stated deletion criterion and is not: since PR #12300 taught hintCovers to read a glob in a non-final segment, the hint route names the gate for 2758 of the 2771 tracked test files (99.5%, against 0-3.3% for its five siblings in this kind) -- through a hint INHERITED from the declaration table the gate imports, where it is one package's declared turbo inputs glob rather than the gate's own population. Records the measurement at the criterion it qualifies, and pins every load-bearing half of it in --self-test: the residue class (no test file outside the packages tree, no .tsx inside it, nothing under apps), the live specimens, the inheritance provenance, and that the KIND still names the gate for all of them. Both routes are kept -- two routes to one gate is redundancy, not a bug. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6 --- scripts/pm/dispatch-gates.mjs | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index 87ff088c30..7f1091a348 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -2745,6 +2745,32 @@ export function reachesMetadataFormModule(path, modulePaths) { * path each already carries is their own output, and a card editing a * baseline matches through it today without making the gate derivable for * anybody else. + * + * ⚠ "A literal naming their POPULATION" is the whole of that criterion, + * and one gate in this kind now fails it while READING as satisfied. + * Measured on this tree (#11199, the day PR #12300 landed): of the 2771 + * tracked test files, the hint route names `check:cross-package-test- + * inputs` for 2758 of them — 99.5%, against 0–3.3% for its five siblings + * in this same kind — because #12300 taught `hintCovers` to read a glob in + * a non-final segment and the deep `packages` glob for TypeScript files + * came back to life. (That glob is not spelled here: its own wildcard + * closes a block comment.) The hint + * is neither this gate's population nor even its own literal: it is + * INHERITED from the declaration table the gate imports, where it is ONE + * package's declared turbo `inputs` glob (`@objectstack/core`'s, wide + * because a single pin test there walks the whole repo with `git + * ls-files`). It is a row the gate JUDGES, not a population the gate + * DECLARES — so it narrows the day that package's declaration narrows, + * which is the direction the gate's own repair advice pushes. And even at + * 99.5% it reaches no test file outside `packages/**` (10 tracked today, + * all under `examples/**`), none with a `.tsx` suffix (3 today, all in + * client-react), and none under `apps/**` the day one arrives — while + * the KIND reaches every one of them, because the trigger really is "a + * test file's content changed, full stop". Both routes are kept (two + * routes to one gate is redundancy, not a defect); the KIND is the + * load-bearing one. The residue and the inheritance are pinned in the + * self-test, so the next reader re-points a red case instead of + * re-deriving this paragraph. * - i18n entry: when `check-i18n-bundles.mjs` stops discovering its targets * at runtime and names its POPULATION in its own source — a literal each * owning package path starts with — the path half matches and this entry @@ -5973,6 +5999,59 @@ function selfTest() { liveFamilies.has('check:cross-package-test-inputs'), ); + // ── The test-file entry's deletion criterion, MEASURED (#11199) ─────────── + // + // The card behind these cases reported that no local derivation ever named + // `check:cross-package-test-inputs` for an edited test file. That is closed — + // the entry above has been in the table since #10542 — and the reason these + // cases exist rather than a seventh entry is what the re-measurement found: + // the entry now READS redundant against its own stated deletion criterion, + // and it is not. The full measurement is in that criterion's bullet in this + // table's docblock; what is pinned here is every load-bearing half of it, so + // the claim reddens instead of ageing. + // + // Both directions matter. The positive case keeps the redundancy honest (the + // hint route really does reach an ordinary packages test file — Zone rule: + // two routes to one gate is redundancy, never a bug, and neither may be + // deleted BECAUSE of the other). The negative cases are the residue: a class + // the hint route cannot reach in principle, with live tracked specimens. + const XPKG = 'check:cross-package-test-inputs'; + const xpkgEntry = discoverFamilies().byCheck.get(XPKG); + // Live specimens, one per residue reason. If either file is ever deleted or + // renamed, re-point the case at another member of its class — and if a class + // ever EMPTIES, that is the measurement to redo, not a case to drop. + const OUTSIDE_PACKAGES = 'examples/app-crm/test/smoke.test.ts'; // not under packages/** + const TSX_TEST = 'packages/client-react/src/realtime-hooks.test.tsx'; // not *.ts + const APPS_TEST = 'apps/docs/src/x.test.ts'; // no tracked member today + t('the gate is discovered with hints at all, so these cases are not vacuous', (xpkgEntry?.hints ?? []).length > 0); + t('both residue specimens are real tracked files, so the negatives are live rather than a pair of matching strings', + existsSync(join(ROOT, OUTSIDE_PACKAGES)) && existsSync(join(ROOT, TSX_TEST))); + t('the hint route really does reach an ordinary packages test file — the redundancy #12300 recovered is real', + covers(xpkgEntry.hints, 'packages/spec/src/x.test.ts')); + t('but no hint of this gate reaches a test file outside packages/**', !covers(xpkgEntry.hints, OUTSIDE_PACKAGES)); + t('nor a .tsx test file inside it', !covers(xpkgEntry.hints, TSX_TEST)); + t('nor one under apps/**, the class with no tracked member to lose', !covers(xpkgEntry.hints, APPS_TEST)); + // The entry itself, anchored on both sides of the rendered name the way the + // STALE cases above are: a bare substring test stays green if some other + // gate's `why` ever quotes this gate's name. + t('the KIND names the gate for every one of them — delete the entry and this reddens', + [OUTSIDE_PACKAGES, TSX_TEST, APPS_TEST].every((p) => + changeKindLines([p], (n) => n).some((l) => l.includes(`- ${XPKG} —`)))); + // The fragility half: the covering hint is INHERITED from the declaration + // table this gate imports (one package's declared turbo `inputs` glob), not + // declared by the gate as its own population. `hintOrigin` carries exactly + // that provenance, and it is what the output prints as `gate source via …`. + const xpkgCovering = xpkgEntry.hints.find((h) => hintCovers(h, 'packages/spec/src/x.test.ts')); + t('and that covering hint is inherited from a module the gate imports, not a population the gate declares', + Boolean(xpkgEntry.hintOrigin?.get(xpkgCovering))); + // The class-level claim, against the real corpus rather than two specimens: + // while ANY tracked test file is unreachable by every hint this gate has, the + // entry's deletion criterion is unmet. The day this reddens, re-measure the + // criterion and either retire the entry with these cases or re-point them. + const xpkgResidue = trackedFiles().filter((f) => isTestFilePath(f) && !covers(xpkgEntry.hints, f)); + t(`the tree still holds test files no hint of this gate reaches (${xpkgResidue.length}), so the entry is not redundant`, + xpkgResidue.length > 0); + // ── The check-family coverage guard (#9187) ─────────────────────────────── // // `docs-drift-check.yml` declared a `paths:` filter and ran a real self-test From 355a742747a215146d3d3a92303675a1b43f1b91 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 17:57:59 +0000 Subject: [PATCH 2/2] docs(pm): re-measure the census against the merged tree Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01UjM2ia8Av1v5NqfqQEQmC6 --- scripts/pm/dispatch-gates.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index 7f1091a348..09583e4466 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -2748,9 +2748,9 @@ export function reachesMetadataFormModule(path, modulePaths) { * * ⚠ "A literal naming their POPULATION" is the whole of that criterion, * and one gate in this kind now fails it while READING as satisfied. - * Measured on this tree (#11199, the day PR #12300 landed): of the 2771 + * Measured on this tree (#11199, the day PR #12300 landed): of the 2773 * tracked test files, the hint route names `check:cross-package-test- - * inputs` for 2758 of them — 99.5%, against 0–3.3% for its five siblings + * inputs` for 2760 of them — 99.5%, against 0–3.3% for its five siblings * in this same kind — because #12300 taught `hintCovers` to read a glob in * a non-final segment and the deep `packages` glob for TypeScript files * came back to life. (That glob is not spelled here: its own wildcard