Conversation
- two per-database hash chains over the append-only surfaces (events by
seq, repair_cache by rowid), digests chained sha256(prev:kind:key:body)
- per-row ledger table integrity_rows records each link in the same
transaction as the insert, so the first divergent row is precisely
locable; heads live in settings as {head,upto}
- store transaction is reentrant (engine.start already wraps both
append points in one outer transaction)
- workflow_status list form carries integrityHeads and accepts
verifyIntegrity for full recomputation; response becomes an object
since a bare JSON array cannot carry the added fields
- zero migration: CREATE TABLE IF NOT EXISTS, lazy first-anchoring
commits pre-existing rows
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 free
to 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.
What changes
Implements the integrity ledger proposed in #46: tamper-evident hash chains over the append-only surfaces (
repair_cacheinserts andevents), so "the results reuse is about to trust are the ones earlier runs actually produced" becomes mechanically checkable. Closes #46.Design constraints honored from the issue discussion: threat model is accidental mutation (agent mistakes), not adversaries; only append-only surfaces are chained; zero schema migration for existing databases; no new MCP tool; no change to any existing behavior or response shape except additive fields.
Design
events(seq order) andrepair_cache(rowid order). Row digest:sha256(prev:kind:key:body)over the exact stored JSON bytes; genesis prev is 64 zeros. Chain heads live in the existingsettingstable (integrity_events/integrity_repairas{head, upto}).integrity_rows(surface,pos,key,hash)table records each link, appended in the same transaction as the insert — this is what makes the first divergent row precisely locable (a single end-anchor alone cannot localize mid-chain tampering; we tried that design first and the test suite rejected it).event()/saveRepairCandidate()wrap INSERT + chain advance in a transaction (the store transaction is now reentrant —engine.start()already wraps both calls in one). The first anchoring write implicitly commits pre-existing rows; later tampering with them is detected.workflow_status(list form) always carries a lightintegrityHeadsfield; passingverifyIntegrity: truetriggers a full recomputation and returns anintegrityreport per surface:{head,upto,verified,checked,unchained,firstDivergence}.verifiedis three-valued:true/false/null(nothing anchored yet). Rows beyonduptoare reported asunchained— an honest window, not a false tamper verdict.CREATE TABLE IF NOT EXISTS; existing databases upgrade lazily on first write, old rows are implicitly committed by the first anchoring write.Note: the list form of
workflow_statuschanges from a bare array to{runs, integrityHeads, ...}— a bare JSON array cannot carry the added fields. The tool description documents the shape.Test evidence
checks/integrity.check.mjs: 8 tests covering chain anchoring, byte-level tamper detection + healing, deleted-row detection, forged-head detection, honestunchainedwindow, implicit commit of pre-existing rows, tool-layer schema/fields, and end-to-end repair flow.72 + 8 new; the one intermittent failure is the pre-existing race from fix(dynamic-workflow): deterministic wait polling and checkpoint lineage in repair reuse #44's description, never an integrity test), packaged MCP smoke passes,npm run buildbyte-reproducible, repository validator green. One existing assertion migrated for the new list-form shape (workflow_statusconsumer inchecks/workspace-router.check.mjs).sih/state/plan/integrity-ledger-parallel.md).Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.