Repository navigation
Encode the sixteen prose mutations as patches, and judge them - #7
Merged
Merged
Conversation
Every record in e2e/verdict-mutations.json described its mutation as PROSE:
"src/dpf/gen.ts — flip every direction bit: X becomes Y". A person can follow
that; a script cannot, so nothing replayed it and the recorded kills were the
author's side of the claim.
Each record now carries a `patch` beside the prose: the file, an anchor that
must occur exactly once, and its replacement. The prose stays, because some of
it is worth keeping that a patch cannot hold -- key-part-root records that the
deeper serializer mutation (ROOT_MATERIAL_BYTES = SECURITY_BYTES) was tried
first and rejected as evidence, because it stops the key round-tripping and
takes the whole suite red, which is not a readable kill on that marker. The
prose says why; the patch is what runs.
ALL SIXTEEN ENCODINGS WERE RIGHT FIRST TIME, which is not what the adoption
note predicted (two of privacy-pass's twenty were wrong), and the reason is
that this ledger's prose already named the file and gave an exact before/after
pair. Two needed a decision, both resolvable by reading rather than by judging
what a claim meant:
server-view-0 `if (share[index] === 0) continue;` occurs TWICE in
src/pir/server.ts, at lines 19 and 55. The record says "in
serverAnswerProgressive", which begins at line 33, so the
anchor carries the following `foldedRecords += 1;` -- a line
only the progressive version has.
record-match `verdict.className = `verdict ${...}`` occurs twice; the
record names the `matches` ternary, which is the second.
THE RUNNER. scripts/mutation.mjs, following sleeve-check and privacy-pass for
its name and pqxdh-wire for its loop, enforcing all four rules:
1. the owning test passed unmutated in the same run, checked per record from
`assertedBy` rather than from the suite's exit code;
2. the patch changed the file, and the file returns to its original md5 --
both checked for every selected patch BEFORE any is applied, and the md5
re-checked after each one, aborting the run if a restore does not land;
3. the bundle hash moved, AND the failure does not match one of four shapes
that mean the code never ran (build error, server never started, nothing
on the port, port already held). CI=1 and --strictPort on 4698;
4. a patch that does not compile is DOES NOT BUILD, never a kill.
It archives HEAD into a temporary tree and mutates that, so a session dying
mid-run cannot strand an inverted condition in a file that also holds real
work, and it refuses a dirty working copy rather than reporting results about
a tree nobody else has.
The gate is `--project=verdict-ledger`, which playwright.config.ts gives
`dependencies: ['claims']`, so claims, flows and verdict-coverage run first and
e2e/verdict-ledger.spec.ts then asserts every record's triple was executed. A
`-g` run cannot exit 0 here: the named test passes and the ledger assertion
fails on the other fifteen. When a mutation does kill, the claims project goes
red and verdict-ledger is SKIPPED, which is why the verdict is read from the
owning test's own result in the JSON report.
16 record(s) make the round trip
baseline bundle 0165188c715d, baseline green, 21 specs
16/16 killed, 0 survived, 0 neither
Every line carries the hashes it moved between and back. Results are not
written into the ledger: verdict-ledger.spec.ts already fails the run when a
recorded kill did not execute, so an archived `observed` string would be a
second copy of an enforced answer. §4.1c calls writing back optional and
enforcement the requirement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every record in
e2e/verdict-mutations.jsondescribed its mutation as prose: "src/dpf/gen.ts — flip every direction bit: X becomes Y". A person can follow that; a script cannot, so nothing replayed it and the recorded kills were the author's side of the claim.Each record now carries a
patchbeside the prose — file, an anchor that must occur exactly once, and its replacement. The prose stays, because some of it holds something a patch cannot:key-part-rootrecords that the deeper serializer mutation (ROOT_MATERIAL_BYTES = SECURITY_BYTES) was tried first and rejected as evidence, since it stops the key round-tripping and takes the whole suite red, which is not a readable kill on that marker.All sixteen encodings were right first time
Not what the adoption note predicted — two of privacy-pass's twenty were wrong. The reason is that this ledger's prose already named the file and gave an exact before/after pair. Two needed a decision, both resolvable by reading rather than by judging what a claim meant:
if (share[index] === 0) continue;occurs twice insrc/pir/server.ts, at lines 19 and 55. The record says "inserverAnswerProgressive", which begins at line 33, so the anchor carries the followingfoldedRecords += 1;, a line only the progressive version has.verdict.className = \verdict ${...}`occurs twice; the record names thematches` ternary, which is the second.The runner
scripts/mutation.mjs, named after sleeve-check and privacy-pass, loop after pqxdh-wire, enforcing all four rules:assertedByrather than from the suite's exit code;CI=1,--strictPorton 4698;DOES NOT BUILD, never a kill.It archives HEAD into a temporary tree and mutates that, so a session dying mid-run cannot strand an inverted condition in a file that also holds real work, and it refuses a dirty working copy.
The gate is
--project=verdict-ledger, which the config givesdependencies: ['claims'], so claims, flows and verdict-coverage run first andverdict-ledger.spec.tsthen asserts every record's triple was executed. A-grun cannot exit 0 here. When a mutation kills, the claims project goes red and verdict-ledger is skipped — which is why the verdict is read from the owning test's own result in the JSON report.Result
Every line carries the hashes it moved between and back. Results are not written into the ledger:
verdict-ledger.spec.tsalready fails the run when a recorded kill did not execute, so an archivedobservedstring would duplicate an enforced answer, and §4.1c calls writing back optional and enforcement the requirement.Two files change: the ledger gains
patchon each of 16 records, and the runner is new. No source, test or workflow is touched.🤖 Generated with Claude Code