An auditor sent our evidence export back with a single line: none of these hashes check out.
They were right. Nothing had been tampered with. We had pretty-printed the file on the way out.
The log is an append-only chain. Each record carries its sequence number, the hash of the record before it, and its own hash. Checking it is supposed to be something you can do with a hashing tool and no access to us.
Except what we hashed was a canonical form (sorted keys, no undefined values, no whitespace), and what we shipped was the same data re-serialized for human eyes. Same objects, different bytes. Hashes are over bytes.
That cost us a round trip with the auditor and a day of proving that a formatting change was a formatting change.
Now the exporter and the hasher share one function. The file is JSON Lines, one canonical record per line. A line with its hash field removed is exactly the byte string that was hashed. You can check a record where it sits, without knowing anything about our code.
The second change was less obvious.
Our verifier used to skip records whose format it did not recognize (newer writer, older reader) and return ok. "Verified" quietly meant "nothing in here was understood."
Now an unknown format or an unknown hash algorithm is a failure rather than a skip. The verifier checks in order: the sequence number equals its position, the previous hash links to the record before it, the format is one this version reads, the algorithm is one this version computes, and the recomputed digest matches the stored hash. First failure wins, and it comes back with the index it broke at and a reason, not a boolean.
A verifier that cannot read a record has no business vouching for it.
What this still does not do is stop anyone editing the file. Nothing does. The chain makes the edit show and names the entry where it happened, and that is the whole promise, worth being precise about, because what people hear is "tamper-proof" and what they are getting is "tamper-evident".
This lives in our open-source project disclosurekit, where the same log records each assessment and each disclosure actually shown to a user.
If you keep an audit log, hand it to someone outside your team and watch them verify it without you in the room.