Skip to content

[finding] measure-self-test-floor's probe awards HELD on a non-zero exit ALONE, so a file with NO verdict handshake reads HELD — measured on scripts/audits/14744-before-update-per-row-value-census.mjs #15324

Description

@claude

Found while classifying scripts/audits/14744-before-update-per-row-value-census.mjs for #13799 batch 10a (the census row the PM asked for). Filed unassigned. Sibling of #14842 and #14963 — same instrument, a third and different root cause — and adjacent to #14968, which asks for a handshake reading the instrument does not take.

The mechanism

probeEarlyReturn() in scripts/measure-self-test-floor.mjs decides its verdict on the mutated run's exit code and nothing else:

verdict: mut.status === 0 ? 'DEFEATED' : 'HELD',

There is a guard above it for a mutation that changed nothing observable (same output AND same status is NOT MEASURED), but no requirement that the mutated run SAY anything. So any file whose early-returned run happens to exit non-zero scores HELD — including one that carries no verdict handshake at all.

The measured instance

scripts/audits/14744-before-update-per-row-value-census.mjs (landed by #15301, 655 lines) carries none of the three handshake spellings #14968 tallies: zero SELF_TEST_VERDICT, zero selfTestReachedVerdict, zero requireReachedVerdict. Its dispatch is:

if (process.argv.includes('--self-test')) {
  process.exit(runSelfTest() === 0 ? 0 : 1);
}

An early return makes runSelfTest() yield undefined; undefined === 0 is false; the process exits 1 printing nothing. The instrument's own row records exactly that and still calls it HELD (measured on 103677652, node scripts/measure-self-test-floor.mjs --probe --json, exit 0):

{"file":"scripts/audits/14744-before-update-per-row-value-census.mjs","floor":"NONE","defs":["runSelfTest"],
 "probe":{"verdict":"HELD","entry":"runSelfTest","baselineExit":0,"mutatedExit":1,"mutatedBytes":0,"mutatedHead":""}}

mutatedBytes 0 and an empty mutatedHead are the tell, and they are already in the row — the verdict just does not read them. Compare the same run's scripts/check-osv-exemptions.mjs: mutatedBytes 206, mutatedHead naming the handshake by name. Both are HELD.

Why it matters

This is precisely the accident-versus-handshake distinction #14842 drew by hand for one file (selfTest mutated to a TypeError stack: "an accident, not a handshake. A row naming this entry would record a hold this file does not have"). Here the instrument makes that mistake on its own, with no ambiguous entry to blame — so a green --probe sweep is not evidence that the files in it have handshakes, and #13798's completion picture cannot be read off it.

Options

Recommendation: A, with C as the separate repair #14968 already asks for. A costs one condition over a field the instrument already records, it turns a wrong answer into an honest one, and it does not commit the instrument to knowing any spelling. B is the same coupling #14968 is filed to remove.

Scope note

The audits file is ALSO unfloored (floor: NONE) and is 10a's classification target; its census row goes to #13799. Nothing here asks for it to be floored — this card is about the instrument's verdict, not about that file.

Duplicate-checked before filing against 284 open issues from the repo-scoped issues list plus a local grep (control terms returned the known family #14842 / #14963 / #14968 / #15296 / #15317, confirming a live read); no existing card for this criterion.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions