Skip to content

fix: receipt freshness binds to tree content instead of commit reachability - #144

Merged
levifig merged 12 commits into
mainfrom
receipt-tree-binding
Jul 30, 2026
Merged

fix: receipt freshness binds to tree content instead of commit reachability#144
levifig merged 12 commits into
mainfrom
receipt-tree-binding

Conversation

@levifig

@levifig levifig commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Change

docs/changes/20260728-receipt-tree-binding/ — target_release: 2.0.0

What & Why

Shapes the receipt freshness rebinding: validity moves from commit reachability to content digests. Today receipts/verify.json records a verified_commit and the gate walks verified_commit..HEAD — after a squash or rebase merge plus branch deletion that commit is unreachable on every machine but the author's, so the same repo content blocks with a clean reason locally and crashes with a bare exit status 128 on CI. The council also proved two deeper defects: cohorts of N≥2 are unsatisfiable under the current rule (each member's receipt commit stales the others, in every ordering), and verify attests worktree results under a HEAD label. The fix: a masked root-tree digest over a declared exclusion set (receipts repo-wide ∪ report boards ∪ the exported releaseMetadataAllowlist), making designation-legal ⟺ receipt-neutral; schema v2 receipts; a pure freshness predicate with typed reasoned verdicts; reachability retired from the verdict entirely.

Review focus

The gating-scope decision (masked root tree over folder scope — 3:2 council split, owner-settled; board committed in reports/), the exact digest serialization (Decision 8 — quotePath/sort/mode/case pinned), the deliberate drop of touch-then-revert detection (Decision 4), and the dirty-worktree refusal at verify.

Verification

All four V-entries green via loaf change verify with the schema-v2 receipt committed at HEAD — this change's own receipt is the first v2 receipt, and it survived a post-verify amend intact (verified_commit no longer exists; the content-bound verdict did not change). loaf change check: zero violations, derives verified. Five review rounds are recorded as boards in reports/: initial review (six findings), Codex gpt-5.6-sol xhigh continued-thread (three findings, incl. the mid-verify mutation and re-verify sweep defects), and Codex fresh-thread (four findings, incl. the submodule-ignore and HEAD-move bypasses) — thirteen findings total, all dispositioned, fixed, and re-verified. The council board (five lenses, decision recorded) is at reports/20260728-222942-council-receipt-freshness.html.

Migration / breaking changes

Schema v2 is a clean break: v1 receipts are refused with a named re-verify remedy (zero receipts exist anywhere today, so nothing is grandfathered). The cannot inspect receipt error path is deleted, not just avoided.

Deferred

CI-green-at-HEAD assertion, rc-cut gating, and the designation diff check — the release-promotion-model Change consumes this change's exported boundary for them (PR #143); per-change evidence_paths (only if a real case appears); rc-sweep command dedup (only when a cohort is big enough to feel it).

levifig added 12 commits July 28, 2026 22:33
Scope digests and the exported exclusion boundary make receipt freshness
merge-strategy-agnostic and designation-legal equal to receipt-neutral.
Verify now records scope digests and refuses dirty tracked trees so a
receipt cannot attest bytes that no commit holds.
Delete the commit-walk freshness path so every clone yields the same
typed verdict under squash, rebase, or cohort peers.
Bare exit-status failures hid the cause; capture stderr and render
folder/cause/remedy blocks from the typed freshness verdict.
Submodule ignore=all and porcelain arrow-path parsing could hide dirt or strip report-mask exemptions; HEAD advances mid-verify could record a clean receipt for an unattested commit. Make status ignore-submodules=untracked with NUL parsing, void on HEAD movement, and annotate ADR-023/024.
@levifig
levifig marked this pull request as ready for review July 30, 2026 11:01
@levifig
levifig merged commit 3575237 into main Jul 30, 2026
1 check passed
@levifig
levifig deleted the receipt-tree-binding branch July 30, 2026 11:05
levifig added a commit that referenced this pull request Jul 30, 2026
The release artifact rebuild changed the native binary after #144's Go changes, staling the installed-smoke receipts that pin its SHA-256. Re-recorded claude-code 2.1.220, codex 0.146.0 (client upgraded from 0.145.0), and opencode 1.18.7 smokes against the new binary; updated the capability record and contract-test identity pins accordingly.
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