Make assay's own guards provably able to fail - #16
Merged
Conversation
The claim this PR touches: every property assay states out loud — the ranking metrics being trec_eval's arithmetic, the refusals refusing, the envelope pinning its signer, the ledger's three integrity checks, and the numeric literals the README promises — is guarded by a test that has been watched go red for the right reason. Why now: assay's ranking-face red runs existed only as prose in commit 1c382ce. No mutation harness was committed anywhere, so no reader could re-run them, and a guard nobody can watch fail is not evidence. That is especially sharp here, since assay is the repo that supplies measurement tooling to everything else. What landed: - scripts/mutation_harness.py, `uv run poe mutants`. 18 mutations, each naming the claim it breaks. Per mutation: run the named guard unmutated (must exit 0), edit the source, read the file back off disk to confirm the edit landed, run the guard again (must exit 1), restore in a finally and compare bytes. The verdict is the pytest exit code and nothing else — 4 (usage error) and 5 (nothing collected) each get their own name and fail the run, because a harness elsewhere in this portfolio grepped stdout, read a crashed runner as "no failures", and reported all 12 of its mutations green. - A test the harness found missing. Deleting the ledger's chain-link check left the whole suite green: the splice test survived it because a spliced entry also changes the count, so the pinned-head check caught it first. The chain walk was defended only in depth and had no case that isolated it. test_should_reject_a_ledger_whose_chain_link_was_rewritten rewrites an interior prev_hash and nothing else — head still matches on count and hash, every signature still verifies, only the chain walk can object. - tests/test_documented_constants.py pins literals to the literal. test_vectors asserted `>= 8` canonicalization vectors and `>= 1` receipts: loose bounds on shape that stay green while three vectors go missing and the README keeps saying 12. Now pinned at 9 / 3 / 12, plus the documented ranking cut-off of 10. No existing assertion was weakened or deleted. - .github/dependabot.yml (github-actions, weekly). assay had none, which is why it was the only repo still on astral-sh/setup-uv v8.3.2 while the rest of the portfolio moved to v9.0.0 — a SHA pin does not move on its own. Both pins bumped to v9.0.0, with the exact version in the comment, never a floating `# v9`. - A mutation-gate CI job, so the evidence regenerates on every PR. Not a step inside `gate`: `gate` asks whether the tests pass, this asks whether they can fail. The gate now also covers scripts/, because the harness that proves the guards can fail is not exempt from the gate that guards them. Evidence: - 18/18 guards fired; whole suite green after restore (harness exit 0). - Watched the harness itself fail three ways: a stale anchor raises MutationNotAppliedError (exit 1); a guard pointed at a test that cannot notice reports SURVIVED (exit 1); a guard node id that does not exist reports BASELINE NOT GREEN (exit 4) (exit 1). - `uv run poe gate` exit 0 — 187 tests, 100% statement and branch coverage. - `pnpm -r --include-workspace-root gate` exit 0 under Node 24 — 71 TS tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015o7tjWLFZvzRv4KyNfDukx
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
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.
The claim this PR touches
Every property assay states out loud — the ranking metrics being
trec_eval's arithmetic, the refusals refusing, the envelope pinning its signer, the ledger's three integrity checks, and the numeric literals the README promises — is now guarded by a test that has been watched go red for the right reason, by a harness anyone can re-run.Why now. assay's ranking-face red runs existed only as prose in commit
1c382ce. No mutation harness was committed anywhere in the repo, so no reader could re-run them. A guard nobody can watch fail is not evidence — and that is especially sharp here, since assay is the repo that supplies measurement tooling to the rest of the portfolio.One command
Evidence: 18/18 guards fired
ranking-order-reaches-trec-evalranking-k-reaches-trec-evalkis handed to the engine, not ignoredranking-recall-is-not-precisionranking-graded-gains-reach-trec-evalranking-average-precision-is-trec-eval-mapranking-f1-is-the-harmonic-meanranking-refuses-an-empty-relevant-setranking-refuses-a-fractional-gainranking-refuses-a-duplicate-documentenvelope-recomputes-the-payload-hashenvelope-pins-the-signerledger-chains-each-entry-to-the-one-beforeledger-requires-the-pinned-headledger-verifies-every-entry-signaturedocumented-sample-floor-is-30documented-confidence-level-is-95pcdocumented-ranking-cutoff-is-10documented-golden-vector-count-is-12The verdict is the exit code, never grepped output
0all passed,1a test failed,4usage error,5nothing collected. Only1counts as a guard firing; every other code gets its own name and fails the run. A harness elsewhere in this portfolio passed--reporter=basicto a Vitest with no such reporter, every run crashed, the grep read the crash as "no failures", and all 12 mutations reported green.Each mutation is also read back off disk before its verdict is trusted, and the anchor must occur exactly once or the harness hard-stops — a mutation that silently did not apply can never be scored as a guard that held.
The harness was itself watched failing, three ways
MutationNotAppliedError: anchor occurs 0x, expected exactly 1SURVIVED — the guard is blind to this breakBASELINE NOT GREEN (exit 4) — the guard was not passing to startA real finding: the ledger chain walk had no isolating test
Deleting the chain-link check left the whole suite green. The existing splice test survived it because a spliced entry also changes the entry count, so the pinned-head check caught it first — the chain walk was defended only in depth.
test_should_reject_a_ledger_whose_chain_link_was_rewrittenisolates it: rewrite an interior entry'sprev_hashand nothing else. The last entry is untouched so the pinned head still matches on count and hash, andprev_hashsits outside the signed receipt so every signature still verifies. Only the chain walk can object.A second finding: two vector-count assertions measured shape
test_vectors.pyasserted>= 8canonicalization vectors and>= 1receipts while the README promises 9, 3 and 12. Three vectors could go missing with the suite green.tests/test_documented_constants.pynow pins the literals. No existing assertion was weakened or deleted — the loose bounds stay as the shape check they are.Also in here
.github/dependabot.yml(github-actions, weekly). Verified: assay had no Dependabot config, which is exactly why it was the only repo in the portfolio still onastral-sh/setup-uvv8.3.2 while everything else moved to v9.0.0. A SHA pin does not move on its own.c771a70e6277c0a99b617c7a806ffedaca235ff9, verified against the upstream tag), with the exact version in the comment — never a floating# v9.GET /repos/hseshadr/assay/vulnerability-alerts→204;automated-security-fixes→{"enabled":true,"paused":false}.mutation-gateCI job, so the evidence regenerates on every PR instead of being captured once. Deliberately not a step insidegate:gateasks whether the tests pass, this asks whether they can fail.scripts/(ruff, ruff-format, mypy--strict, xenon A). The harness that proves the guards can fail is not exempt from the gate that guards them.Statuscorrected — it claimed 220 tests andavow0.2.0 as published; it is 258 and 0.3.0.Gates
uv run poe gatepnpm -r --include-workspace-root gate(Node 24)@edgeproc/avow+ 31@edgeproc/receipt-ui, 100% coverage bothuv run poe mutantsNothing merged, tagged or published.
🤖 Generated with Claude Code
https://claude.ai/code/session_015o7tjWLFZvzRv4KyNfDukx