|
| 1 | +# RECEIPT_CHAIN_v0.2 |
| 2 | + |
| 3 | +Status: Design and test artefact only. |
| 4 | + |
| 5 | +Scope: Narrow, path-local proof surface for hash-linked refusal receipts. |
| 6 | + |
| 7 | +Claim boundary: This does not claim production readiness, compliance, tamper-proofing, or path-universal governance. It describes one bounded receipt-chain pattern for inspection and testing. |
| 8 | + |
| 9 | +## Purpose |
| 10 | + |
| 11 | +A refusal receipt should not only say that an action was refused. |
| 12 | + |
| 13 | +It should also be possible to inspect whether that receipt belongs to a coherent receipt chain, whether the attempted payload and decision record are bound to the receipt, and whether the system recorded that no mutation was committed. |
| 14 | + |
| 15 | +This artefact defines the smallest useful receipt-chain brick for `commit-gate-core`. |
| 16 | + |
| 17 | +## Core invariant |
| 18 | + |
| 19 | +No consequence-producing mutation is permitted unless the gate returns an admissible decision. |
| 20 | + |
| 21 | +If the gate refuses, the refusal must be recorded before mutation and the receipt must bind: |
| 22 | + |
| 23 | +1. the attempted payload, |
| 24 | +2. the decision record, |
| 25 | +3. the refusal reason, |
| 26 | +4. the previous receipt hash, |
| 27 | +5. the current receipt hash, |
| 28 | +6. evidence that mutation did not commit. |
| 29 | + |
| 30 | +## Minimal receipt fields |
| 31 | + |
| 32 | +```json |
| 33 | +{ |
| 34 | + "receipt_id": "rcpt_0002", |
| 35 | + "previous_receipt_hash": "sha256:...", |
| 36 | + "payload_hash": "sha256:...", |
| 37 | + "decision_record_hash": "sha256:...", |
| 38 | + "decision": "REFUSE", |
| 39 | + "refusal_reason": "missing_valid_authority", |
| 40 | + "mutation_committed": false, |
| 41 | + "state_snapshot_hash": "sha256:...", |
| 42 | + "timestamp_utc": "2026-05-11T00:00:00Z", |
| 43 | + "receipt_hash": "sha256:...", |
| 44 | + "signature": null |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +## Hashing rule |
| 49 | + |
| 50 | +`receipt_hash` is calculated over the canonical receipt body excluding `receipt_hash` and `signature`. |
| 51 | + |
| 52 | +Canonicalisation must be deterministic. |
| 53 | + |
| 54 | +The minimum acceptable test is: |
| 55 | + |
| 56 | +1. Same receipt body produces the same hash. |
| 57 | +2. Any payload change changes `payload_hash`. |
| 58 | +3. Any decision record change changes `decision_record_hash`. |
| 59 | +4. Any receipt body change changes `receipt_hash`. |
| 60 | +5. Any broken `previous_receipt_hash` breaks chain verification. |
| 61 | + |
| 62 | +## Verification procedure |
| 63 | + |
| 64 | +A verifier should check: |
| 65 | + |
| 66 | +1. `decision` is `REFUSE`. |
| 67 | +2. `mutation_committed` is `false`. |
| 68 | +3. `payload_hash` matches the attempted payload. |
| 69 | +4. `decision_record_hash` matches the DecisionRecord used by the gate. |
| 70 | +5. `previous_receipt_hash` matches the prior receipt in the chain. |
| 71 | +6. `receipt_hash` recomputes correctly from the canonical receipt body. |
| 72 | +7. Optional signature verifies against the declared signing key, if signatures are enabled. |
| 73 | + |
| 74 | +## Signature status |
| 75 | + |
| 76 | +Signature support is optional in v0.2. |
| 77 | + |
| 78 | +If used, the signature must bind the canonical receipt body and declared key identity. |
| 79 | + |
| 80 | +Key rotation must be logged as its own audit event before any new signing key is treated as active. |
| 81 | + |
| 82 | +## What this does not prove |
| 83 | + |
| 84 | +This artefact does not prove that: |
| 85 | + |
| 86 | +- the system is production-ready, |
| 87 | +- the chain is tamper-proof, |
| 88 | +- every possible execution path is covered, |
| 89 | +- the implementation satisfies any compliance regime, |
| 90 | +- downstream systems cannot mutate by another route. |
| 91 | + |
| 92 | +It only defines a small, inspectable receipt-chain pattern for refused actions. |
| 93 | + |
| 94 | +## Clean line |
| 95 | + |
| 96 | +Do not call it hardened. |
| 97 | +Make it harder to fool. |
0 commit comments