Check the chain
The verifier recomputes every receipt from its own contents and carries the recomputed hash forward. It trusts none of the stored hashes, which is the whole point: a chain where tampering does not propagate is just a list.
The genuine chain — accepted
Recomputed from the receipts alone.
The same chain with receipt 1 edited — rejected
One number changed. The check catches it twice: the edited receipt no longer hashes to what it carries, and the receipt after it points at a hash nothing produces.
| # | Kind | Detail |
|---|---|---|
| 1 | hash-mismatch | contents hash to 6d2265c6d4…f3d2, receipt claims ff03fccb3b…e721 |
| 2 | broken-link | points at ff03fccb3b…e721 but the receipt before it hashes to 6d2265c6d4…f3d2 |
Notice that the claimed head is the same in both. It would be: it is a number stored on the last receipt, and an editor has no reason to change it. A stored head proves nothing on its own, which is exactly why the check recomputes rather than compares.
Run it yourself
git clone https://github.com/sumplus-real/sumplus-steward cd sumplus-steward && python run.py --audit
A verifier that always says yes is worth nothing, so the test suite asserts both halves of the break. Weakening the verifier on purpose turns it red; that was checked rather than assumed.