mergedhumanPR #266Other
fix(receipt): refuse receipts over bundles that fail verification
One of nine independent PRs from a correctness audit of main at df0b5f1. Each merges cleanly with the others in any order; together they pass 908 tests locally on Python 3.11 and 3.14 (CI covers 3.11 and 3.12).
Description
The pitch.
One of nine independent PRs from a correctness audit of `main` at `df0b5f1`. Each merges cleanly with the others in any order; together they pass 908 tests locally on Python 3.11 and 3.14 (CI covers 3.11 and 3.12). Commits: `df8aa6c`, `2ea5adb`, `ce0a715`, `b2e5dbc`, `efea868` ### Problem `nandatown receipt` signed claims copied from `manifest.json` without verifying the bundle. `verify-receipt --bundle` compared only against those manifest values. So a bundle edited in place after its receipt, or a failed result relabelled "passed" without rehashing, still printed "receipt verifies … and the bundle matches" or received a signed passing receipt, with exit 0. `proof` already refused both. ### Change - Receipt creation and bundle-aware receipt verification now run the `verify` checks first. They refuse, naming each problem, on: - record, hash, manifest or fingerprint problems; - cross-record binding problems; - an unsupported evaluator; - an evaluator replay mismatch; - an attestation failure. - The one exception is a bundle recorded by an evaluator version that actually shipped earlier for that mode. The versions are listed in `SHIPPED_EVALUATOR_VERSIONS` in `bundle.py`, taken from git history. Every other check still runs, and the command output says `evaluator replay not checked: bundle X, local Y`. That line is not part of the signed receipt. - A made-up or future evaluator version is refused with `unrecognised evaluator version …; replay not possible`. - The exception is marked by a typed `EvaluatorVersionDiffers` problem, not by string matching. ### Compatibility - `verify_bundle` output is unchanged for `proof`, `mirror`, `recover`, `board` and `verify`. - The receipt payload is unchanged. - `verify-receipt` without `--bundle` still checks only shape and signature. - Partial and failed receipts over intact bundles still work. - Receipts are no longer issued for bundles that fail current-evaluator replay. The existing proof-integrity test expects that refusal at receipt time. It also still shows that `proof` refuses a validly hand-signed receipt over a replay-mismatched bundle. - **Remaining limit:** someone can still relabel a bundle with a genuinely old version string and get a receipt carrying the disclosure. This is by design, so honest historical bundles keep getting receipts; closing it would require replaying under old evaluators. - **Merge note:** if `fix/track-response-correlation` also merges, add Track `0.3.0` to `SHIPPED_EVALUATOR_VERSIONS` when Track moves past it. If that is missed, those bundles are refused, not wrongly accepted. ### Verification - Full suite on the branch: 835 passed. - An adversarial reviewer ran 27 integrity attacks per bundle over Lab, Track and Path bundles. All are refused, and no honest bundle is refused. - The made-up-version attack was also run through the real CLI: refused, exit 1, no receipt written. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Try it
Open PR on GitHubView diffCheckout locally
git fetch origin pull/266/head:pr-266
git checkout pr-266