Skip to content

feat(dynamic-workflow): tamper-evident integrity ledger for repair_cache and events - #48

Open
modacker wants to merge 1 commit into
MiniMax-AI:mainfrom
modacker:community/integrity-ledger
Open

modacker wants to merge 1 commit into
MiniMax-AI:mainfrom
modacker:community/integrity-ledger

Conversation

@modacker

@modacker modacker commented Sep 17, 2026

Copy link
Copy Markdown

What changes

Dependency note: the pre-existing wait-polling race in checks/workspace-router.check.mjs (fixed by #44, which should merge first) will occasionally flake this PR's test run on fast machines — every failure we observed locally was that known race, never an integrity test.

Implements the integrity ledger proposed in #46: tamper-evident hash chains over the append-only surfaces (repair_cache inserts and events), 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

  • Two per-database chains: events (seq order) and repair_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 existing settings table (integrity_events / integrity_repair as {head, upto}).
  • Per-row ledger: a new 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).
  • Crash-safe writes: 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.
  • Verify on demand: workflow_status (list form) always carries a light integrityHeads field; passing verifyIntegrity: true triggers a full recomputation and returns an integrity report per surface: {head,upto,verified,checked,unchained,firstDivergence}. verified is three-valued: true / false / null (nothing anchored yet). Rows beyond upto are reported as unchained — an honest window, not a false tamper verdict.
  • Zero migration: the ledger table is 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_status changes from a bare array to {runs, integrityHeads, ...} — a bare JSON array cannot carry the added fields. The tool description documents the shape.

Test evidence

  • New checks/integrity.check.mjs: 8 tests covering chain anchoring, byte-level tamper detection + healing, deleted-row detection, forged-head detection, honest unchained window, implicit commit of pre-existing rows, tool-layer schema/fields, and end-to-end repair flow.
  • TDD order: tests landed first and verified red (8/8 fail on the missing API) before implementation; 6/8 green on first implementation; the 2 failures correctly rejected the weaker divergence-localization design, which was upgraded to the per-row ledger (documented above).
  • Full plugin suite: 80/80 on green runs (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 build byte-reproducible, repository validator green. One existing assertion migrated for the new list-form shape (workflow_status consumer in checks/workspace-router.check.mjs).
  • Developed under an SDD + TDD discipline with an independent test cluster and implementation cluster converged against one contract (design record: sgmov/sih-engine sih/state/plan/integrity-ledger-parallel.md).

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

- 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Design discussion: tamper-evident reuse results (hash-chained repair_cache/events)

1 participant