Skip to content

Commit 025baf1

Browse files
committed
feat(devx): the handshake column, its controls, and a LIVE completeness check (#14968)
`--json` and the human census gain a per-file `handshake` field beside `floor`, plus a per-shape summary line. One fixture per landed shape drives the recogniser in both directions, including the ACCIDENT boundary (a return value compared against a LITERAL is not a handshake), a decoy whose spellings sit in a comment and a fixture template, and a name-independence control that renames all three landed spellings out of the fixtures and requires the same verdicts. `handshakeCensusFailures` measures the census's completeness against a second opinion that shares no code with the recogniser, over the live tree rather than over fixtures -- so it lives outside `runControls()`, whose invariant is that a control failure is always the instrument and never the tree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
1 parent 2258fc9 commit 025baf1

1 file changed

Lines changed: 220 additions & 1 deletion

File tree

scripts/measure-self-test-floor.mjs

Lines changed: 220 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,69 @@ const MASKED_DEFS_GATE = [
10811081
/** What `selfTestDefs` must collect from the fixture above, and in this order. */
10821082
const MASKED_DEFS_EXPECTED = ['selfTest', 'runSelfTestTwice'];
10831083

1084+
/**
1085+
* The HANDSHAKE DECOY: both spellings the recogniser reads, standing in the two
1086+
* texts the mask blanks -- a `selfTest() !== SELF_TEST_VERDICT` comparison in a
1087+
* COMMENT, and the flag's `= true` assignment inside a fixture TEMPLATE within
1088+
* the self-test's own body. Neither is a handshake the dispatch can perform, and
1089+
* the file's real dispatch is the bare `selfTest();` that notices nothing.
1090+
*
1091+
* The two decoys are un-hidden INDEPENDENTLY below, which is what makes this a
1092+
* reading of the MASK rather than of a fixture whose spellings were never
1093+
* recognisable: strip the comment marker and the same text reads `sentinel`;
1094+
* strip the template delimiters and it reads `flag`. Masked, both are gone and
1095+
* the answer is `none`.
1096+
*/
1097+
const HANDSHAKE_DECOY_GATE = [
1098+
'#!/usr/bin/env node',
1099+
"const SELF_TEST_VERDICT = 'reached';",
1100+
'let selfTestReachedVerdict = false;',
1101+
'// if (selfTest() !== SELF_TEST_VERDICT) process.exit(1);',
1102+
'function selfTest() {',
1103+
' const FIXTURE = `',
1104+
' selfTestReachedVerdict = true;',
1105+
' `;',
1106+
" if (FIXTURE.length < 1) { console.error('the fixture text went missing'); process.exit(1); }",
1107+
" console.log('fixture self-test: 1 case passes');",
1108+
'}',
1109+
"if (process.argv.includes('--self-test')) {",
1110+
' selfTest();',
1111+
' if (!selfTestReachedVerdict) { console.error(\'no verdict\'); process.exit(1); }',
1112+
'}',
1113+
'',
1114+
].join('\n');
1115+
1116+
/** The two decoy texts, each looked up where it is hidden. */
1117+
const DECOY_SENTINEL_TEXT = 'selfTest() !== SELF_TEST_VERDICT';
1118+
const DECOY_FLAG_TEXT = 'selfTestReachedVerdict = true;';
1119+
1120+
/**
1121+
* The COLUMN-ZERO BRACE gate, reduced: an inline arrow argument whose `});`
1122+
* closes at column 0 INSIDE the self-test, ahead of the line that sets the
1123+
* handshake flag. This is the shape `scripts/check-error-code-casing.mjs`
1124+
* carries -- and `check-optional-error-sink-contract.mjs` and
1125+
* `check-org-identifier.mjs` with it. Read with a "body ends at the first `}` at
1126+
* column 0" rule, the flag assignment falls outside its own function's body, the
1127+
* carrier never crosses anything, and all three ordinary handshakes read `none`.
1128+
* `definitionSpan` counts braces over masked text instead; this fixture is why.
1129+
*/
1130+
const EARLY_BRACE_GATE = [
1131+
'#!/usr/bin/env node',
1132+
'let selfTestReachedVerdict = false;',
1133+
'const check = (fn) => fn();',
1134+
'function selfTest() {',
1135+
' check(() => {',
1136+
" console.log('fixture self-test: 1 case passes');",
1137+
'});',
1138+
' selfTestReachedVerdict = true;',
1139+
'}',
1140+
"if (process.argv.includes('--self-test')) {",
1141+
' selfTest();',
1142+
" if (!selfTestReachedVerdict) { console.error('no verdict'); process.exit(1); }",
1143+
'}',
1144+
'',
1145+
].join('\n');
1146+
10841147
/**
10851148
* The SLOW gate, reduced: a self-test that outlasts the budget it is probed
10861149
* under. It sleeps rather than spins -- a control that runs on EVERY invocation
@@ -1340,6 +1403,78 @@ export function runControls() {
13401403
`LEDGER ROW INVALID: ${file} carries a field this reader does not read (${fields.join(', ')}); a misspelled \`timeoutMs\` is not a smaller budget, it is NO budget -- the default, and the SIGTERM this field exists to end`);
13411404
}
13421405

1406+
// Instrument 3 -- WHICH handshake, one fixture per landed shape and both
1407+
// directions on each. What is at stake is the question the card was filed
1408+
// about: every handshake census in this family was a hand-written grep for one
1409+
// of three spellings, and three of them in one shift gave three wrong answers.
1410+
say(classifyHandshake(SOUND_GATE) === 'sentinel',
1411+
`HANDSHAKE CONTROL FAILED: a dispatch comparing the self-test's RETURN VALUE against a named verdict read ${classifyHandshake(SOUND_GATE)}, not sentinel`);
1412+
say(classifyHandshake(WALKING_GATE) === 'flag',
1413+
`HANDSHAKE CONTROL FAILED: a module-level flag set inside the self-test and read negated at the dispatch read ${classifyHandshake(WALKING_GATE)}, not flag`);
1414+
say(classifyHandshake(HELPER_HANDSHAKE_GATE) === 'helper',
1415+
`HANDSHAKE CONTROL FAILED: a flag handed to a refusing helper read ${classifyHandshake(HELPER_HANDSHAKE_GATE)}, not helper`);
1416+
say(classifyHandshake(HOLED_GATE) === 'none',
1417+
`HANDSHAKE CONTROL FAILED: a bare \`selfTest();\` dispatch that discards the completion read ${classifyHandshake(HOLED_GATE)}, not none`);
1418+
// ... and the pair that makes `helper` a reading of the HANDSHAKE rather than
1419+
// of the file: the SAME fixture with only the `requireReachedVerdict` call
1420+
// deleted. One line is the whole difference, and it is the handshake.
1421+
say(classifyHandshake(HELPER_HANDSHAKE_GATE_HOLED) === 'none',
1422+
`HANDSHAKE CONTROL FAILED: the helper fixture with only its handshake CALL deleted still read ${classifyHandshake(HELPER_HANDSHAKE_GATE_HOLED)}; the flag is still declared and still set, so anything but none is the NAME being read and not the mechanism`);
1423+
// The ACCIDENT boundary, which is the sharpest thing this recogniser has to
1424+
// get right: `runSelfTest() === 0` IS a comparison of the return value, and it
1425+
// is NOT a handshake -- an early return makes it `undefined === 0`, exit 1,
1426+
// ZERO bytes printed, nothing noticed. Reading it sentinel would publish the
1427+
// exact accident-versus-handshake confusion this file exists to expose.
1428+
say(classifyHandshake(ACCIDENT_GATE) === 'none',
1429+
`HANDSHAKE CONTROL FAILED: a return value compared against a LITERAL read ${classifyHandshake(ACCIDENT_GATE)}; that is the ACCIDENT shape, where a comparison against a missing return value exits non-zero having printed nothing`);
1430+
say(classifyHandshake(TERNARY_EXIT_GATE) === 'none',
1431+
`HANDSHAKE CONTROL FAILED: a bare \`process.exit(<expr> ? 0 : 1)\` dispatch read ${classifyHandshake(TERNARY_EXIT_GATE)}; nothing there compares the completion against anything`);
1432+
// ⭐ NAME-INDEPENDENCE, the direction the card is about. Every landed spelling
1433+
// is renamed out of all three fixtures -- `SELF_TEST_VERDICT`,
1434+
// `selfTestReachedVerdict`, `requireReachedVerdict` -- and the verdicts must
1435+
// not move. A recogniser keyed on those names passes every control above and
1436+
// fails all three of these; `classifyFloor` keyed on the NAME
1437+
// `SELF_TEST_BATTERIES` once and called a fixture floored with its roster gone.
1438+
const renamed = (fixture) => fixture
1439+
.replaceAll('SELF_TEST_VERDICT', 'FIXTURE_COMPLETION_TOKEN')
1440+
.replaceAll('VERDICT', 'COMPLETION_TOKEN')
1441+
.replaceAll('selfTestReachedVerdict', 'batteriesAllRan')
1442+
.replaceAll('requireReachedVerdict', 'insistTheyRan');
1443+
say(classifyHandshake(renamed(SOUND_GATE)) === 'sentinel',
1444+
'NAME-INDEPENDENCE CONTROL FAILED: the sentinel fixture stopped reading sentinel once its verdict constant was renamed; the recogniser is keyed on a NAME, which is the defect one level up');
1445+
say(classifyHandshake(renamed(WALKING_GATE)) === 'flag',
1446+
'NAME-INDEPENDENCE CONTROL FAILED: the flag fixture stopped reading flag once `selfTestReachedVerdict` was renamed; the recogniser is keyed on a NAME');
1447+
say(classifyHandshake(renamed(HELPER_HANDSHAKE_GATE)) === 'helper',
1448+
'NAME-INDEPENDENCE CONTROL FAILED: the helper fixture stopped reading helper once `requireReachedVerdict` was renamed; the recogniser is keyed on a NAME');
1449+
1450+
// The DECOY, and the fixture-validity guards without which it says nothing: a
1451+
// decoy that is not comment or literal content is testing something else.
1452+
const hsFlags = scanSource(HANDSHAKE_DECOY_GATE);
1453+
const sentinelDecoy = HANDSHAKE_DECOY_GATE.indexOf(DECOY_SENTINEL_TEXT);
1454+
const flagDecoy = HANDSHAKE_DECOY_GATE.indexOf(DECOY_FLAG_TEXT);
1455+
say(sentinelDecoy >= 0 && hsFlags.comment[sentinelDecoy] === 1,
1456+
'CONTROL FIXTURE INVALID: the sentinel decoy is not COMMENT content, so the decoy verdict below says nothing about comments being masked away');
1457+
say(flagDecoy >= 0 && hsFlags.literal[flagDecoy] === 1,
1458+
'CONTROL FIXTURE INVALID: the flag decoy is not LITERAL content, so the decoy verdict below says nothing about fixture STRINGS being masked away');
1459+
say(classifyHandshake(HANDSHAKE_DECOY_GATE) === 'none',
1460+
`HANDSHAKE DECOY CONTROL FAILED: a handshake spelled only inside a comment and a fixture template was recognised as ${classifyHandshake(HANDSHAKE_DECOY_GATE)}; a census reading raw text credits every gate that merely QUOTES the repair with having it`);
1461+
// ... and both decoys un-hidden INDEPENDENTLY, which is what makes the verdict
1462+
// above a reading of the mask rather than of two texts that were never
1463+
// recognisable in the first place.
1464+
say(classifyHandshake(HANDSHAKE_DECOY_GATE.replace('// ', '')) === 'sentinel',
1465+
'CONTROL FIXTURE INVALID: with its comment marker removed the sentinel decoy is still not recognised, so it was never a handshake spelling and the decoy verdict passes for the wrong reason');
1466+
say(classifyHandshake(HANDSHAKE_DECOY_GATE.replaceAll('`', '')) === 'flag',
1467+
'CONTROL FIXTURE INVALID: with the template delimiters removed the flag decoy is still not recognised, so it was never a handshake spelling and the decoy verdict passes for the wrong reason');
1468+
1469+
// The BODY EXTENT, on the shape that made three live files read `none`: an
1470+
// inline arrow argument closing with `});` at column 0 inside the self-test,
1471+
// ahead of the flag assignment.
1472+
const earlyBraceLines = EARLY_BRACE_GATE.split('\n');
1473+
say(earlyBraceLines.findIndex((l) => l.startsWith('}')) < earlyBraceLines.findIndex((l) => l.includes('selfTestReachedVerdict = true')),
1474+
'CONTROL FIXTURE INVALID: the fixture no longer closes a brace at column 0 AHEAD of its flag assignment, so a first-column-brace body rule would reach the assignment anyway and the verdict below tests nothing');
1475+
say(classifyHandshake(EARLY_BRACE_GATE) === 'flag',
1476+
`BODY EXTENT CONTROL FAILED: a self-test whose body contains a column-0 \`});\` read ${classifyHandshake(EARLY_BRACE_GATE)}; its flag is set INSIDE the function and the body extent is what says so -- three live files carry exactly this and read none without brace counting`);
1477+
13431478
// Instrument 1, both directions.
13441479
say(classifyFloor(maskComments(HOLED_GATE)) === 'NONE',
13451480
'POSITIVE CONTROL FAILED: a self-test deciding success by failures.length alone was not classified NONE');
@@ -1697,12 +1832,76 @@ export function population() {
16971832
if (!DISPATCH.test(code)) continue;
16981833
const file = abs.slice(ROOT.length + 1).split(sep).join('/');
16991834
if (file === CENSUS_SELF) continue;
1700-
rows.push({ file, abs, floor: classifyFloor(code), defs: selfTestDefs(src) });
1835+
rows.push({ file, abs, floor: classifyFloor(code), defs: selfTestDefs(src), handshake: classifyHandshake(src) });
17011836
}
17021837
if (rows.length === 0) throw new Error('the census found no self-test dispatch at all -- refusing rather than reporting zero');
17031838
return rows;
17041839
}
17051840

1841+
/**
1842+
* The three LANDED NAMES, kept as the census's SECOND OPINION and never as its
1843+
* answer. Each is the grep a seat actually wrote when it needed this reading.
1844+
*
1845+
* ⛔ This is not a fallback recogniser and nothing reads it for a verdict. It
1846+
* exists so the live check below can ask the completeness question the card was
1847+
* filed about -- "does the population carrying a handshake match the population
1848+
* the recogniser can see?" -- against a reading that shares NO code with the
1849+
* recogniser. Agreement is the evidence; the moment they disagree, one of the
1850+
* two is incomplete and a census printed from either is a number nobody can
1851+
* check. Measured on this base: they agree on all 181 rows, file for file.
1852+
*
1853+
* A FIFTH shape therefore lands in TWO places -- here and in the recogniser --
1854+
* and that is deliberate. A shape only the recogniser knows would silently make
1855+
* this control weaker than the thing it controls.
1856+
*/
1857+
const LANDED_HANDSHAKE_NAMES = [
1858+
/!==\s*[A-Za-z_$][\w$]*VERDICT|===\s*[A-Za-z_$][\w$]*VERDICT/,
1859+
/[A-Za-z_$][\w$]*ReachedVerdict/,
1860+
/requireReachedVerdict\s*\(/,
1861+
];
1862+
1863+
/**
1864+
* THE LIVE COMPLETENESS CHECK, over the real census rather than over fixtures.
1865+
*
1866+
* ⛔ Deliberately NOT in `runControls()`, whose whole invariant is that nothing
1867+
* there reads the repo, so a control failure is always the instrument. This one
1868+
* reads the tree, and it can fail because of what LANDED in it -- which is
1869+
* exactly what it is for. It refuses rather than degrading: a census that quietly
1870+
* reports the smaller of two disagreeing populations commits the defect this
1871+
* instrument exists to measure, one level up.
1872+
*
1873+
* The card's own words for why the assertion is not enough: "a hand-written grep
1874+
* whose completeness nobody can check". This is the check.
1875+
*/
1876+
export function handshakeCensusFailures(rows) {
1877+
const failures = [];
1878+
const seenBy = { recogniser: [], names: [] };
1879+
for (const r of rows) {
1880+
const code = maskCommentsAndLiterals(readFileSync(r.abs, 'utf8'));
1881+
if (r.handshake !== 'none') seenBy.recogniser.push(r.file);
1882+
if (LANDED_HANDSHAKE_NAMES.some((re) => re.test(code))) seenBy.names.push(r.file);
1883+
}
1884+
const byName = new Set(seenBy.names);
1885+
const byShape = new Set(seenBy.recogniser);
1886+
const recogniserOnly = seenBy.recogniser.filter((f) => !byName.has(f));
1887+
const namesOnly = seenBy.names.filter((f) => !byShape.has(f));
1888+
if (recogniserOnly.length > 0) {
1889+
failures.push(
1890+
`${recogniserOnly.length} file(s) carry a shape the recogniser reads but no LANDED SPELLING knows: `
1891+
+ `${recogniserOnly.join(', ')}. A new shape landed and the second opinion was not widened with it, `
1892+
+ 'so this census no longer has one.',
1893+
);
1894+
}
1895+
if (namesOnly.length > 0) {
1896+
failures.push(
1897+
`${namesOnly.length} file(s) carry a landed handshake spelling the recogniser reads as \`none\`: `
1898+
+ `${namesOnly.join(', ')}. The column would report those gates as having NO handshake -- the `
1899+
+ 'exact wrong reading, in the flattering direction, that #14968 was filed about.',
1900+
);
1901+
}
1902+
return failures;
1903+
}
1904+
17061905
function main() {
17071906
const controlFailures = runControls();
17081907
if (controlFailures.length > 0) {
@@ -1714,6 +1913,14 @@ function main() {
17141913
}
17151914

17161915
const rows = population();
1916+
const censusFailures = handshakeCensusFailures(rows);
1917+
if (censusFailures.length > 0) {
1918+
console.error('measure-self-test-floor: THE HANDSHAKE CENSUS IS NOT COMPLETE -- no census printed.\n');
1919+
for (const f of censusFailures) console.error(` - ${f}`);
1920+
console.error('\nThe recogniser and the landed spellings disagree about WHICH files carry a handshake.');
1921+
console.error('Widen `classifyHandshake` and `LANDED_HANDSHAKE_NAMES` together, with a control on each.\n');
1922+
process.exit(1);
1923+
}
17171924
const wantProbe = process.argv.includes('--probe');
17181925
if (wantProbe) {
17191926
for (const r of rows) {
@@ -1738,6 +1945,18 @@ function main() {
17381945
if (byFloor.ROSTER.length) console.log(` roster: ${byFloor.ROSTER.join(', ')}`);
17391946
if (byFloor.COUNT.length) console.log(` count candidates: ${byFloor.COUNT.join(', ')}`);
17401947

1948+
const byShape = { sentinel: 0, flag: 0, helper: 0, none: 0 };
1949+
for (const r of rows) byShape[r.handshake]++;
1950+
console.log('\nHandshake SHAPE -- which verdict handshake each file carries, read from CODE (#14968):');
1951+
console.log(
1952+
` ${byShape.sentinel} sentinel, ${byShape.flag} flag, ${byShape.helper} helper, `
1953+
+ `${byShape.none} none, of ${rows.length}.`,
1954+
);
1955+
console.log(' ⛔ The shapes are RECOGNISED, not legislated: the flag form exists because those');
1956+
console.log(' self-tests\' own exit codes are load-bearing, so the handshake cannot BE the');
1957+
console.log(' return value. This column answers "which spelling", never "which is right".');
1958+
for (const r of rows) console.log(` ${r.handshake.padEnd(8)} ${r.floor.padEnd(6)} ${r.file}`);
1959+
17411960
if (!wantProbe) {
17421961
console.log('\nHole 2 -- no verdict handshake: NOT MEASURED (pass --probe; it runs every self-test twice).');
17431962
return;

0 commit comments

Comments
 (0)