|
76 | 76 | * the judged population, has the strictest one. Below any floor the gate |
77 | 77 | * refuses (`exit 2`) instead of passing. |
78 | 78 | * |
| 79 | + * ## The provenance of a floor, and how to reproduce it |
| 80 | + * |
| 81 | + * `MEASURED` is a claim about ONE named commit -- `MEASURED.ref` -- and never |
| 82 | + * about `main`. It is the census the floors under it were derived from, not a |
| 83 | + * statement about the tree you are running on. |
| 84 | + * |
| 85 | + * ⚠️ `MEASURED.ref` is this gate's PR BASE, and this gate DOES NOT EXIST in |
| 86 | + * that tree: the census was taken on the PR branch, and the base is the sha the |
| 87 | + * branch had to record. So the obvious recipe -- check the ref out and run the |
| 88 | + * gate there -- fails with `MODULE_NOT_FOUND` (measured 2026-08-29), and the |
| 89 | + * reader who tries it learns nothing about the record. Reproduce it by running |
| 90 | + * TODAY's instrument AGAINST that tree instead. `sweep` is exported and takes a |
| 91 | + * root for exactly this: |
| 92 | + * |
| 93 | + * git worktree add --detach ../os-keyed-provenance "$REF" # $REF = MEASURED.ref |
| 94 | + * node --input-type=module -e "import('./scripts/check-keyed-text-bounds.mjs') |
| 95 | + * .then((m) => console.log(m.sweep('../os-keyed-provenance').counts))" |
| 96 | + * |
| 97 | + * All five counts are source-only, so where the tree is available the |
| 98 | + * re-derivation is cheap: no install and no build. Re-derived at `MEASURED.ref` |
| 99 | + * on 2026-08-29: 113/118/255/594/151 -- exactly the record, which is the |
| 100 | + * measurement that rules out "the original count was written wrong". |
| 101 | + * |
| 102 | + * ⚠️ A SHALLOW clone cannot do this at all -- `MEASURED.ref` predates the |
| 103 | + * default checkout window, so the commit is simply absent. That is why the |
| 104 | + * reconciliation below is a PRINTED comparison and not a computed assertion: |
| 105 | + * the ref's tree is not reliably on disk. And note what a computed assertion |
| 106 | + * would be worth even where it works -- a commit's tree is IMMUTABLE, so |
| 107 | + * re-deriving the record at its ref can never go red. The only thing that moves |
| 108 | + * is today's tree, and comparing today's tree to the record is the equality |
| 109 | + * ruled out below. |
| 110 | + * |
| 111 | + * ## Why no equality against the tree, and why no band either |
| 112 | + * |
| 113 | + * An equality reds on every legitimate move. This population shrinks for good |
| 114 | + * reasons as readily as it grows: retiring an object, folding two objects into |
| 115 | + * one, or dropping an index each decrement it with nothing wrong. A band around |
| 116 | + * the record is the next thing to reach for, and it fails a derivation rather |
| 117 | + * than a taste test. Two reasons, either one sufficient: |
| 118 | + * |
| 119 | + * 1. The band already exists and is called the FLOOR. `MIN_FILES` IS |
| 120 | + * `MEASURED.files` minus the headroom this gate declared. A second, |
| 121 | + * narrower band would be a second tolerance for one fact, and its width |
| 122 | + * would be invented rather than measured. |
| 123 | + * 2. No width measures anything. Measured 2026-08-29, the three gates in |
| 124 | + * `scripts/` carrying a record of this shape had drifted -5, -1 and +28 |
| 125 | + * from theirs, in both directions, within days of landing. A band narrow |
| 126 | + * enough to notice this file's -1 reds on the +28 next door; one wide |
| 127 | + * enough to survive the +28 cannot see a -1. |
| 128 | + * |
| 129 | + * So the repair is not enforcement. What was missing is that a GREEN run never |
| 130 | + * showed the reader the two censuses side by side, so the record could stop |
| 131 | + * describing the tree with nothing, anywhere, saying so. `provenanceLine` |
| 132 | + * prints both on every pass: the drift is a fact in the log, not a discovery. |
| 133 | + * |
79 | 134 | * ## "text-family" is READ OFF THE EMITTER, not retyped here |
80 | 135 | * |
81 | 136 | * The three pins this gate supersedes each hard-coded |
@@ -236,13 +291,29 @@ const ALLOWLIST = [ |
236 | 291 | const ALLOWLIST_KINDS = new Set(['unboundable', 'pending']); |
237 | 292 |
|
238 | 293 | // --------------------------------------------------------------------------- |
239 | | -// Vacuity floors. Each is set just under the value measured on `fa5d137ab0`, |
240 | | -// so a walk or a matcher that collapses REFUSES instead of reporting the empty |
241 | | -// finding set that success also looks like. |
242 | | - |
243 | | -const MEASURED = { |
244 | | - files: 113, objects: 118, indexEntries: 255, textFields: 594, keyedTextColumns: 151, |
245 | | -}; |
| 294 | +// Vacuity floors, and the provenance of the census they were derived from -- |
| 295 | +// the header is the authority on how to reproduce it and on why it is recorded |
| 296 | +// rather than enforced. Each floor sits just under its measured value, so a |
| 297 | +// walk or a matcher that collapses REFUSES instead of reporting the empty |
| 298 | +// finding set that success also looks like. The ref lives INSIDE the record, so |
| 299 | +// a count and the tree it came from cannot be edited apart, and every site that |
| 300 | +// quotes either interpolates from here instead of restating it. Re-measuring UP |
| 301 | +// is free; LOWERING a floor to make a run pass is the move this block exists to |
| 302 | +// make visible in a diff. |
| 303 | + |
| 304 | +const MEASURED = Object.freeze({ |
| 305 | + // The commit this census describes. ⚠️ It is this gate's PR BASE, not a tree |
| 306 | + // the gate ever ran in -- see the header for the recipe that actually |
| 307 | + // reproduces it, and for why that distinction is not a detail. Immutable, so |
| 308 | + // the record stays reproducible forever even as `main` moves away from it. |
| 309 | + // ⛔ Never repoint it without re-running all five counts against the new ref. |
| 310 | + ref: 'fa5d137ab0', |
| 311 | + files: 113, |
| 312 | + objects: 118, |
| 313 | + indexEntries: 255, |
| 314 | + textFields: 594, |
| 315 | + keyedTextColumns: 151, |
| 316 | +}); |
246 | 317 | const MIN_FILES = 105; |
247 | 318 | const MIN_OBJECTS = 110; |
248 | 319 | const MIN_INDEX_ENTRIES = 235; |
@@ -854,11 +925,41 @@ function floorProblem(counts) { |
854 | 925 | for (const [key, min, what, why] of FLOORS) { |
855 | 926 | const got = counts?.[key] ?? 0; |
856 | 927 | if (got >= min) continue; |
857 | | - return `discovered only ${got} ${what}, below the floor of ${min} (measured ${MEASURED[key]} on fa5d137ab0).\n${why}`; |
| 928 | + return `discovered only ${got} ${what}, below the floor of ${min} (measured ${MEASURED[key]} on ${MEASURED.ref}).\n${why}`; |
858 | 929 | } |
859 | 930 | return null; |
860 | 931 | } |
861 | 932 |
|
| 933 | +/** |
| 934 | + * The provenance footer for a PASSING run: the census this run read, the floors |
| 935 | + * it cleared, the census those floors were derived from, and the ref that |
| 936 | + * census belongs to -- side by side. |
| 937 | + * |
| 938 | + * This is the whole repair. The floors are inequalities on purpose, so no run |
| 939 | + * can ever contradict the record; without this line the record could stop |
| 940 | + * describing the tree and every green log would look identical either way. The |
| 941 | + * delta is reported as INFORMATION and never as a verdict: this population |
| 942 | + * moves in both directions for good reasons (see the header), and only the |
| 943 | + * floors decide anything. |
| 944 | + * |
| 945 | + * Pure, so `--self-test` drives it with no tree. |
| 946 | + * |
| 947 | + * @param {{files?: number, objects?: number, indexEntries?: number, textFields?: number, keyedTextColumns?: number}} counts |
| 948 | + * @returns {string} |
| 949 | + */ |
| 950 | +export function provenanceLine(counts) { |
| 951 | + const got = FLOORS.map(([key]) => counts?.[key] ?? 0); |
| 952 | + const rec = FLOORS.map(([key]) => MEASURED[key]); |
| 953 | + const floors = FLOORS.map(([, min]) => min); |
| 954 | + const delta = got.map((g, i) => (g === rec[i] ? '=' : `${g > rec[i] ? '+' : ''}${g - rec[i]}`)); |
| 955 | + const names = FLOORS.map(([key]) => key).join('/'); |
| 956 | + return ` provenance — ${names}: this run ${got.join('/')}` |
| 957 | + + ` · floors ${floors.join('/')} · derived from ${rec.join('/')} measured on ${MEASURED.ref}` |
| 958 | + + ` (${delta.join('/')} vs the record).\n` |
| 959 | + + ' ⚠ The delta is information, not a verdict — this population grows AND shrinks for good' |
| 960 | + + ' reasons, and only the floors decide. Reproduce the record: see this file\'s header.'; |
| 961 | +} |
| 962 | + |
862 | 963 | function familyProblem(family) { |
863 | 964 | const got = [...family].sort().join(', '); |
864 | 965 | const want = [...EXPECTED_TEXT_FAMILY].sort().join(', '); |
@@ -948,6 +1049,7 @@ function main() { |
948 | 1049 | + `Allowlist: ${pending} pending, ${unboundable} unboundable, all rows still real. ` |
949 | 1050 | + `${unclassified} unclassified field(s), none of them keyed.`, |
950 | 1051 | ); |
| 1052 | + console.log(provenanceLine(result.counts)); |
951 | 1053 | return 0; |
952 | 1054 | } |
953 | 1055 |
|
@@ -1237,7 +1339,62 @@ export function selfTest() { |
1237 | 1339 | floorProblem({ files: 999, objects: 999, indexEntries: 0, textFields: 999, keyedTextColumns: 999 }) !== null); |
1238 | 1340 | t('a tree whose keyed-text INTERSECTION collapses trips its own floor', |
1239 | 1341 | floorProblem({ files: 999, objects: 999, indexEntries: 999, textFields: 999, keyedTextColumns: 0 }) !== null); |
1240 | | - t('the floors pass at the values measured on fa5d137ab0', floorProblem(MEASURED) === null); |
| 1342 | + t('the floors pass at the values in the record', floorProblem(MEASURED) === null); |
| 1343 | + t('every floor sits at or below the value it was measured from -- a floor ABOVE its own ' |
| 1344 | + + 'measurement reds every real run, the opposite failure and just as invisible in review', |
| 1345 | + FLOORS.every(([key, min]) => min <= MEASURED[key]), |
| 1346 | + JSON.stringify(FLOORS.map(([key, min]) => `${key}: ${min} vs ${MEASURED[key]}`))); |
| 1347 | + |
| 1348 | + // ── provenance: the record must stay reproducible, and visibly so ────── |
| 1349 | + // |
| 1350 | + // ⛔ None of these can red on a tree that legitimately moved -- that is the |
| 1351 | + // point, and an equality here is the thing the header rules out. They red |
| 1352 | + // when the RECORD stops being a self-contained, reproducible claim: a ref |
| 1353 | + // that is not a ref, a quotation that restated the ref instead of reading |
| 1354 | + // it, or a pass line that stopped showing the reader both censuses. |
| 1355 | + t('PROVENANCE — the record carries the ref it was measured on, inside the frozen record', |
| 1356 | + typeof MEASURED.ref === 'string' && /^[0-9a-f]{7,40}$/.test(MEASURED.ref) && Object.isFrozen(MEASURED), |
| 1357 | + JSON.stringify(MEASURED.ref)); |
| 1358 | + t('PROVENANCE — the refusal names the ref and the measurement', |
| 1359 | + (floorProblem({ ...MEASURED, files: 0 }) ?? '').includes(MEASURED.ref), |
| 1360 | + JSON.stringify(floorProblem({ ...MEASURED, files: 0 }))); |
| 1361 | + // ⚠️ The case above is NOT sufficient, and an ablation proved it: replacing |
| 1362 | + // `${MEASURED.ref}` in the refusal with the same sha typed out by hand |
| 1363 | + // leaves the OUTPUT identical, so an assertion over the output stays green |
| 1364 | + // while the ref and the count have become editable apart -- which is the |
| 1365 | + // whole defect this file was repaired for. The only thing separating |
| 1366 | + // "interpolated from the record" from "restated and currently agreeing" is |
| 1367 | + // that the literal occurs exactly ONCE in the CODE: inside the record. |
| 1368 | + // |
| 1369 | + // Comments are masked first, with this tree's own masker, because PROSE |
| 1370 | + // naming the ref is fine and sometimes necessary -- the header explains how |
| 1371 | + // to reproduce the census, and a sibling docblock may date a different |
| 1372 | + // claim to the same commit. What may never happen twice is a ref the |
| 1373 | + // MACHINE reads, because that is the pair that can drift apart. |
| 1374 | + const ownSource = readFileSync(fileURLToPath(import.meta.url), 'utf8'); |
| 1375 | + const ownCode = blank(ownSource, scanSource(ownSource).comment); |
| 1376 | + t('PROVENANCE — the ref literal appears exactly ONCE in the CODE: inside the record. ' |
| 1377 | + + 'Every other site interpolates it, so a count and its tree cannot be edited apart', |
| 1378 | + ownCode.split(MEASURED.ref).length - 1 === 1, |
| 1379 | + `${ownCode.split(MEASURED.ref).length - 1} code occurrence(s) of the ref literal`); |
| 1380 | + const provDrifted = provenanceLine({ |
| 1381 | + files: 112, objects: 117, indexEntries: 251, textFields: 589, keyedTextColumns: 148, |
| 1382 | + }); |
| 1383 | + t('PROVENANCE — a passing run shows the census it read AND the census the floors came from', |
| 1384 | + provDrifted.includes('112/117/251/589/148') |
| 1385 | + && provDrifted.includes(FLOORS.map(([key]) => MEASURED[key]).join('/')) |
| 1386 | + && provDrifted.includes(FLOORS.map(([, min]) => min).join('/')) |
| 1387 | + && provDrifted.includes(MEASURED.ref), provDrifted); |
| 1388 | + t('PROVENANCE — drift is reported in BOTH directions, and equality says so', |
| 1389 | + provDrifted.includes('-1/-1/-4/-5/-3') |
| 1390 | + && provenanceLine(MEASURED).includes('=/=/=/=/=') |
| 1391 | + && provenanceLine({ ...MEASURED, files: MEASURED.files + 28 }).includes('+28/'), |
| 1392 | + provDrifted); |
| 1393 | + t('PROVENANCE — the delta is marked as information, never as a verdict', |
| 1394 | + /not a verdict/i.test(provDrifted) && !/✗|REFUS/.test(provDrifted), provDrifted); |
| 1395 | + t('PROVENANCE — the PASS path actually prints it (a line nothing calls is the defect above)', |
| 1396 | + readFileSync(fileURLToPath(import.meta.url), 'utf8').includes(`console.log(${'provenanceLine'}(result.counts))`), |
| 1397 | + 'the pass path in main() no longer calls provenanceLine — the record would stop being reconciled in the log'); |
1241 | 1398 |
|
1242 | 1399 | // ── the watch-hint declaration vs the repo-wide walk ───────────────── |
1243 | 1400 | const outsideHints = run({ 'tools/stray.object.ts': objectFile(`{ name: 'o', fields: { c: Field.text({ maxLength: 5 }) }, indexes: [{ fields: ['c'] }] }`) }); |
|
0 commit comments