IPX: fingerprint the consumed spool prefix in replay checkpoints #199

Merged
mara merged 2 commits from fix/issue-182 into master 2026-09-08 01:34:45 +00:00
Collaborator

Fixes #182

Bug

replay-ipx-http-spool resumed purely from the stored byte offset of the latest capture checkpoint. Nothing tied that offset to the actual spool file content, so a replaced, restored-from-backup, or re-exported spool file with the same operation/capture-session/source identity was silently decoded from unrelated bytes into canonical exchange evidence.

Fix

  • make-capture-checkpoint-record gains validated optional spool-fingerprint (SHA-256 hex of the consumed spool prefix [0,offset)) and spool-size payload fields.
  • ipx-persist-checkpoint computes and records both for every new checkpoint.
  • replay-ipx-http-spool verifies before resuming:
    • current file missing or shorter than the recorded size -> the new exported ipx-spool-fingerprint-mismatch condition;
    • prefix-content fingerprint mismatch -> the same typed condition.
  • Legacy checkpoints without a fingerprint still replay under the size check only, so pre-fix databases keep working.

RED-first verification

Two regression tests added to tests/ipx-replay.lisp: after a checkpoint, replacing the spool with different content and shortening it below the recorded offset must each signal ipx-spool-fingerprint-mismatch instead of decoding garbage.

Local exact-head core gate (mirror of core.yml, pinned deps): all ten Hackmode test suites pass at commit time, including the new regressions. ironclad declared in hackmode.asd (already a transitive starintel dependency).

Boundary

Replay/checkpoint correctness only. No capture-provider, expert, or database authority changes; no API behavior change for fingerprint-carrying checkpoints.

Fixes #182 ## Bug `replay-ipx-http-spool` resumed purely from the stored byte offset of the latest capture checkpoint. Nothing tied that offset to the actual spool file content, so a replaced, restored-from-backup, or re-exported spool file with the same operation/capture-session/source identity was silently decoded from unrelated bytes into canonical exchange evidence. ## Fix - `make-capture-checkpoint-record` gains validated optional `spool-fingerprint` (SHA-256 hex of the consumed spool prefix `[0,offset)`) and `spool-size` payload fields. - `ipx-persist-checkpoint` computes and records both for every new checkpoint. - `replay-ipx-http-spool` verifies before resuming: - current file missing or shorter than the recorded size -> the new exported `ipx-spool-fingerprint-mismatch` condition; - prefix-content fingerprint mismatch -> the same typed condition. - Legacy checkpoints without a fingerprint still replay under the size check only, so pre-fix databases keep working. ## RED-first verification Two regression tests added to `tests/ipx-replay.lisp`: after a checkpoint, replacing the spool with different content and shortening it below the recorded offset must each signal `ipx-spool-fingerprint-mismatch` instead of decoding garbage. Local exact-head core gate (mirror of core.yml, pinned deps): all ten Hackmode test suites pass at commit time, including the new regressions. ironclad declared in hackmode.asd (already a transitive starintel dependency). ## Boundary Replay/checkpoint correctness only. No capture-provider, expert, or database authority changes; no API behavior change for fingerprint-carrying checkpoints.
IPX replay: fingerprint consumed spool prefix in checkpoints (#182)
Some checks failed
agent-pr-serialization / one-open-pr-per-agent-lane (pull_request_target) Failing after 1s
monorepo / hygiene (pull_request) Failing after 21s
agent-framework-boundary / keep-agent-framework-out-of-product-tree (pull_request) Failing after 21s
core / common-lisp-core (pull_request) Failing after 50s
26dd29fd49
Replay resumed purely from a stored byte offset, so a replaced, restored, or
re-exported spool file with the same capture-session/source identity was
silently decoded from the wrong bytes into canonical evidence.

Checkpoints now record a SHA-256 fingerprint and size of the consumed spool
prefix [0,offset). Replay verifies both before resuming: a missing or
shortened file, or a prefix-content mismatch, raises the new exported
ipx-spool-fingerprint-mismatch condition instead of decoding unrelated bytes.
make-capture-checkpoint-record gains validated optional :spool-fingerprint and
:spool-size payload fields; legacy checkpoints without a fingerprint still
replay under the size check only.

RED-first: two regression tests in tests/ipx-replay.lisp replace and shorten
the spool after a checkpoint and require the typed mismatch error. Local
exact-head core gate green at commit time: all ten Hackmode test suites pass.
ironclad is declared in hackmode.asd (already a transitive starintel dep).
ci: retrigger workflows after runner outage (data.forgejo.org DNS)
All checks were successful
agent-framework-boundary / keep-agent-framework-out-of-product-tree (pull_request) Successful in 4s
monorepo / hygiene (pull_request) Successful in 1m9s
core / common-lisp-core (pull_request) Successful in 5m5s
bf37e9139a
mara merged commit 420b788df3 into master 2026-09-08 01:34:45 +00:00
Sign in to join this conversation.
No description provided.