Skip to main content

Module chain_validator

Module chain_validator 

Source
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 integrityrecord[i].previous_record_digest == digest(record[i-1]), step_seq strictly +1, genesis previous_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_id never 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.

Structs§

DegradedHop
A hop whose strict record decode failed but whose identity fields survived — the C7 marking.
RuleReport
One rule’s verdict on one segment.
SegmentReport
One operation’s chain, judged independently.
SessionStream
One session-log file, classified: its events in append order plus the count of blobs that were not JSON objects at all.
ValidationReport

Enums§

EvidenceEvent
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_id did 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_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_started delimits the run its following attempts belong to). Streams never cross-join: fingerprint and route-stability checks are per-stream.