Skip to content

Proof v3: receipts that can't be faked - #1

Merged
EricFinland merged 43 commits into
mainfrom
v3-core
Sep 30, 2026
Merged

EricFinland merged 43 commits into
mainfrom
v3-core

Conversation

@EricFinland

Copy link
Copy Markdown
Owner

Proof v3: receipts that can't be faked

v2 caught agents claiming "tests pass" when they didn't. v3 closes the ways an agent could still slip a false claim through.

What changed

  • The hook runs the checks itself. The Stop hook verifies in-process under a time budget ([verify].inline_budget, default 90s) and blocks with the real output on FAIL. Only checks that don't finish in time go to a verifier subagent, and the hook keeps re-blocking until proof.py verify --claim-key has recorded a verdict.
  • SUSPECT verdict (exit 3). A SessionStart hook snapshots the repo (temp index, never touches your index or working tree). When tests "pass", Proof diffs against that baseline and flags gamed tests: deleted test files, removed tests, added skips, .only, gutted assertions, neutered test commands. It blocks once, then reports to you instead of nagging.
  • Red-green fix receipts. For "I fixed the bug" claims, the repro must fail on the session baseline (in a temp worktree) and pass now. Passing on both is SUSPECT.
  • Claim vs diff checks. "I fixed X" with nothing changed, or only docs changed, or a named file/symbol that the diff never touched.
  • CI. proof check "all tests pass" --since origin/main diffs from the merge-base.
  • Fixes to v2 behavior. The fix loop now actually re-blocks inside a continuation chain (v2 bailed on stop_hook_active), timeouts are deferred instead of counted as failures, the verifier checks the stored claim rather than the agent's latest message, and Windows command timeouts kill the whole process tree.

Verdicts

Verdict Exit
PASS 0
FAIL 1
INCONCLUSIVE 2
SUSPECT 3

Upgrading

Run proof arm again to install the SessionStart hook and the Stop hook timeout. proof status flags a v2 entry.

Tests

442 passed, 2 skipped (core), 68 passed (proofml), on Windows locally; CI covers Linux and Windows on Python 3.11 to 3.13.

Design: docs/specs/2026-09-29-v3-core-design.md

Adds proofkit/hookflow.py (decide_stop, verify_inline, DIRECTIVE with --claim-key) and reduces proof_trigger.py to a JSON-only wrapper. set_pending now demotes other pending claims in the session. An autouse conftest fixture isolates PROOF_HOME for every test.

Migrated v2 hook tests:
- test_trigger.py::test_fresh_claim_blocks_with_session: runs in an empty cwd, expects the deferral directive (adds --claim-key).
- test_trigger.py::test_reblock_after_fail_with_receipts: runs in a tests_fail copy with a prior fail, expects attempt 2 of 3 and the fresh FAIL tests receipt instead of PREVIOUS RECEIPTS.
- test_trigger.py::test_silent_after_pass, test_silent_after_max_cycles, test_noop_when_stop_hook_active, test_noop_on_non_claim, test_missing_transcript_path_is_silent, test_transcript_path_is_directory_is_silent: same assertions, explicit empty cwd.
- test_end_to_end.py::test_hook_fires_then_verifier_catches_the_lie: hook runs in a tests_fail copy and must block with the FAIL tests receipt; verifier step unchanged.
- test_fixes.py::test_directive_format_contains_quoted_script, test_trigger_directive_contains_out_dir_value: format with pending and key; out-dir assertion kept, claim-key assertion added.
- test_gate.py: unchanged, all gate skip/verify/audit assertions pass under the new flow.
…the chain

A reworded re-claim after a fail got fresh per-claim bookkeeping, so the opt-in gate could skip re-verification and FAIL_HEAD reported attempt 1 on every rewording. The gate now runs only outside a fail/suspect chain, and the attempt label uses the chain block count that caps the loop.

Tests: test_hookflow.py adds test_reworded_reclaim_in_fail_chain_counts_chain_attempts and test_gate_never_skips_reworded_reclaim_in_fail_chain. test_trigger.py::test_reblock_after_fail_with_receipts now simulates the prior fail inside the block chain (stop_hook_active set), keeping its attempt 2 of 3 and fresh receipt assertions.
@EricFinland
EricFinland merged commit daa0839 into main Sep 30, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant