From 01214203fc674f23df2bcd234cb927a160cc1f61 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 19 Sep 2026 05:39:35 +0000 Subject: [PATCH] refactor(scripts): the population-floor mechanism is spelled once, in one module The row-walk, the refusal wording and the provenance line lived hand-typed in three gates under two names. The refusal text is what an operator acts on, so three copies are three places for it to drift -- invisibly, because each gate's --self-test asserts only its own text. scripts/population-floor.mjs now owns the walk and both formats; each gate keeps its own row table, because every `why` is a claim about that gate's internals. check-dual-build-cjs-loads' older `floorProblem` / `provenanceLine` spelling is retired, so the mechanism is spelled one way in all three. Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk Co-authored-by: Claude --- scripts/check-dual-build-cjs-loads.mjs | 144 +++++++++--------- scripts/check-engine-double-contract.mjs | 110 +++++--------- scripts/check-type-check-coverage.mjs | 100 ++++--------- scripts/population-floor.mjs | 177 +++++++++++++++++++++++ 4 files changed, 308 insertions(+), 223 deletions(-) create mode 100644 scripts/population-floor.mjs diff --git a/scripts/check-dual-build-cjs-loads.mjs b/scripts/check-dual-build-cjs-loads.mjs index 172308deaea..99ca76cf032 100644 --- a/scripts/check-dual-build-cjs-loads.mjs +++ b/scripts/check-dual-build-cjs-loads.mjs @@ -190,7 +190,8 @@ * * So the repair is not enforcement. What was missing is that a GREEN run never * showed the reader the two numbers side by side, so the record could stop - * describing the tree with nothing, anywhere, saying so. `provenanceLine` + * describing the tree with nothing, anywhere, saying so. + * `populationProvenanceLine` * prints both on every pass: the drift is a fact in the log now, not a * discovery. * @@ -218,6 +219,7 @@ import { dirname, join, relative, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { isEntrypoint } from './invoked-as.mjs'; +import { definePopulationFloor } from './population-floor.mjs'; // ── The self-test's own battery roster and floor (#13489) ────────────────── // @@ -519,67 +521,55 @@ const MIN_TYPED_JUDGED = 88; const MEASURED_TYPED = Object.freeze({ ref: '196612a313', typedJudged: 102 }); /** - * The first floor a run falls below, as a refusal message -- or `null` when - * every count clears. Pure, so `--self-test` drives every floor with no tree. + * The vacuity floors and the provenance line, over the row table THIS gate + * declares. The row-walk, the refusal wording and the provenance formatting are + * shared with the two other gates that carry the same mechanism + * (`scripts/population-floor.mjs`); the rows stay HERE, because each `why` is a + * claim about this gate's internals and is true of nothing else. * - * @param {{entries?: number, packages?: number, cjsFiles?: number, probes?: number}} counts - * @returns {string | null} - */ -export function floorProblem(counts) { - const rows = [ - [counts?.entries ?? 0, MIN_ENTRIES, MEASURED.entries, 'published `require` entry point(s)', - 'The manifest walk or the `exports` resolver broke. With no entries nothing is required, nothing is parsed, and the gate prints what a clean tree prints.', - MEASURED.ref], - [counts?.packages ?? 0, MIN_PACKAGES, MEASURED.packages, 'publishable package(s)', - 'Entries were found but collapsed onto a fraction of the tree — the walk is reading part of `packages/`, not the whole of it.', - MEASURED.ref], - [counts?.cjsFiles ?? 0, MIN_CJS_FILES, MEASURED.cjsFiles, 'emitted CommonJS file(s)', - 'This is the PARSES population. `commonJsFilesUnder` matched (almost) nothing, so `node --check` ran over an empty set and every byte we emit went unread.', - MEASURED.ref], - [counts?.probes ?? 0, MIN_PROBES, MEASURED.probes, 'cross-format behaviour probe(s) run', - 'AGREES is the invariant loading alone cannot give you, and an empty probe table satisfies it vacuously.', - MEASURED.ref], - [counts?.typedJudged ?? 0, MIN_TYPED_JUDGED, MEASURED_TYPED.typedJudged, 'require entry point(s) JUDGED by TYPED', - 'This is the TYPED population — entries reached and answered, clean or not. It does not move when packages are defective, only when the row loop stops asking, so a fall here means TYPED went silent rather than that the tree got worse.', - MEASURED_TYPED.ref], - ]; - for (const [got, min, measured, what, why, at] of rows) { - if (got >= min) continue; - return `measured only ${got} ${what}, below the floor of ${min} (${measured} on ${at}).\n` - + ` ${why}\n` - + ' ⛔ NOT a pass: nothing, or nearly nothing, was read.'; - } - return null; -} - -/** - * The provenance footer for a PASSING run: the census this run read, the floors - * it cleared, the census those floors were derived from, and the ref that - * census belongs to -- side by side. + * This file is the PRECEDENT the other two were copied from, and it carried the + * mechanism under the older name `floorProblem` / `provenanceLine`. The names + * here are now the shared spelling, so the mechanism is spelled ONE way in all + * three gates -- which is the whole point: the refusal text is what an operator + * acts on, and three hand-typed copies of it are three places for it to drift. * - * This is the whole repair. The floors are inequalities on purpose, so no run - * can ever contradict the record; without this line the record could stop - * describing the tree and every green log would look identical either way. The - * delta is reported as INFORMATION and never as a verdict: this population - * moves in both directions for good reasons (see the header), and only the - * floors decide anything. + * ⛔ `typedJudged` has a floor but NO provenance column. Its number comes from a + * SECOND census (`MEASURED_TYPED`), taken on a different commit, and a + * one-ref provenance line cannot carry two refs without lying about one of + * them. The row itself names its own ref through `at`, which is where the + * refusal quotes it from. * - * Pure, so `--self-test` drives it with no tree. + * Exported, unlike the two other gates' copies: this file already guards its + * dispatch with `isEntrypoint`, so `check:entry-guard`'s "exports a binding AND + * runs on import" rule does not reach it. * - * @param {{entries?: number, packages?: number, cjsFiles?: number, probes?: number}} counts - * @returns {string} + * @type {{populationFloorProblem: (counts?: object) => string | null, + * populationProvenanceLine: (counts?: object) => string}} */ -export function provenanceLine(counts) { - const got = [counts?.entries ?? 0, counts?.packages ?? 0, counts?.cjsFiles ?? 0, counts?.probes ?? 0]; - const rec = [MEASURED.entries, MEASURED.packages, MEASURED.cjsFiles, MEASURED.probes]; - const floors = [MIN_ENTRIES, MIN_PACKAGES, MIN_CJS_FILES, MIN_PROBES]; - const delta = got.map((g, i) => (g === rec[i] ? '=' : `${g > rec[i] ? '+' : ''}${g - rec[i]}`)); - return ` provenance — entries/packages/cjsFiles/probes: this run ${got.join('/')}` - + ` · floors ${floors.join('/')} · derived from ${rec.join('/')} measured on ${MEASURED.ref}` - + ` (${delta.join('/')} vs the record).\n` - + ' ⚠ The delta is information, not a verdict — this population grows AND shrinks for good' - + ' reasons, and only the floors decide. Reproduce the record: see this file\'s header.'; -} +const populationFloor = definePopulationFloor({ + ref: MEASURED.ref, + provenance: ['entries', 'packages', 'cjsFiles', 'probes'], + reproduce: 'Reproduce the record: see this file\'s header.', + rows: [ + { key: 'entries', min: MIN_ENTRIES, measured: MEASURED.entries, + what: 'published `require` entry point(s)', + why: 'The manifest walk or the `exports` resolver broke. With no entries nothing is required, nothing is parsed, and the gate prints what a clean tree prints.' }, + { key: 'packages', min: MIN_PACKAGES, measured: MEASURED.packages, + what: 'publishable package(s)', + why: 'Entries were found but collapsed onto a fraction of the tree — the walk is reading part of `packages/`, not the whole of it.' }, + { key: 'cjsFiles', min: MIN_CJS_FILES, measured: MEASURED.cjsFiles, + what: 'emitted CommonJS file(s)', + why: 'This is the PARSES population. `commonJsFilesUnder` matched (almost) nothing, so `node --check` ran over an empty set and every byte we emit went unread.' }, + { key: 'probes', min: MIN_PROBES, measured: MEASURED.probes, + what: 'cross-format behaviour probe(s) run', + why: 'AGREES is the invariant loading alone cannot give you, and an empty probe table satisfies it vacuously.' }, + { key: 'typedJudged', min: MIN_TYPED_JUDGED, measured: MEASURED_TYPED.typedJudged, at: MEASURED_TYPED.ref, + what: 'require entry point(s) JUDGED by TYPED', + why: 'This is the TYPED population — entries reached and answered, clean or not. It does not move when packages are defective, only when the row loop stops asking, so a fall here means TYPED went silent rather than that the tree got worse.' }, + ], +}); +export const populationFloorProblem = populationFloor.populationFloorProblem; +export const populationProvenanceLine = populationFloor.populationProvenanceLine; /** * Ledger rows naming an id the discovered population does not contain. Pure. @@ -1133,7 +1123,7 @@ async function main(argv) { // ⛔ Before any verdict: a run that read (almost) nothing must refuse, not // report the clean tree. Ordered after the prerequisite check so an unbuilt // tree still answers 3 — "nothing was measured" has its own code. - const floor = floorProblem({ + const floor = populationFloorProblem({ entries: rows.length, packages: new Set(rows.map((r) => r.pkg)).size, cjsFiles: cjsFileCount, @@ -1167,7 +1157,7 @@ async function main(argv) { ); for (const h of ledgerHits) console.log(` · declared: ${h}`); for (const h of typedExempt) console.log(` · declared UNREACHABLE declaration: ${h}`); - console.log(provenanceLine({ + console.log(populationProvenanceLine({ entries: rows.length, packages: new Set(rows.map((r) => r.pkg)).size, cjsFiles: cjsFileCount, @@ -1486,25 +1476,25 @@ export async function selfTest() { // real run, which is the opposite failure and just as invisible in review. battery('the vacuity floors, each driven to zero'); const full = { entries: MEASURED.entries, packages: MEASURED.packages, cjsFiles: MEASURED.cjsFiles, probes: MEASURED.probes, typedJudged: MEASURED_TYPED.typedJudged }; - t('FLOOR — the values in the records clear every floor', floorProblem(full) === null, JSON.stringify(floorProblem(full))); - t('FLOOR — a dead manifest walk refuses', floorProblem({ ...full, entries: 0 }) !== null); - t('FLOOR — entries collapsed onto too few packages refuses', floorProblem({ ...full, packages: 0 }) !== null); - t('FLOOR — a dead CommonJS collector refuses (PARSES over an empty set)', floorProblem({ ...full, cjsFiles: 0 }) !== null); - t('FLOOR — an emptied probe table refuses (AGREES satisfied vacuously)', floorProblem({ ...full, probes: 0 }) !== null); - t('FLOOR — a dead types resolver refuses (TYPED judged nothing)', floorProblem({ ...full, typedJudged: 0 }) !== null); + t('FLOOR — the values in the records clear every floor', populationFloorProblem(full) === null, JSON.stringify(populationFloorProblem(full))); + t('FLOOR — a dead manifest walk refuses', populationFloorProblem({ ...full, entries: 0 }) !== null); + t('FLOOR — entries collapsed onto too few packages refuses', populationFloorProblem({ ...full, packages: 0 }) !== null); + t('FLOOR — a dead CommonJS collector refuses (PARSES over an empty set)', populationFloorProblem({ ...full, cjsFiles: 0 }) !== null); + t('FLOOR — an emptied probe table refuses (AGREES satisfied vacuously)', populationFloorProblem({ ...full, probes: 0 }) !== null); + t('FLOOR — a dead types resolver refuses (TYPED judged nothing)', populationFloorProblem({ ...full, typedJudged: 0 }) !== null); t('FLOOR — the TYPED refusal cites the tree ITS number came from, not the older one', - /\(102 on 196612a313\)/.test(floorProblem({ ...full, typedJudged: 0 }) ?? ''), JSON.stringify(floorProblem({ ...full, typedJudged: 0 }))); + /\(102 on 196612a313\)/.test(populationFloorProblem({ ...full, typedJudged: 0 }) ?? ''), JSON.stringify(populationFloorProblem({ ...full, typedJudged: 0 }))); // ⛔ The measured regression the floor must NOT produce: a tree where every // one of the 35 defective entries is judged and reported still clears it, // because judged does not fall when clean does. With the floor on the clean // count this returned a refusal and the 35 findings were never printed. t('FLOOR — a tree FULL of TYPED findings still reports them, never refuses', - floorProblem({ ...full, typedJudged: MEASURED_TYPED.typedJudged }) === null); - t('FLOOR — a missing count is zero, not "unmeasured but fine"', floorProblem({}) !== null); + populationFloorProblem({ ...full, typedJudged: MEASURED_TYPED.typedJudged }) === null); + t('FLOOR — a missing count is zero, not "unmeasured but fine"', populationFloorProblem({}) !== null); t('FLOOR — the refusal names the count, the floor and the measurement', new RegExp(`measured only 0 .* below the floor of \\d+ \\(${MEASURED.cjsFiles} on ${MEASURED.ref}\\)`, 's') - .test(floorProblem({ ...full, cjsFiles: 0 }) ?? ''), - JSON.stringify(floorProblem({ ...full, cjsFiles: 0 }))); + .test(populationFloorProblem({ ...full, cjsFiles: 0 }) ?? ''), + JSON.stringify(populationFloorProblem({ ...full, cjsFiles: 0 }))); t('FLOOR — every floor sits at or below the value it was measured from', MIN_ENTRIES <= MEASURED.entries && MIN_PACKAGES <= MEASURED.packages && MIN_CJS_FILES <= MEASURED.cjsFiles && MIN_PROBES <= MEASURED.probes @@ -1525,9 +1515,9 @@ export async function selfTest() { t('PROVENANCE — the record carries the ref it was measured on', typeof MEASURED.ref === 'string' && /^[0-9a-f]{7,40}$/.test(MEASURED.ref), JSON.stringify(MEASURED.ref)); t('PROVENANCE — the refusal reads the ref from the record rather than restating it', - (floorProblem({ ...full, entries: 0 }) ?? '').includes(MEASURED.ref), - JSON.stringify(floorProblem({ ...full, entries: 0 }))); - const provDrifted = provenanceLine({ entries: 102, packages: 66, cjsFiles: 610, probes: 1 }); + (populationFloorProblem({ ...full, entries: 0 }) ?? '').includes(MEASURED.ref), + JSON.stringify(populationFloorProblem({ ...full, entries: 0 }))); + const provDrifted = populationProvenanceLine({ entries: 102, packages: 66, cjsFiles: 610, probes: 1 }); t('PROVENANCE — a passing run shows the census it read AND the census the floors came from', provDrifted.includes('102/66/610/1') && provDrifted.includes(`${MEASURED.entries}/${MEASURED.packages}/${MEASURED.cjsFiles}/${MEASURED.probes}`) @@ -1535,12 +1525,12 @@ export async function selfTest() { && provDrifted.includes(MEASURED.ref), provDrifted); t('PROVENANCE — drift is reported in BOTH directions, and equality says so', provDrifted.includes('-1/-1/-3/=') - && provenanceLine({ ...full }).includes('=/=/=/=') - && provenanceLine({ ...full, entries: MEASURED.entries + 15 }).includes('+15/'), + && populationProvenanceLine({ ...full }).includes('=/=/=/=') + && populationProvenanceLine({ ...full, entries: MEASURED.entries + 15 }).includes('+15/'), provDrifted); t('PROVENANCE — the PASS path actually prints it (a line nothing calls is the defect above)', - readFileSync(fileURLToPath(import.meta.url), 'utf8').includes(`console.log(${'provenanceLine'}({`), - 'the pass path in main() no longer calls provenanceLine — the record would stop being reconciled in the log'); + readFileSync(fileURLToPath(import.meta.url), 'utf8').includes(`console.log(${'populationProvenanceLine'}({`), + 'the pass path in main() no longer calls populationProvenanceLine — the record would stop being reconciled in the log'); t('PROVENANCE — the delta is marked as information, never as a verdict', /not a verdict/i.test(provDrifted) && !/✗|REFUSES/.test(provDrifted), provDrifted); diff --git a/scripts/check-engine-double-contract.mjs b/scripts/check-engine-double-contract.mjs index eee738f3052..c28264cb060 100644 --- a/scripts/check-engine-double-contract.mjs +++ b/scripts/check-engine-double-contract.mjs @@ -323,6 +323,7 @@ import { fileURLToPath } from 'node:url'; import { requireDefaultExport } from './import-prerequisite.mjs'; const ts = await requireDefaultExport('typescript', () => import('typescript'), import.meta.url); import { parseSourceFile } from './ts-parse.mjs'; +import { definePopulationFloor } from './population-floor.mjs'; const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..'); const BASELINE_PATH = join(ROOT, 'scripts', 'engine-double-contract.baseline.json'); @@ -3069,59 +3070,53 @@ const MIN_DISCOVERED_FILES = 700; const MIN_PINNED_ROWS = 600; /** - * The first floor a run falls below, as a refusal message -- or `null` when - * every count clears. Pure, so `--self-test` drives every row with no tree. + * The POPULATION FLOORS and the provenance line, over the row table THIS gate + * declares. The row-walk, the refusal wording and the provenance formatting are + * shared with the two other gates that carry the same mechanism + * (`scripts/population-floor.mjs`); the rows stay HERE, because each `why` is a + * claim about this gate's internals and is true of nothing else. * * ⛔ Each `why` names ONLY the stage its own count measures. A row that fell * says which walk or which reader went quiet and nothing else: the other three * stages are reported by their own rows, and blaming them here would put causes * that did not occur in front of the reader. * - * @param {{testFiles?: number, productionFiles?: number, discoveredFiles?: number, pinnedRows?: number}} counts - * @returns {string | null} - * * ⛔ NOT exported, deliberately. `check:entry-guard` refuses a `scripts/**` file * that exports a binding AND runs on import -- whatever its top level does then * runs inside the importer -- and this file's top level IS its dispatch. The - * self-test lives in this same module and reaches it directly, so an export - * would buy nothing and cost that rule. (The precedent this shape is copied - * from, `check-dual-build-cjs-loads.mjs`, exports because it already guards its - * dispatch with `isEntrypoint`; retrofitting that here is a change to two large - * gates' argv handling and not this card's subject.) + * self-test lives in this same module and reaches these directly, so an export + * would buy nothing and cost that rule. The shared module is the other half of + * the same rule: it only ever exports and never runs, so importing it costs + * this file nothing. + * + * @type {{populationFloorProblem: (counts?: object) => string | null, + * populationProvenanceLine: (counts?: object) => string}} */ -function populationFloorProblem(counts) { - const rows = [ - [counts?.testFiles ?? 0, MIN_TEST_FILES, MEASURED_POPULATION.testFiles, - 'test file(s) offered by the discovery walk', - 'This is the population all three slices iterate. `walk()` swallows a readdir failure and ' +const { populationFloorProblem, populationProvenanceLine } = definePopulationFloor({ + ref: MEASURED_POPULATION.ref, + rows: [ + { key: 'testFiles', min: MIN_TEST_FILES, measured: MEASURED_POPULATION.testFiles, + what: 'test file(s) offered by the discovery walk', + why: 'This is the population all three slices iterate. `walk()` swallows a readdir failure and ' + 'returns what it has, so a scan root that stopped being readable narrows this set in ' - + 'silence and every verdict below becomes a statement about the remainder.'], - [counts?.productionFiles ?? 0, MIN_PRODUCTION_FILES, MEASURED_POPULATION.productionFiles, - 'non-test source file(s) offered by the seam walk', - 'This is the population the consumer-seam scan iterates, and it is a SEPARATE walk with a ' + + 'silence and every verdict below becomes a statement about the remainder.' }, + { key: 'productionFiles', min: MIN_PRODUCTION_FILES, measured: MEASURED_POPULATION.productionFiles, + what: 'non-test source file(s) offered by the seam walk', + why: 'This is the population the consumer-seam scan iterates, and it is a SEPARATE walk with a ' + 'separate filter -- REFUSES and SEAMS_RETAINED are statements about whatever it hands ' - + 'over. SEAMS_DISCOVERED only sees this reach zero.'], - [counts?.discoveredFiles ?? 0, MIN_DISCOVERED_FILES, MEASURED_POPULATION.discoveredFiles, - '(file, verb) pair(s) in which a double was discovered', - 'The walk offered files and the pre-filter or the parser read almost nothing in them. ' + + 'over. SEAMS_DISCOVERED only sees this reach zero.' }, + { key: 'discoveredFiles', min: MIN_DISCOVERED_FILES, measured: MEASURED_POPULATION.discoveredFiles, + what: '(file, verb) pair(s) in which a double was discovered', + why: 'The walk offered files and the pre-filter or the parser read almost nothing in them. ' + 'DISCOVERED only fires when a slice finds zero, so a reader that went quiet on most of ' - + 'the tree while still answering somewhere passes it.'], - [counts?.pinnedRows ?? 0, MIN_PINNED_ROWS, MEASURED_POPULATION.pinnedRows, - 'pinned (file, verb) row(s) in the RETAINED census', - 'Doubles were discovered and almost none of them read as pinned. That is guard recognition ' + + 'the tree while still answering somewhere passes it.' }, + { key: 'pinnedRows', min: MIN_PINNED_ROWS, measured: MEASURED_POPULATION.pinnedRows, + what: 'pinned (file, verb) row(s) in the RETAINED census', + why: 'Doubles were discovered and almost none of them read as pinned. That is guard recognition ' + 'going quiet rather than the tree getting worse -- and it is the count `--write` ' - + 'rewrites the RETAINED ledger down to, so the ledger cannot report it.'], - ]; - for (const [got, min, measured, what, why] of rows) { - if (got >= min) continue; - return `measured only ${got} ${what}, below the floor of ${min} ` - + `(${measured} on ${MEASURED_POPULATION.ref}).\n` - + ` ${why}\n` - + ' ⛔ NOT a pass: nothing, or nearly nothing, was read. This says WHICH population fell and\n' - + ' nothing about why the others stand — they are reported by their own rows.'; - } - return null; -} + + 'rewrites the RETAINED ledger down to, so the ledger cannot report it.' }, + ], +}); /** * Refuse a run whose population fell below a floor -- the ONE place this file @@ -3162,43 +3157,6 @@ function refusePopulationFloor(population, what) { process.exit(EXIT_POPULATION_REFUSED); } -/** - * The provenance footer for a PASSING run: what this run read, the floors it - * cleared, and the census those floors were derived from, side by side. - * - * The floors are inequalities on purpose, so no run can contradict the record. - * Without this line the record could stop describing the tree with nothing - * anywhere saying so, and every green log would look identical either way. The - * delta is INFORMATION, never a verdict: this population moves in both - * directions for good reasons -- a package leaving the workspace, a fake engine - * replaced by a real one -- and only the floors decide. Pure. - * - * @param {{testFiles?: number, productionFiles?: number, discoveredFiles?: number, pinnedRows?: number}} counts - * @returns {string} - * - * ⛔ NOT exported, deliberately. `check:entry-guard` refuses a `scripts/**` file - * that exports a binding AND runs on import -- whatever its top level does then - * runs inside the importer -- and this file's top level IS its dispatch. The - * self-test lives in this same module and reaches it directly, so an export - * would buy nothing and cost that rule. (The precedent this shape is copied - * from, `check-dual-build-cjs-loads.mjs`, exports because it already guards its - * dispatch with `isEntrypoint`; retrofitting that here is a change to two large - * gates' argv handling and not this card's subject.) - */ -function populationProvenanceLine(counts) { - const got = [counts?.testFiles ?? 0, counts?.productionFiles ?? 0, - counts?.discoveredFiles ?? 0, counts?.pinnedRows ?? 0]; - const rec = [MEASURED_POPULATION.testFiles, MEASURED_POPULATION.productionFiles, - MEASURED_POPULATION.discoveredFiles, MEASURED_POPULATION.pinnedRows]; - const floors = [MIN_TEST_FILES, MIN_PRODUCTION_FILES, MIN_DISCOVERED_FILES, MIN_PINNED_ROWS]; - const delta = got.map((g, i) => (g === rec[i] ? '=' : `${g > rec[i] ? '+' : ''}${g - rec[i]}`)); - return ` provenance — testFiles/productionFiles/discoveredFiles/pinnedRows: this run ${got.join('/')}` - + ` · floors ${floors.join('/')} · derived from ${rec.join('/')} measured on ${MEASURED_POPULATION.ref}` - + ` (${delta.join('/')} vs the record).\n` - + ' ⚠ The delta is information, not a verdict — this population grows AND shrinks for good' - + ' reasons, and only the floors decide.'; -} - function audit() { const baseline = readBaseline(); const errors = []; diff --git a/scripts/check-type-check-coverage.mjs b/scripts/check-type-check-coverage.mjs index 299ea1ccd7f..4974c44ebc8 100644 --- a/scripts/check-type-check-coverage.mjs +++ b/scripts/check-type-check-coverage.mjs @@ -548,6 +548,7 @@ import { SELF_TEST_CASE_COUNT as TYPECHECK_CONFIGS_CASES, selfTest as typecheckConfigsSelfTest, } from './typecheck-configs.mjs'; +import { definePopulationFloor } from './population-floor.mjs'; // Anchored to the script, not to cwd: the verdict must not depend on where the // guard was invoked from. @@ -2271,89 +2272,48 @@ const MIN_WALKED_TEST_FILES = 2800; const MIN_WALKED_SOURCE_FILES = 2000; /** - * The first floor a run falls below, as a refusal message -- or `null` when - * every count clears. Pure, so `--self-test` drives every row with no tree. + * The POPULATION FLOORS and the provenance line, over the row table THIS gate + * declares. The row-walk, the refusal wording and the provenance formatting are + * shared with the two other gates that carry the same mechanism + * (`scripts/population-floor.mjs`); the rows stay HERE, because each `why` is a + * claim about this gate's internals and is true of nothing else. * * ⛔ Each `why` names ONLY the stage its own count measures. A row that fell * says which reader went quiet and nothing else: the other rows report * themselves, and listing every way a run can collapse would put causes that * did not occur in front of the reader. * - * @param {{packages?: number, walkedTestFiles?: number, walkedSourceFiles?: number}} counts - * @returns {string | null} - * * ⛔ NOT exported, deliberately. `check:entry-guard` refuses a `scripts/**` file * that exports a binding AND runs on import -- whatever its top level does then * runs inside the importer -- and this file's top level IS its dispatch. The - * self-test lives in this same module and reaches it directly, so an export - * would buy nothing and cost that rule. (The precedent this shape is copied - * from, `check-dual-build-cjs-loads.mjs`, exports because it already guards its - * dispatch with `isEntrypoint`; retrofitting that here is a change to two large - * gates' argv handling and not this card's subject.) + * self-test lives in this same module and reaches these directly, so an export + * would buy nothing and cost that rule. The shared module is the other half of + * the same rule: it only ever exports and never runs, so importing it costs + * this file nothing. + * + * @type {{populationFloorProblem: (counts?: object) => string | null, + * populationProvenanceLine: (counts?: object) => string}} */ -function populationFloorProblem(counts) { - const rows = [ - [counts?.packages ?? 0, MIN_PACKAGES, MEASURED_POPULATION.packages, - 'workspace package(s) enumerated', - 'This is the population every per-package clause is asked about. With none of it, each ' +const { populationFloorProblem, populationProvenanceLine } = definePopulationFloor({ + ref: MEASURED_POPULATION.ref, + rows: [ + { key: 'packages', min: MIN_PACKAGES, measured: MEASURED_POPULATION.packages, + what: 'workspace package(s) enumerated', + why: 'This is the population every per-package clause is asked about. With none of it, each ' + 'clause is vacuously satisfied and the summary line reports a coverage ratio over an ' - + 'empty set.'], - [counts?.walkedTestFiles ?? 0, MIN_WALKED_TEST_FILES, MEASURED_POPULATION.walkedTestFiles, - 'test file(s) found by the per-package walk', - 'TESTS_COVERED and PINS_CHECKED are decided against what this walk hands over. A walk that ' + + 'empty set.' }, + { key: 'walkedTestFiles', min: MIN_WALKED_TEST_FILES, measured: MEASURED_POPULATION.walkedTestFiles, + what: 'test file(s) found by the per-package walk', + why: 'TESTS_COVERED and PINS_CHECKED are decided against what this walk hands over. A walk that ' + 'returns nothing hides no tests and pins nothing, which is the same silence a fully ' - + 'covered workspace produces.'], - [counts?.walkedSourceFiles ?? 0, MIN_WALKED_SOURCE_FILES, MEASURED_POPULATION.walkedSourceFiles, - 'non-test source file(s) found by the per-package walk', - 'SOURCES_COVERED is decided against this half of the same walk. With none of it every ' + + 'covered workspace produces.' }, + { key: 'walkedSourceFiles', min: MIN_WALKED_SOURCE_FILES, measured: MEASURED_POPULATION.walkedSourceFiles, + what: 'non-test source file(s) found by the per-package walk', + why: 'SOURCES_COVERED is decided against this half of the same walk. With none of it every ' + 'source directory reads as accounted for, because the clause reports the REMAINDER and ' - + 'the remainder of nothing is nothing.'], - ]; - for (const [got, min, measured, what, why] of rows) { - if (got >= min) continue; - return `measured only ${got} ${what}, below the floor of ${min} ` - + `(${measured} on ${MEASURED_POPULATION.ref}).\n` - + ` ${why}\n` - + ' ⛔ NOT a pass: nothing, or nearly nothing, was read. This says WHICH population fell and\n' - + ' nothing about why the others stand — they are reported by their own rows.'; - } - return null; -} - -/** - * The provenance footer for a PASSING run: what this run read, the floors it - * cleared, and the census those floors came from, side by side. - * - * The floors are inequalities on purpose, so no run can contradict the record. - * Without this line the record could stop describing the tree with nothing - * anywhere saying so. The delta is INFORMATION, never a verdict: this - * population moves in both directions for good reasons -- a package merged - * away, a test tree deleted -- and only the floors decide. Pure. - * - * @param {{packages?: number, walkedTestFiles?: number, walkedSourceFiles?: number}} counts - * @returns {string} - * - * ⛔ NOT exported, deliberately. `check:entry-guard` refuses a `scripts/**` file - * that exports a binding AND runs on import -- whatever its top level does then - * runs inside the importer -- and this file's top level IS its dispatch. The - * self-test lives in this same module and reaches it directly, so an export - * would buy nothing and cost that rule. (The precedent this shape is copied - * from, `check-dual-build-cjs-loads.mjs`, exports because it already guards its - * dispatch with `isEntrypoint`; retrofitting that here is a change to two large - * gates' argv handling and not this card's subject.) - */ -function populationProvenanceLine(counts) { - const got = [counts?.packages ?? 0, counts?.walkedTestFiles ?? 0, counts?.walkedSourceFiles ?? 0]; - const rec = [MEASURED_POPULATION.packages, MEASURED_POPULATION.walkedTestFiles, - MEASURED_POPULATION.walkedSourceFiles]; - const floors = [MIN_PACKAGES, MIN_WALKED_TEST_FILES, MIN_WALKED_SOURCE_FILES]; - const delta = got.map((g, i) => (g === rec[i] ? '=' : `${g > rec[i] ? '+' : ''}${g - rec[i]}`)); - return ` provenance — packages/walkedTestFiles/walkedSourceFiles: this run ${got.join('/')}` - + ` · floors ${floors.join('/')} · derived from ${rec.join('/')} measured on ${MEASURED_POPULATION.ref}` - + ` (${delta.join('/')} vs the record).\n` - + ' ⚠ The delta is information, not a verdict — this population grows AND shrinks for good' - + ' reasons, and only the floors decide.'; -} + + 'the remainder of nothing is nothing.' }, + ], +}); function workspacePackages() { // Membership comes from scripts/workspace-enumerator.mjs (#11510) — this repo's diff --git a/scripts/population-floor.mjs b/scripts/population-floor.mjs new file mode 100644 index 00000000000..c9968727312 --- /dev/null +++ b/scripts/population-floor.mjs @@ -0,0 +1,177 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * population-floor -- the ONE row-walk, the ONE refusal wording and the ONE + * provenance line the gates that floor a DERIVED population share. + * + * ## What this module is for + * + * A gate that sweeps a population and reports findings cannot tell "swept + * everything, found nothing" from "swept nothing". Both are the ABSENCE of a + * finding, and both print the line a clean tree prints. The repair is a floor + * on the derived population plus a provenance line on every green run, and + * three gates now carry it: + * + * check-engine-double-contract.mjs 4 rows walk -> parse -> pin + * check-type-check-coverage.mjs 3 rows enumeration -> walk (x2) + * check-dual-build-cjs-loads.mjs 5 rows manifests -> entries -> parse + * + * The mechanism was hand-typed in each, under two names (`floorProblem` in the + * precedent, `populationFloorProblem` in the two copied from it), and the + * REFUSAL WORDING was re-typed with it. That wording is the thing an operator + * acts on, so three hand-written copies of it are three places for it to drift + * -- invisibly, because each gate's `--self-test` asserts only its own text. + * + * ## ⛔ The row tables are NOT here, deliberately + * + * What is shared is the row-WALK and the refusal FORMATTING. The rows are not: + * the three tables have no row in common, and each `why` is a specific claim + * about that gate's internals ("`walk()` swallows a readdir failure ...", + * "SOURCES_COVERED is decided against this half of the same walk ..."). Pulling + * the tables in here would throw away each gate's own knowledge and replace it + * with prose that is true of nothing in particular. Each gate declares its own + * rows and hands them over; this module decides nothing about which populations + * matter. + * + * ## Inert on import + * + * No CLI, no top-level statement that runs anything, per `check:entry-guard`'s + * second rule -- a `scripts/**` file that exports a binding AND runs on import + * makes its whole top level run inside the importer. Two of the three gates + * keep their floor functions module-local for exactly that reason (their top + * level IS their dispatch); a module that only ever exports is what lets them + * share one implementation without either of them growing an entry guard. + * + * ## ⛔ No `--self-test` of its own, and why that is not the usual answer + * + * The shared `scripts/` modules that lint.yml runs a self-test for + * (`invoked-as`, `ts-parse`, `js-comment-mask`, `import-prerequisite`) are + * pinned at the module because the gates routing to them assert ROUTING and + * never behaviour -- nothing downstream checks that `ts-parse` still refuses. + * That is not the shape here. All three importers drive these two functions as + * pure functions over their own row tables and assert the OUTPUT: the refusal + * text, the ref it cites, which row wins, that a missing count is zero, and the + * provenance deltas in both directions -- 60+ assertions in three batteries, + * each with a pinned case floor, all run by `package.json`'s own `check:*` + * scripts. After this extraction every one of them exercises THIS code. A + * fifth `run_self_test` line would add a workflow file to the change and buy + * coverage that already exists three times over. Recorded as a considered + * omission, not an oversight. + */ + +/** + * The tail of every refusal. One wording, spelled once. + * + * It says WHICH population fell and nothing about why the others stand, + * because a message that listed every way a scan can collapse would put causes + * that did not occur in front of the reader. True of every gate here: each + * walks several rows and reports the first to fall. + */ +const REFUSAL_TAIL = ' ⛔ NOT a pass: nothing, or nearly nothing, was read. This says WHICH population fell and\n' + + ' nothing about why the others stand — they are reported by their own rows.'; + +/** + * The tail of every provenance line. The delta is INFORMATION, never a verdict: + * these populations move in both directions for good reasons -- a package + * leaving the workspace, a fake engine replaced by a real one -- and only the + * floors decide. + */ +const PROVENANCE_TAIL = ' ⚠ The delta is information, not a verdict — this population grows AND shrinks for good' + + ' reasons, and only the floors decide.'; + +/** + * One floor row: a count this gate derives, the floor it must clear, and the + * measurement the floor came from. + * + * @typedef {object} PopulationFloorRow + * @property {string} key The name of this count in the `counts` object, and + * its column name on the provenance line. + * @property {number} min The floor. ⛔ Never above `measured` -- a floor over + * its own record reds a healthy tree. + * @property {number} measured What the census recorded for this count. + * @property {string} what What the count counts, as the refusal names it. + * @property {string} why Why a run below the floor is a refusal and not a + * pass -- a claim about THIS gate's internals, which + * is why it lives in the gate and not in here. + * @property {string} [at] The ref `measured` was taken on, when this row's + * number comes from a DIFFERENT census than the + * gate's main record. Defaults to `spec.ref`. + */ + +/** + * Bind the row-walk and the provenance line to one gate's row table. + * + * Returns the two functions the gate calls, under the one spelling all three + * use, so every existing call site and every self-test case reads unchanged. + * + * @param {object} spec + * @param {string} spec.ref The commit the census was taken on. Read from the + * frozen record rather than restated, so a count and its provenance cannot be + * edited apart. + * @param {PopulationFloorRow[]} spec.rows Walked in order; the FIRST row below + * its floor is the one reported. + * @param {string[]} [spec.provenance] The keys to print on the provenance + * line, when that is not every row -- a count can be worth a floor without + * being worth a column (`check-dual-build-cjs-loads`'s `typedJudged` comes + * from a second census and would put a second ref on a one-ref line). + * Defaults to every row, in row order. + * @param {string} [spec.reproduce] One sentence appended to the provenance + * tail, pointing at where THIS gate records how to reproduce its census. + * @returns {{populationFloorProblem: (counts?: Record) => string | null, + * populationProvenanceLine: (counts?: Record) => string}} + */ +export function definePopulationFloor(spec) { + const { ref, rows } = spec; + const columns = spec.provenance ?? rows.map((row) => row.key); + const byKey = new Map(rows.map((row) => [row.key, row])); + for (const key of columns) { + if (!byKey.has(key)) { + // A provenance column naming no row would print `undefined` into the one + // line a reader checks the record against. Loud here, at module load, so + // it can never be a runtime surprise inside a refusal. + throw new Error(`population-floor: provenance column "${key}" names no floor row`); + } + } + const reproduce = spec.reproduce ? ` ${spec.reproduce}` : ''; + + /** + * The first floor a run falls below, as a refusal message -- or `null` when + * every count clears. Pure, so a `--self-test` drives every row with no tree. + * + * ⛔ A missing count is ZERO, never "unmeasured but fine": a collector that + * stopped reporting is exactly the failure the floor exists for. + */ + function populationFloorProblem(counts) { + for (const row of rows) { + const got = counts?.[row.key] ?? 0; + if (got >= row.min) continue; + return `measured only ${got} ${row.what}, below the floor of ${row.min} ` + + `(${row.measured} on ${row.at ?? ref}).\n` + + ` ${row.why}\n` + + REFUSAL_TAIL; + } + return null; + } + + /** + * The provenance footer for a PASSING run: what this run read, the floors it + * cleared, and the census those floors were derived from, side by side. + * + * The floors are inequalities on purpose, so no passing run can contradict + * the record. Without this line the record could stop describing the tree + * with nothing anywhere saying so, and every green log would look identical + * either way. Pure. + */ + function populationProvenanceLine(counts) { + const got = columns.map((key) => counts?.[key] ?? 0); + const rec = columns.map((key) => byKey.get(key).measured); + const floors = columns.map((key) => byKey.get(key).min); + const delta = got.map((g, i) => (g === rec[i] ? '=' : `${g > rec[i] ? '+' : ''}${g - rec[i]}`)); + return ` provenance — ${columns.join('/')}: this run ${got.join('/')}` + + ` · floors ${floors.join('/')} · derived from ${rec.join('/')} measured on ${ref}` + + ` (${delta.join('/')} vs the record).\n` + + PROVENANCE_TAIL + reproduce; + } + + return { populationFloorProblem, populationProvenanceLine }; +}