Skip to content

Commit 582bea6

Browse files
claude[bot]claude
andauthored
fix(devx): the durability-log-level self-test handshake asserts "ran to the end", pass or fail (#15504)
`selfTest()` set `selfTestReachedVerdict` on its SUCCESS path only, and the dispatch read that flag BETWEEN the two batteries. A genuine red therefore printed its own verdict line and was then reported as "selfTest() returned without reaching its verdict" — false, since the verdict had just been printed — and the process exited before `selfTestReadSeams()` ran at all, which is exactly what the comment above the dispatch forbids ("a red one must not hide the other"). Exit 1 either way, so no false green; the cost was a misleading diagnostic plus half the self-test coverage lost on the red path. Both halves of the repair: - the flag is now set at BOTH verdict sites of each battery, adjacent to the line it certifies, so it can only be true if a verdict was really printed; the returned status keeps carrying pass/fail; - the dispatch runs BOTH batteries first and reads both handshakes after, then exits with the combined status. An early `return` above either verdict still trips that battery's own named diagnostic — the property the handshake was landed for is unchanged. `scripts/check-dispatcher-error-vocabulary.mjs` ships the same landed shape and is deliberately untouched: its failure path calls `process.exit(1)` inside the self-test, so its flag is never consulted on a red. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
1 parent cabd7cc commit 582bea6

1 file changed

Lines changed: 41 additions & 11 deletions

File tree

scripts/check-durability-degradation-log-level.mjs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4201,11 +4201,21 @@ function reportDepthCost() {
42014201
// fixtures pin both directions: it must FLAG the #4420 shape and must NOT flag
42024202
// the shapes that are legitimately `warn`.
42034203

4204-
// Set by `selfTest()` only after its verdict is printed, and read at the
4205-
// dispatch: a `return` that leaves the function above that line prints nothing
4206-
// and still exits 0 — a self-test that never finished, reported as one that
4207-
// passed (#13798). The self-test's own exit code stays load-bearing, so the
4208-
// handshake is a flag rather than a returned sentinel.
4204+
// Set by `selfTest()` at BOTH its verdict sites — the green line and the red
4205+
// one — and read at the dispatch AFTER both batteries have run. What it asserts
4206+
// is "ran to the end", pass or fail: a `return` that leaves the function above
4207+
// both verdict lines prints nothing and still exits 0 — a self-test that never
4208+
// finished, reported as one that passed (#13798). The self-test's own exit code
4209+
// stays load-bearing, so the handshake is a flag rather than a returned sentinel.
4210+
//
4211+
// ⛔ Not the sibling gates' shape, deliberately (#14962). Those set the flag on
4212+
// the success path alone, which is sound THERE because their failure path calls
4213+
// `process.exit(1)` inside the self-test, so the flag is never consulted on a
4214+
// red. Here the failure path `return`s and the dispatch keeps running, so a
4215+
// success-only flag reads a genuine red as "never reached its verdict" — a false
4216+
// diagnostic that sends a maintainer hunting for a truncated run that did not
4217+
// happen, and, when the flag was read between the two calls, stopped the second
4218+
// battery from running at all.
42094219
let selfTestReachedVerdict = false;
42104220

42114221
// ── The two self-tests' battery roster and floors (#13489, batch 10c) ────────
@@ -5526,6 +5536,12 @@ function selfTest() {
55265536
);
55275537
if (failures > 0) {
55285538
console.error(`\n✗ self-test (log-level rule): ${failures} failure(s) (cases and floor)\n`);
5539+
// A printed red verdict IS a reached verdict (#14962). The handshake
5540+
// asserts "ran to the end", pass or FAIL; the returned 1 keeps carrying
5541+
// the verdict, so the dispatch still exits 1. Set HERE, adjacent to the
5542+
// line it certifies, rather than once before the branch: the flag can
5543+
// then only be true if one of the two verdict lines was really printed.
5544+
selfTestReachedVerdict = true;
55295545
return 1;
55305546
}
55315547
console.log(`\n✓ self-test (log-level rule): ${cases.length} case(s) passed\n`);
@@ -5543,7 +5559,9 @@ function selfTest() {
55435559
// three instances, in both directions, or the fourth recurrence lands green.
55445560
// The dispatch calls TWO self-test entries and combines their statuses, so each
55455561
// one needs its own handshake: a `return` above either verdict prints nothing and
5546-
// leaves `undefined`, which the `||` below reads as a pass (#13798).
5562+
// leaves `undefined`, which the `||` below reads as a pass (#13798). Set at both
5563+
// of this battery's verdict sites, green and red, for the reason spelled out at
5564+
// `selfTestReachedVerdict` (#14962).
55475565
let readSeamsReachedVerdict = false;
55485566

55495567
function selfTestReadSeams() {
@@ -6793,6 +6811,9 @@ function selfTestReadSeams() {
67936811
);
67946812
if (failures > 0) {
67956813
console.error(`\n✗ self-test (read-seam invention rule): ${failures} failure(s) (cases and floor)\n`);
6814+
// Its own handshake, same reading as `selfTest`'s red path (#14962): a
6815+
// printed red verdict is a reached verdict, and the returned 1 carries it.
6816+
readSeamsReachedVerdict = true;
67966817
return 1;
67976818
}
67986819
console.log(
@@ -6805,26 +6826,35 @@ function selfTestReadSeams() {
68056826

68066827
const args = process.argv.slice(2);
68076828
if (args.includes('--self-test')) {
6808-
// Both rules' fixtures always run — a red one must not hide the other.
6829+
// Both rules' fixtures always run — a red one must not hide the other. That
6830+
// is why BOTH batteries run BEFORE either handshake is read (#14962): reading
6831+
// the first handshake between the two calls exited the process on a red
6832+
// battery 1, so battery 2 never ran — the very thing this comment forbids —
6833+
// and it did so under a message saying no verdict had been reached, while the
6834+
// red verdict line sat directly above it in the same output.
68096835
const logLevelStatus = selfTest();
6836+
const readSeamStatus = selfTestReadSeams();
6837+
// Read AFTER both have reported. An early `return` from either one still
6838+
// trips its own named diagnostic here; a genuine red does not, because a
6839+
// printed verdict sets the flag.
6840+
let handshakeMissing = false;
68106841
if (!selfTestReachedVerdict) {
68116842
console.error(
68126843
'\n✗ check-durability-degradation-log-level self-test: selfTest() returned without reaching its verdict,\n'
68136844
+ 'so no success line was printed. Exiting 0 here would report a self-test\n'
68146845
+ 'that never finished as a self-test that passed.\n',
68156846
);
6816-
process.exit(1);
6847+
handshakeMissing = true;
68176848
}
6818-
const readSeamStatus = selfTestReadSeams();
68196849
if (!readSeamsReachedVerdict) {
68206850
console.error(
68216851
'\n✗ check-durability-degradation-log-level self-test: selfTestReadSeams() returned without\n'
68226852
+ 'reaching its verdict, so no success line was printed. Exiting 0 here would report a\n'
68236853
+ 'self-test that never finished as a self-test that passed.\n',
68246854
);
6825-
process.exit(1);
6855+
handshakeMissing = true;
68266856
}
6827-
process.exit(logLevelStatus || readSeamStatus ? 1 : 0);
6857+
process.exit(handshakeMissing || logLevelStatus || readSeamStatus ? 1 : 0);
68286858
} else if (args.includes('--depth-cost')) {
68296859
// A diagnostic, deliberately not part of any verdict — see `reportDepthCost`.
68306860
process.exit(reportDepthCost());

0 commit comments

Comments
 (0)