What you're trying to do
audit.log.jsonl is "append-only by design" (see CONTRIBUTING) and is the
trust anchor for the review gate — every approve/reject/supersede lands an
AuditEvent. But "append-only" is currently a convention, not a property:
audit.log_event simply opens the file in append mode and writes a JSON line,
and AuditEvent carries no link to the prior event. Any process (a buggy
importer, a malicious agent with filesystem access, a bad merge) can rewrite,
reorder, or delete history and nothing detects it. For a review-gated KB whose
whole pitch is "a human approved this," a tamper-evident log is the natural
backstop.
Suggested shape
- Extend
AuditEvent with prev_hash: str and hash: str, where
hash = sha256(prev_hash + canonical_json(event_without_hash)) — a Merkle-style
chain over the log.
log_event reads the last line's hash, sets it as prev_hash, computes and
stores hash. Genesis event uses a fixed zero prev_hash.
vouch doctor (or a new vouch fsck check) re-walks the chain and reports the
first broken link with its line number — audit chain broken at line N.
kb.audit optionally returns _meta.chain_ok: bool.
Acceptance
- Tampering with any historical line (edit a field, delete a line, reorder)
makes vouch doctor report the exact break point.
- An untouched log verifies clean; verification is O(n) over the file.
- Existing logs without hashes are detected and can be sealed forward from the
current tip (documented one-time migration), so adoption isn't a hard break.
Out of scope
- Cryptographic signing / external notarization (hash-chaining only here).
- Encrypting audit entries (that's a visibility/secrecy concern, orthogonal to
integrity).
What you're trying to do
audit.log.jsonlis "append-only by design" (see CONTRIBUTING) and is thetrust anchor for the review gate — every approve/reject/supersede lands an
AuditEvent. But "append-only" is currently a convention, not a property:audit.log_eventsimply opens the file in append mode and writes a JSON line,and
AuditEventcarries no link to the prior event. Any process (a buggyimporter, a malicious agent with filesystem access, a bad merge) can rewrite,
reorder, or delete history and nothing detects it. For a review-gated KB whose
whole pitch is "a human approved this," a tamper-evident log is the natural
backstop.
Suggested shape
AuditEventwithprev_hash: strandhash: str, wherehash = sha256(prev_hash + canonical_json(event_without_hash))— a Merkle-stylechain over the log.
log_eventreads the last line'shash, sets it asprev_hash, computes andstores
hash. Genesis event uses a fixed zeroprev_hash.vouch doctor(or a newvouch fsckcheck) re-walks the chain and reports thefirst broken link with its line number —
audit chain broken at line N.kb.auditoptionally returns_meta.chain_ok: bool.Acceptance
makes
vouch doctorreport the exact break point.current tip (documented one-time migration), so adoption isn't a hard break.
Out of scope
integrity).