> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ctrlrun.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The receipt chain

> Each receipt carries the hash of the one before it, so an edit, a deletion from the middle or a reordering is detected and named by seq.

The receipt chain is a hash chain over the evidence log: receipt *n* carries `prev_hash`, the
hash of receipt *n − 1*, with `seq` inside the hashed content. Change what one receipt says,
delete one from the middle, or swap two, and the chain no longer verifies at that point.
`ctrlrun receipts --verify-chain` reports the break by `seq` and by name.

## What it detects

```console theme={null}
$ ctrlrun receipts --verify-chain
chain: 41 receipts
seq 17: content altered
```

Six named breaks: content altered at a `seq`, a broken link between two, a gap where a `seq` is
missing, a duplicate `seq`, a head that does not match the last receipt, and an unchained
receipt where the chain expected one. Each names the `seq` so a reader can go and look at that
row rather than being told the log is bad.

## What it does not prove

**Alteration is not authorship.** Receipts are not signed. The chain says the log was not
edited after the fact; it says nothing about who wrote any receipt, and nothing here is
evidence of origin. Signing is not in this version.

**It is not tamper-proof.** The head lives in the same database as the receipts, so an
administrator who can rewrite every row can recompute the chain and it will verify. What the
chain raises is the cost of *changing* history while keeping it: rewriting one receipt means
rewriting every receipt after it and the head.

**It does not detect erasing the end.** Deleting the last receipts and rewinding the head is
two statements and leaves a chain that verifies. An anchor outside the database would close
that, and there is none. This is asserted by a test rather than argued, so the sentence cannot
quietly become optimistic.

**It does not prove every action wrote a receipt.** A receipt whose write failed leaves no gap
in `seq` and is invisible to the chain by construction. The events log is where that is
reconciled.

## Where it is checked

* `ctrlrun receipts --verify-chain`, on either store backend, including through `--store-url`.
* `ctrlrun verify`'s G11, *an altered receipt is detected*, against your own configuration.
* On Postgres, `put_receipt` takes the head row's lock first, so concurrent writers cannot
  interleave into a chain that then fails to verify.

## What to do with it

Run `--verify-chain` where you already run integrity checks, and treat a break as an incident
about the store rather than about CTRLRun: the chain is the alarm, not the lock. If you need
evidence of origin rather than of integrity, sign or anchor the receipts outside the database
yourself; they are portable JSON, one object per line, for exactly that reason.

## Next

* [Receipts and evidence](/concepts/receipts-and-evidence): what a receipt holds.
* [Threat model](/THREAT_MODEL): what remains open, in full.
* [Get started](/get-started/quickstart) · [Why](/why).


## Related topics

- [Receipts and evidence](/concepts/receipts-and-evidence.md)
- [Receipt and event schemas](/reference/receipt-and-event-schemas.md)
- [Frequently asked questions](/faq.md)
- [Architecture](/ARCHITECTURE.md)
- [Use the docs from your editor](/mcp/use-the-docs-from-your-editor.md)
