ADR-037: Offline witness checkpoint + append-only consistency proof
Date: 2026-06-18 Status: Accepted Author: Rômulo Febasi
SYN-270. Closes the gap ADR-026/030 explicitly leave to remote comparison. Companion to ADR-026 (tamper-evident audit), ADR-030 (git substrate), ADR-035 (verify report). Grounds:
docs/researchs/2026-06-16-provable-non-corruption-syn-verify.md(O3).
Context
ADR-026 makes the audit log tamper-evident (per-author hash-chain + a signed head checkpoint) and ADR-030 makes git the integrity substrate. Both note an honest ceiling: a lone local clone cannot detect its own owner’s rewrite: a force-push or a mid-log edit-then-recheckpoint: because the attacker controls every local artifact. ADR-026/030 leave that to a remote witness (a push-protected remote sees the old history).
The research (O3, after Go sumdb / Sigsum / RFC 9162 consistency proofs) identifies a local analogue: cache a signed tree-head and later prove the current state extends it. The verifier holding a prior checkpoint is the witness: exactly the offline single-user case.
Decision
syn audit witness emits a tiny ed25519-signed synapse.audit-witness/1
checkpoint: the git HEAD, and per author the segment size + a prefix_hash
(sha256 over the canonical bytes of the first size entries), plus the total
count and a timestamp. It is signed with the user’s existing identity (reuses
the receipt/report signing path: no new crypto, no new deps). The user
publishes it (commit it, post it, email it).
syn verify --since <witness> adds INV-12: prove the current audit
history is an append-only extension of the witness,
- git ancestry (when versioned): HEAD is the witnessed commit or descends
from it (
gixrev-walk). A force-push that drops the witnessed commit fails here. - segment prefix stability: for every witnessed segment, the current
author segment has
>= sizeentries and its firstsizeentries re-hash to the witnessedprefix_hash. A truncation shrinks the count; a mid-log rewrite moves the hash. Either fails.
Both checks are offline and dep-free. The check runs over read_all
(live + archive), so retention rotation does not weaken it.
Consequences
- Improves: force-push / history-rewrite is now detectable locally, without a remote: the gap ADR-026/030 deferred. A published witness lets a third party hold the owner to their history (the witness property a remote used to be required for). Zero new dependencies.
- Worsens / limits: still tamper-evident, not tamper-proof: the
witness is only as trustworthy as where it was published. A witness an
attacker can also rewrite (e.g. an unpublished local file they control) is no
stronger than the chain it summarises; the value is in publishing it
somewhere the owner cannot quietly change.
verifysurfaces this in the trust-root caveat. - Open: a future
audit witness --publishcould push the checkpoint to a conventional location (a gist, a transparency endpoint); deferred, the file- manual publication is enough for single-user and shared-git today.
Alternatives considered
- Require a remote to detect rewrites (ADR-026/030 status quo). Works only online and only when a push-protected remote exists; the witness file gives the same property offline and for a third party.
- Run a transparency log (Rekor/Trillian/Sigsum server). Rejected by the governing discipline (borrow the invariant, refuse the engine): a network service contradicts offline-first and single-user. The consistency proof is adopted; the server is not.
- Byte-compare the whole audit file against a stored copy. Brittle across retention rotation and legitimate appends; the per-segment prefix hash + git ancestry is rotation-stable and proves the precise append-only property.
- A Merkle tree over entries for inclusion proofs. Overkill for single-user (no third party requesting selective inclusion); a prefix hash over the witnessed range is sufficient and simpler.