Instance-ledger kernel: signed, hash-chained, append-only history (SPEC-003 v1) - #389
Merged
Conversation
…tory (SPEC-003 v1) The record that will let `ashlar verify` say CERTIFIED with a real signature instead of VERIFIED · unsigned. An append-only, hash-chained, signed history under .ashlar/ledger/, one JSON file per entry: each is Ed25519-signed (SPEC-006 keys) and carries the hash of its predecessor, so modifying, inserting, or reordering the past is detected and refused loudly — the same fail-closed stance as the gate store, on the same principle that a forged history is worse than a missing one. Verification is intrinsic (each entry carries its own key), so a keyless reader still validates the whole chain; append verifies the existing chain BEFORE extending it, so a fresh entry cannot bury a broken one. Honest about v1 scope: tail truncation is not detectable without an external anchor (v2; guarded meanwhile by the policy's truncate_ledger never-entry), and the signer is the local operator key, not an org trust root (v2). docs/InstanceLedger.md states both plainly. Reuses the gate store's proven shapes — a FileShare.None cross-process append lock, temp-then- rename writes, fail-closed reads — and the same CanonicalJson + Ed25519 machinery. Adversarially reviewed across four lenses (chain integrity, canonicalization/hash determinism, append race, fail-open); zero confirmed bugs. Applied its refuted-but-worthwhile hardening: collision-proof Subject (hash each document then combine, no delimiter assumption), numeric file ordering with a foreign-file fail-close, a File.Move collision normalised into the fail-closed contract, and stray-temp sweeping under the lock. Kernel signing tests unaffected; 11 new ledger tests (genesis, chaining, tamper/gap/reorder/foreign-file refusal, keyless read). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
IanFrelinger added a commit
that referenced
this pull request
Aug 24, 2026
…-003 wiring) (#390) The payoff of the signing arc. `ashlar verify` no longer prints "unsigned" when a key exists — it appends a signed entry to the instance ledger (#389) and renders CERTIFIED · signed ed25519:… · ledger #N. The trust model becomes a concrete, visible artifact. - provenance course (ProjectVerifier): joins the run only once a signed ledger exists and checks that chain via InstanceLedger.VerifyChain, fail-closed — a tampered ledger fails verification (exit 65), so `run` over a forged history is refused too. A keyless project stays at three courses and reads unsigned; zero-setup is untouched. - InstanceLedger.VerifyChain(): a synchronous form, since the verifier runs courses synchronously. The async API and its 11 kernel tests are unchanged. - VerifyCommand: async; on a passing verify with a key present, append a signed verification entry (subject = hash of the exact documents) and render CERTIFIED with the fingerprint and sequence; no key -> VERIFIED unsigned as before; corrupt key -> fail closed (exit 1); a ledger that turns corrupt between the provenance course and the append -> refused (exit 65). e2e-loop 70/70 (real binary): certifies with a key, writes a signed entry, second run adds provenance and extends to #2, tampered ledger refused at 65 — keyless verify still unsigned at three courses. Kernel 360/360 incl. new provenance tests. Adversarially reviewed (fail-closed + keyless-regression lenses); zero confirmed findings. Co-authored-by: PlzTouchGrass <130718671+PlzTouchGrass@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The kernel that will let
ashlar verifysay CERTIFIED with a real signature instead of VERIFIED · unsigned. An append-only, hash-chained, signed history under.ashlar/ledger/— the read side of the same trust model the gate store (#386–#388) writes.What landed (src/ + docs/ only — kernel-first, clean layer gate)
InstanceLedger— one Ed25519-signed JSON entry per verification, each carryingPrev= the hash of its predecessor's canonical bytes.VerifyChainchecks contiguous sequence, every signature, and every link, and throws (fail-closed) on any break; append verifies the existing chain before extending it, so a fresh entry can't bury a broken one. Verification is intrinsic — a keyless reader validates the whole chain.FileShare.Nonecross-process append lock, temp-then-rename writes, fail-closed reads, and the SPEC-006CanonicalJson+ Ed25519 machinery.docs/InstanceLedger.md— the on-disk format and an honest integrity statement.Honest v1 scope (documented, not pretended)
truncate_ledgernever-entry.Review + verification
Adversarially reviewed across four lenses (chain integrity, canonicalization/hash determinism, append race, fail-open) — zero confirmed bugs. Applied its refuted-but-worthwhile hardening: collision-proof
Subject(hash each document then combine), numeric file ordering with a foreign-file fail-close, aFile.Movecollision folded into the fail-closed contract, and stray-temp sweeping under the lock. 11 ledger tests (genesis, chaining, tamper/gap/reorder/foreign-file refusal, keyless read); kernel signing tests unaffected.Next
The wiring slice: a
provenancecourse inProjectVerifierthat runsVerifyChain,verifyappending a signed entry on success, and the CERTIFIED display inVerifyCommand.