Skip to content

fix(scripts): measure-self-test-floor's probe reads NOT MEASURED when the baseline run already fails (#15391) - #15455

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-15391-probe-baseline-not-measured
Sep 4, 2026
Merged

fix(scripts): measure-self-test-floor's probe reads NOT MEASURED when the baseline run already fails (#15391)#15455
baozhoutao merged 2 commits into
mainfrom
claude/issue-15391-probe-baseline-not-measured

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15391

probeEarlyReturn decided HELD / ACCIDENT from the mutated run alone. When the UNMUTATED file already exits non-zero, this tree cannot run it at all, so the mutation had nothing to defeat — but both runs exit non-zero and both print a module-resolution stack, so the mutated run "speaks" and the row read HELD: the flattering answer, awarded for the tree being broken. The same row reads ACCIDENT once the tree is installed, so one probe row had two verdicts depending on the environment.

The fix

The baseline is now a precondition, not a data point. It is read before any reading of the mutated run, and a non-zero one ends the probe as NOT MEASURED with the reason baseline run failed (exit N).

The mutated run is not spawned at all in that case. That is the deliberate half of the choice the card left open: in the shape that motivates this (a checkout whose dependencies are absent) every row is baseline-red, so running each doomed mutation would double a whole sweep of spawns to learn nothing.

--probe's human listing and its tallies fold the row into the existing NOT MEASURED class with that reason — no new class, no renamed key. The row additively publishes baselineExit, baselineBytes and baselineHead; baselineHead is usually the whole diagnosis (Cannot find package ... reads as "run pnpm install").

Before / after — the row from the card

Reproduced on this tree by making the audits census file's typescript import unresolvable (the dependency the card's stack trace names). Restore proven by git hash-object equality with the HEAD blob and an empty git diff HEAD.

field before (f01adfa5c) after (this branch)
verdict HELD NOT MEASURED
why absent baseline run failed (exit 1)
entry runSelfTest runSelfTest
baselineExit 1 1
mutatedExit 1 not spawned
mutatedBytes 965 not spawned
mutatedHead node:internal/modules/package_json_reader:314 not spawned
mutatedSpoke true not spawned
baselineBytes absent 942
baselineHead absent node:internal/modules/package_json_reader:314

The new inline control

UNRUNNABLE_GATE — a fixture whose first statement is an import no registry can supply, so neither run ever reaches its (perfectly ordinary, injectable) self-test. Two assertions, because one alone would pass for the wrong reason:

  1. the verdict is NOT MEASURED and the reason is the baseline one — which pins which NOT MEASURED branch fired, not merely that some branch did;
  2. the fixture really is a red baseline that speaks (baselineExit non-zero, baselineBytes positive, baselineHead non-empty) — exactly the shape an exit-code-and-speech reading scored HELD.

Controls run inline on every invocation, as this file's already do; it ships no --self-test mode to add them to.

Ablation. Neutralising the new guard turns the controls red, and they name the defect:

POSITIVE CONTROL FAILED: a file whose BASELINE run already exits non-zero was read as HELD (); the mutation had nothing to defeat, so nothing was measured
POSITIVE CONTROL FAILED: the unrunnable fixture no longer produces the measured shape (baseline exit 1, undefined byte(s)); the NOT MEASURED verdict above would then be passing for the wrong reason

Mutation and restore were both proven on disk (anchor grep counts each way; restore equal to the HEAD blob by hash, with an empty git diff HEAD). No dist/ is involved — this script runs as source, so there is no rebuild leg.

Whole-population check

--probe --json over all 170 rows, base f01adfa5c vs this branch, in an installed tree:

  • floor tallies unchanged: 165 roster / 4 NONE / 1 count-candidate;
  • verdict tallies unchanged: 164 HELD / 1 ACCIDENT / 5 NOT MEASURED;
  • verdict changes: 0, and rows with a non-zero baselineExit: 0 — which is why those two agree. The whole payload is byte-for-byte identical between the two runs, so no row moved for any other reason either;
  • the three handshake dispatch spellings still read HELD: check-nul-bytes.mjs (compare in place), check-watch-hint-literal.mjs (bind, then compare), check-ratchet-remedy-authority.mjs (a reached-verdict flag).

A plain --json run exits 0, so the inline controls pass.

Gates

Run at 484688f09, exit codes captured before any pipe. All 22 commands of the derived family (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack) exit 0, plus check:pm-dispatch-gates (✓ dispatch-gates self-test: 1402 cases pass., under the shared verify lock), check-self-test-workflow-commands.mjs and its --self-test, check:declared-population-live, the verify-lock and os-regen-merge self-tests, and whole-repo pnpm lint (exit 0, full population — no narrowing). No gate exited 3, so nothing here is NOT MEASURED.

check-self-test-wired still places this file on its inline route: ✓ check-self-test-wired: every one of the 169 script(s) CI runs that ship a --self-test has that self-test run by CI.

origin/main was merged in at a256cd45f so the gate-family derivation would read a tree someone is actually on; the family it derives is identical either way.

Scope

#15371 (helper-spelling coverage) and #15421 are queued behind this on the same file and are deliberately untouched here.

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

…fails

`probeEarlyReturn` awarded HELD/ACCIDENT from the mutated run alone. When the
UNMUTATED file already exits non-zero the tree cannot run it at all, so the
mutation had nothing to defeat -- but both runs exit non-zero and both print a
module-resolution stack, so the mutated run "speaks" and the row read HELD. A
checkout without `pnpm install` therefore reported the flattering answer for
every file it could not load, and the same row read ACCIDENT once installed.

The baseline is now a PRECONDITION, read before any reading of the mutated run:
a non-zero one ends the probe as NOT MEASURED with `baseline run failed
(exit N)`. The mutated run is not spawned at all -- in the shape that motivates
this every row is baseline-red, so those spawns would double a whole sweep to
learn nothing. The row additively publishes `baselineExit`/`baselineBytes`/
`baselineHead`; no existing key is renamed, and `--probe`'s listing and tallies
fold it into the existing NOT MEASURED class.

A new inline control (`UNRUNNABLE_GATE`, an unresolvable import) pins both
halves: the verdict is NOT MEASURED with that reason, and the fixture really is
a red baseline that SPEAKS -- the shape an exit-code-and-speech reading scored
HELD.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
@github-actions github-actions Bot added the size/s label Sep 4, 2026
@baozhoutao baozhoutao added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026 — with Claude
@baozhoutao
baozhoutao marked this pull request as ready for review September 4, 2026 16:36
@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 16:36
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit e8c7956 Sep 4, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-15391-probe-baseline-not-measured branch September 4, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] measure-self-test-floor's probe awards HELD/ACCIDENT when the BASELINE run already exits non-zero — an uninstalled tree reads HELD

2 participants