# The Audit Ledger Format The ledger is the constitution's memory: an append-only, hash-chained record binding every governance event — proposals, ballots, tallies, ratifications, fork declarations, registry changes — into one verifiable history. It is the same ledger the funding pool's money flows through, by design: votes and funds, one chain, one audit story. This document is the format specification implemented by `govtool.ledger` and `govtool.canonical`. ## Design constraints 1. **Append-only.** No entry is ever modified or deleted. Corrections are new entries referencing what they correct. 2. **Offline-verifiable.** Anyone with the file, the citizen registry, and `govtool` (or ~100 lines of any language) can verify the entire chain. No server, no trust in CI. 3. **Byte-deterministic.** Hashes and signatures are computed over a canonical serialization, so verification is identical on every machine. 4. **Greppable.** One JSON object per line (JSONL). The audit tool of last resort is `grep`, and that's a feature. ## File layout The ledger is a single JSONL file (`ledger/ledger.jsonl`). Each line is one entry. Line order is chain order; the `seq` field is redundant with line number and both are checked. ## Entry envelope Every entry has the same envelope: ```json { "seq": 42, "ts": "2024-06-01T12:00:00Z", "type": "ballot", "payload": { ... }, "author": "citizen:alice", "sig": "", "prev": "", "hash": "" } ``` | Field | Description | |----------|-------------| | `seq` | 0-based position in the chain. Must equal previous `seq` + 1. | | `ts` | UTC timestamp, RFC 3339, `Z` suffix, second precision. Must be ≥ previous entry's `ts` (monotonic non-decreasing). | | `type` | Entry type (see registry below). | | `payload`| Type-specific body. | | `author` | Citizen id of the signer, or `system:gate` / `system:genesis` for tool-generated entries. | | `sig` | Ed25519 signature over the canonical **signing payload** (see below). For citizen entries, verifies against the registry key; `system:*` entries verify against the repository's gate key committed in the registry. | | `prev` | `hash` of the previous entry. Genesis uses 64 zero hex chars. | | `hash` | SHA-256 (hex) of the canonical **hashing payload** of this entry. | ### Canonical serialization Implemented in `govtool.canonical`. The canonical form of any value is JSON with: keys sorted lexicographically at every level, no insignificant whitespace (`,` and `:` separators), UTF-8, no NaN/Infinity, integers only (no floats anywhere in governance data — parameters that look fractional, like thresholds, are stored as ratio pairs, e.g. `{"num": 2, "den": 3}`). - **Hashing payload:** the entry with the `hash` field removed. `hash = sha256(canonical(entry_without_hash))`. - **Signing payload:** the entry with both `hash` and `sig` removed. `sig = ed25519_sign(canonical(entry_without_hash_and_sig))`. So the hash covers the signature (signature stripping is detectable), and the signature covers everything else including `prev` and `seq` (a signed entry cannot be replayed at a different chain position). ## Entry types ### `genesis` First entry of any chain. Payload: constitution version, kernel file digests, and — for forks — the upstream url, commit, version, and upstream ledger head hash (see [forking.md](forking.md)). Signed by `system:genesis`. ### `proposal` ```json { "proposal_id": "prop--", "pr": 17, "title": "Lower userland-patch quorum to 20%", "diff_digest": "", "classification": "kernel-major", "window": { "open": "...", "close": "..." }, "base_commit": "", "registry_snapshot": "" } ``` `registry_snapshot` freezes the eligible voter set (see [pipeline.md](pipeline.md)). Signed by the proposing citizen. ### `ballot` ```json { "proposal_id": "prop-17-a1b2c3d4", "diff_digest": "", "voter": "citizen:bob", "choice": "yes", "cast_at": "2024-06-03T09:14:00Z" } ``` Signed by the voter. `voter` must equal the envelope `author`. The bound `diff_digest` means a ballot is consent to an exact text, not to a PR number. ### `tally` Written by the gate (`system:gate`) at window close — **pass or fail**: ```json { "proposal_id": "prop-17-a1b2c3d4", "eligible": 12, "participated": 9, "counted": { "yes": 7, "no": 1, "abstain": 1 }, "rejected_ballots": [ { "seq": 38, "reason": "BALLOT_OUT_OF_WINDOW" } ], "superseded_ballots": [31], "quorum": { "required": {"num": 1, "den": 2}, "met": true }, "threshold": { "required": {"num": 2, "den": 3}, "met": true }, "passed": true } ``` Rejected and superseded ballots are referenced by their ledger `seq` — every exclusion is itself auditable. ### `ratification` Written by `system:gate` after merge: ```json { "proposal_id": "prop-17-a1b2c3d4", "tally_hash": "", "merge_commit": "", "version_from": "0.2.0", "version_to": "1.0.0", "latency_seconds": 432000 } ``` `latency_seconds` (proposal registration → ratification) feeds the public release cadence counter — the number that sits next to the incumbent's 203 years. ### `registry` Citizen enrollment/status change, written when a registry amendment ratifies. Payload: citizen id, public key (base64 raw Ed25519), action (`enroll`/`suspend`/`reinstate`), and the ratification entry hash that authorized it. Registry entries with no authorizing ratification (other than genesis bootstrap) fail verification. ### `fork` Declares a fork publicly in the *upstream* ledger (optional but encouraged — Article 7 grants forking without permission; declaring is courtesy plus provenance). Payload: fork name, repo url, forked version/commit. ### `note` Free-form annotation (e.g., linking an exploit report to the proposal it affects). No governance effect; verified like any entry. ## Verification algorithm `govtool ledger verify` (and check 5 of the gate) verifies, per entry: 1. line parses as JSON; canonical re-serialization round-trips byte-identically 2. `seq` increments by exactly 1; `ts` is monotonic non-decreasing 3. `prev` equals the previous entry's `hash` (genesis: 64 zeros) 4. `hash` equals sha256 of the canonical hashing payload 5. `sig` verifies against the author's key — resolved from the registry *as of that point in the chain* (keys are themselves chain history, so key rotation and enrollment ordering are enforced) 6. type-specific payload schema validates 7. cross-references resolve: ballots → existing proposals (matching digest), tallies → proposals, ratifications → tallies (matching hash), registry entries → authorizing ratifications Total failure isolation: verification reports *every* defect with the offending `seq`, not just the first. ## What the ledger does and doesn't promise - **It detects tampering; it does not prevent it.** A hostile maintainer can rewrite the file — but not without breaking the chain for everyone holding an earlier copy. Mitigation is replication: every fork, every CI run, every citizen's clone is a checkpoint. (Anchoring head hashes to an external timestamping service is deliberately out of scope for this milestone and tracked for a later one.) - **It is public by constitutional requirement** (Article 8). Privacy- preserving voting is a real, open design question — v0 chooses radical legibility and says so out loud, because secret ballots and offline- verifiable one-person-one-vote tallies are in genuine tension. Expect this to be one of the first contested amendments. Good.