From 9ccd3cdc491e5892918380562ebc609c201373e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 14:12:06 +0000 Subject: [PATCH 1/2] fix(scripts): measure-self-test-floor recognises a ternary process.exit as a failure producer `classifyFloor` awards ROSTER only when a roster comparison AND a failure production both match. The failure half read five literal spellings, none of which covers `process.exit(cond ? 0 : 1)` -- so a file could carry a complete, working roster floor and still classify NONE. Measured on `scripts/check-regen-pending.mjs` before its verdict was respelled as an explicit branch; the cost is prospective, since nothing on main mis-classifies today. The criterion is now published in two halves, NAMED and TERNARY, so each can be controlled on its own. TERNARY reads a ternary exit whose failing arm is a non-zero literal, in both orders. A bare `process.exit()` stays unrecognised on purpose: over a self-test that returned early it is `process.exit(undefined)` -- exit 0, the accident shape this instrument exists to tell apart from a handshake. Six inline controls come with it, run on every invocation like the rest: a roster floor whose only failure production is the ternary reads ROSTER (with a setup control proving the fixture carries no other recognised spelling), the non-1 and inverted arms read ROSTER, a bare opaque exit reads NONE, the same fixture with the roster renamed reads NONE, and the recognised shape is pinned to the dispatch line the ACCIDENT fixture already carries. Census tallies are unchanged: 170 rows, 163 ROSTER / 6 NONE / 1 COUNT, with `--json` byte-identical before and after. No key renamed; additive. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk --- scripts/measure-self-test-floor.mjs | 86 ++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/scripts/measure-self-test-floor.mjs b/scripts/measure-self-test-floor.mjs index 00f6d4d6ee..b54b2319e0 100644 --- a/scripts/measure-self-test-floor.mjs +++ b/scripts/measure-self-test-floor.mjs @@ -111,8 +111,32 @@ const PROBE_MARKER = 'OS_SELF_TEST_FLOOR_PROBE'; /** * A FLOOR must PRODUCE A FAILURE, not merely be named. Keying on a name is the * mistake this card is about one level up, and the control below proves it. + * + * The criterion is published in two halves so a control can test each on its own: + * + * NAMED the failure is produced by a spelling that names itself -- + * `failures.push`, a literal `process.exit(1)`, `throw new Error`, + * `exitCode = 1`, `ok(false`. + * TERNARY the EXIT CODE is the verdict: `process.exit( ? 0 : 1)`, the + * same with any non-zero failing arm (`? 0 : N`), and the inverted + * `process.exit( ? 1 : 0)`. A failing arm that is a non-zero + * LITERAL produces a failure exactly as `process.exit(1)` does; it is + * an ordinary spelling, and reading only the literal form called a + * complete, working roster floor NONE (#15339) -- the roster half + * matched, the file carried no other recognised spelling, and the + * failure half missed. + * + * BOUNDARY -- a bare `process.exit()` is deliberately NOT a failure + * producer, however likely the expression is to be non-zero. That is the + * accident shape this file's header is about: over a self-test that returned + * early, `process.exit(runSelfTest())` is `process.exit(undefined)` -- exit 0, + * nothing produced, nothing noticed. Source text cannot tell what an opaque + * expression yields; a non-zero literal in the failing arm it can. */ -const PRODUCES_FAILURE = /failures\.push|process\.exit\(1\)|throw new Error|exitCode = 1|ok\(false/; +const PRODUCES_FAILURE_NAMED = /failures\.push|process\.exit\(1\)|throw new Error|exitCode = 1|ok\(false/; +const PRODUCES_FAILURE_TERNARY_EXIT = + /process\.exit\(\s*[^;]{0,200}?\?\s*(?:0\s*:\s*[1-9]\d*|[1-9]\d*\s*:\s*0)\s*\)/; +const PRODUCES_FAILURE = new RegExp(`${PRODUCES_FAILURE_NAMED.source}|${PRODUCES_FAILURE_TERNARY_EXIT.source}`); const ROSTER_COMPARISON = /(?:declaredBatteries|SELF_TEST_BATTERIES|BATTERY_FLOOR)[^;]{0,400}?(?:\.length|\.size|includes\(|has\(|!==|===|<)/s; const COUNT_COMPARISON = [ @@ -299,6 +323,41 @@ const ACCIDENT_GATE = [ '', ].join('\n'); +/** + * The ternary exit, reduced: a roster floor whose ONLY failure production is + * `process.exit( ? 0 : 1)`. It carries none of the NAMED spellings -- no + * `failures.push`, no literal `process.exit(1)`, no `throw`, no `exitCode = 1`, + * no `ok(false` -- and a control asserts that, so reading it ROSTER can only be + * the ternary being recognised and never some other half of the criterion + * sneaking in. This is the shape `scripts/check-regen-pending.mjs` carried while + * its floor was sound, its ablations all fired, and this instrument still said + * NONE (#15339). + * + * The classifier is a pure function of source text, so unlike the three fixtures + * above this one is never spawned -- it is read, not run. + */ +const TERNARY_EXIT_GATE = [ + '#!/usr/bin/env node', + 'const SELF_TEST_BATTERIES = Object.freeze({ only: 1 });', + 'function runSelfTest() {', + ' const seen = new Map();', + ' const battery = (n) => seen.set(n, (seen.get(n) ?? 0) + 1);', + " battery('only');", + ' const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);', + ' let held = declaredBatteries.length >= 1;', + ' for (const n of declaredBatteries) if ((seen.get(n) ?? 0) < SELF_TEST_BATTERIES[n]) held = false;', + " console.log('fixture self-test: floor ' + (held ? 'held' : 'shrank'));", + ' return held;', + '}', + "if (process.argv.includes('--self-test')) {", + ' process.exit(runSelfTest() ? 0 : 1);', + '}', + '', +].join('\n'); + +/** The one dispatch line of `TERNARY_EXIT_GATE`, the anchor the variants replace. */ +const TERNARY_EXIT_DISPATCH = 'runSelfTest() ? 0 : 1'; + /** * Both instruments, against both directions. Returns the failures; the caller * refuses on any. Nothing here reads the repo, so a control failure is always @@ -314,6 +373,31 @@ export function runControls() { say(classifyFloor(maskComments(SOUND_GATE)) === 'ROSTER', 'NEGATIVE CONTROL FAILED: a roster-floored self-test was not classified ROSTER'); + // The ternary exit, both directions. The failing arm being a NON-ZERO LITERAL + // is what produces the failure; the roster half still has to match on its own, + // and an opaque expression still has to produce nothing. + const ternaryExit = (dispatchArgs) => + maskComments(TERNARY_EXIT_GATE.replace(TERNARY_EXIT_DISPATCH, dispatchArgs)); + say(!PRODUCES_FAILURE_NAMED.test(maskComments(TERNARY_EXIT_GATE)), + 'CONTROL FIXTURE INVALID: the ternary fixture picked up one of the NAMED failure spellings; every verdict below it would then be passing for the wrong reason'); + say(classifyFloor(maskComments(TERNARY_EXIT_GATE)) === 'ROSTER', + 'NEGATIVE CONTROL FAILED: a roster floor whose only failure production is `process.exit( ? 0 : 1)` was not classified ROSTER'); + say(classifyFloor(ternaryExit('runSelfTest() ? 0 : 2')) === 'ROSTER', + 'NEGATIVE CONTROL FAILED: a ternary exit whose failing arm is a non-zero literal other than 1 was not classified ROSTER'); + say(classifyFloor(ternaryExit('!runSelfTest() ? 1 : 0')) === 'ROSTER', + 'NEGATIVE CONTROL FAILED: the inverted ternary exit (`? 1 : 0`, the failing arm first) was not classified ROSTER'); + say(classifyFloor(ternaryExit('runSelfTest()')) === 'NONE', + 'POSITIVE CONTROL FAILED: a bare `process.exit()` was read as producing a failure -- an opaque expression is the accident shape (it is `process.exit(undefined)` after an early return), not a floor'); + say(classifyFloor(maskComments(TERNARY_EXIT_GATE + .replaceAll('SELF_TEST_BATTERIES', 'FIXTURE_BATTERIES_BY_NAME') + .replaceAll('declaredBatteries', 'declaredNames'))) === 'NONE', + 'POSITIVE CONTROL FAILED: the ternary exit alone was classified ROSTER -- producing a failure is HALF the criterion; a roster this criterion can NAME is the other half'); + // Reuse rather than invention: the shape now recognised is the one the ACCIDENT + // fixture below actually dispatches with (and the audit file it is reduced + // from), so the criterion stays pinned to a spelling measured in this tree. + say(PRODUCES_FAILURE_TERNARY_EXIT.test(ACCIDENT_GATE.split('\n').find((l) => l.includes('process.exit(')) ?? ''), + 'CONTROL FAILED: the accident fixture no longer dispatches with the ternary exit this criterion was extended to read; the two have drifted apart'); + // Instrument 2, both directions, against real processes on disk. const dir = mkdtempSync(join(tmpdir(), 'self-test-floor-control-')); try { From 9d98ef60a61f6be9dff72bcd02e282d2ccb3fb7c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 4 Sep 2026 14:27:38 +0000 Subject: [PATCH 2/2] docs(scripts): correct a direction word in the ternary-exit control comment The ACCIDENT fixture is defined above `runControls`, not below it. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk --- scripts/measure-self-test-floor.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/measure-self-test-floor.mjs b/scripts/measure-self-test-floor.mjs index b54b2319e0..cb0ead4945 100644 --- a/scripts/measure-self-test-floor.mjs +++ b/scripts/measure-self-test-floor.mjs @@ -393,7 +393,7 @@ export function runControls() { .replaceAll('declaredBatteries', 'declaredNames'))) === 'NONE', 'POSITIVE CONTROL FAILED: the ternary exit alone was classified ROSTER -- producing a failure is HALF the criterion; a roster this criterion can NAME is the other half'); // Reuse rather than invention: the shape now recognised is the one the ACCIDENT - // fixture below actually dispatches with (and the audit file it is reduced + // fixture above actually dispatches with (and the audit file it is reduced // from), so the criterion stays pinned to a spelling measured in this tree. say(PRODUCES_FAILURE_TERNARY_EXIT.test(ACCIDENT_GATE.split('\n').find((l) => l.includes('process.exit(')) ?? ''), 'CONTROL FAILED: the accident fixture no longer dispatches with the ternary exit this criterion was extended to read; the two have drifted apart');