Expand description
P7-S5 · the chain validator (P2 §5 rules C1–C4 + C7). Host-ops tooling — CI and incident triage run the same knife — never part of an SDK runtime path. P7-S5 · the chain validator, batch 1: rules C1–C4 with C7 degradation marking (P2 §5).
Host-ops tooling, not an SDK runtime path: CI gates and incident triage run the same knife,
and C3 needs the deterministic transition (re-plan), which only the core can perform. The CLI
half is src/bin/ds-chain-validator.rs; this module is the verdict logic.
Input is a journal prefix — a sequence of opaque record byte blobs. Records are grouped into per-operation chain segments and every segment is judged independently. Nothing here ever re-serializes a record: blobs pass through untouched, so a self-digest verdict is a verdict about the bytes the host durably wrote.
The rules, and where each one gets its teeth:
- C1 · chain integrity —
record[i].previous_record_digest == digest(record[i-1]),step_seqstrictly +1, genesisprevious_record_digest = None. Complete segments go through [verify_record_chain]; a segment with degraded hops falls back to checking every link whose digests survived. - C2 · input idempotency — one
input_idnever yields two different records: a retry must reach the same record. Grouped per operation (the idempotency key’s namespace). - C3 · causal closure — every record’s resolved effect must be reproducible by
re-planning the earlier records. This is the §12.2 restore ladder’s genesis leg
([
restore_operation] with no checkpoint): chain verify + deterministic re-plan + per-step record-digest comparison. It doubles as the re-plan determinism regression gate — the direct gate for 0.2.62-class “this binary does not reproduce the history it is resuming” incidents. If C1 failed, C3 reports degraded rather than re-reporting the same break. - C4 · task lineage — the journal-direct half: every
(task_id, attempt_id)launch pair appears at most once (the launch token is derived from that pair, so a repeated pair is a reused token), and a spawn resolution names an effect the same operation published at an earlier step. The parent chain itself is not journaled; it holds structurally under C3’s re-plan because an orphan spawn has no outstanding effect to resolve. The durable launch-token ledger lives in checkpoints — batch 2 territory. Both limits are named in [ValidationReport::deferred]. - C7 · degradation — an old-format hop (strict decode fails but the identity fields survive) degrades the checks that need the missing fields instead of failing them. A proven digest mismatch fails C1 even when identity fields survive; every degraded hop is marked on its segment’s report. A blob that is not a record at all counts as unparseable input, which is an exit-code-2 condition (“evidence insufficient”), never a violation.
§Batch 3 · the SessionLog input plane (0.2.64 S4)
[validate_with_session_log] adds a second plane: SessionLog event streams. SessionLog is
Evidence Truth (P6 §S) — never recovery authority, and never kernel input. Where the journal
plane is order-independent blobs, a session log is one file’s append-ordered events, so the
input is a list of streams (one per file) whose internal order is preserved.
The core has no typed SessionLog vocabulary (P6: the core treats SessionLog as opaque JSON),
so events are classified leniently: the kind field picks the extraction shape, missing
additive fields parse as absent, and both spellings of host-nested fields are accepted
(route.routeId from node, route.route_id from python). Unknown kinds are parseable but
ignored — the vocabulary evolves; only C6/C8-relevant kinds are extracted. An event that is
not a JSON object at all counts as unparseable (exit-code-2), exactly like the journal plane.
C7 carries across planes: old logs simply lack provider_attempt / the additive fields —
the rules that need them degrade, never fail.
§Batch 2 · the checkpoint input plane (0.2.65 S1)
[validate_with_checkpoint] adds the third plane: one or more logical checkpoints (§12).
A checkpoint is a claim about the journal — “this logical state was captured at step N,
anchored by these digests” — and C5 is the rule that makes the claim answer to the bytes.
Without a checkpoint input, C5 is deferred, not red (the C7 philosophy: a plane nobody
handed over cannot fail).
- C5a · checkpoint anchoring — the checkpoint’s
genesis_digestnames the journal’s genesis record, its covered head names the record atthrough_step_seq, and every bounded-tail entry whose journal record survives carries that record’s digest. A present record with the wrong digest is a proven contradiction (fail); a pruned or missing record is unverifiable (degrade) — retention is not a crime. - C5b · the launch-token ledger — the durable half of C4: within one checkpoint the
same launch token may not name two mints at different steps (reuse across
TaskLaunchpayloads), every pendingSpawnTaskseffect must carry tokens the ledger registered at the effect’s own step, and no ledger entry may sit beyond the covered boundary. Under--strictthe re-plan fold must re-derive the exact ledger. --strict· the re-plan replay — the journal is folded from genesis through the covered step through the same restore path C3 uses, and the re-derived checkpoint must carry the checkpoint’sstate_digest; the checkpoint+tail restore ladder must also hold against the journal above the covered step. Cost is one full fold — explicit request only.
Structs§
- Degraded
Hop - A hop whose strict record decode failed but whose identity fields survived — the C7 marking.
- Rule
Report - One rule’s verdict on one segment.
- Segment
Report - One operation’s chain, judged independently.
- Session
Stream - One session-log file, classified: its events in append order plus the count of blobs that were not JSON objects at all.
- Validation
Report
Enums§
- Evidence
Event - A SessionLog event, leniently classified. Only the kinds C6/C8 read are extracted; every
other kind — known or future — is
Other. Field absence is data (C7 degrades), not error. - Verdict
Constants§
- UNATTRIBUTED_
SEGMENT - The pseudo-segment for degraded hops whose
operation_iddid not survive. Kept obviously synthetic so a report reader never confuses it with a real operation.
Functions§
- validate_
journal - Validate a journal prefix: a sequence of opaque record byte blobs, in any order. Records
group into per-operation segments, each judged independently; blob order never matters
because the chain’s own
step_seq/digest links define the order. - validate_
with_ checkpoint - Batch 2 entry point: the journal plane plus whichever evidence planes the caller holds.
An empty
session_streamsmeans journal-only; an emptycheckpoint_blobsmeans C5 is deferred, not run.strictarms the re-plan replay (C5’s--strict): each checkpoint’s journal prefix is folded from genesis through the covered step and both the state digest and the launch-token ledger must re-derive exactly. Strict costs one fold per checkpoint and is meaningless without checkpoint blobs. - validate_
with_ session_ log - Batch 3 entry point: the journal plane plus SessionLog evidence streams. Each inner slice
is one session-log file’s events in append order — unlike journal blobs, event order
within a stream is meaningful (a
run_starteddelimits the run its following attempts belong to). Streams never cross-join: fingerprint and route-stability checks are per-stream.