feat(delivery): carry pre-ledger delivery attempts forward through a boundary arm - #485
Merged
schickling-assistant merged 1 commit intoSep 6, 2026
Conversation
…boundary arm
The newest-format ledger ignored `delivery-state.json`, so upgrading a seat
with an in-flight attempt dropped the only evidence that attempt existed and
the first pass after the upgrade re-sent it. Translate that record exactly
once, when no ledger file exists, into an asserted entry that holds the
delivery and authorizes no transport.
Canonical `src/delivery_ledger.rs` keeps one schema and gains one version-free
concept, `Attestation{Observed, Asserted}`: a phase this build graded versus a
phase another authority asserted. Every retired wire shape lives in
`src/migrations/delivery_state/{mod,codex_v1,opencode_v1}.rs`, reached through
one statement in `Ledger::open`'s not-found arm. Deletion trigger and its live
query: `docs/vrs/.delta/DELTA-006-delivery-state-v1-arm.md`.
agent-identity: dev3.direct.omp.43sz6ujq
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.1.7
agent-runtime: OMP 18.1.7
tooling-profile: dotfiles@39a19af
11 tasks
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
delivery-ledger.json(#484) ignores the pre-ledgerdelivery-state.jsonrecord. Upgrading a seat that had an attempt in flight therefore dropped the only evidence that the attempt existed, and the first pass after the upgrade re-sent the message. This adds the boundary arm that carries such an attempt forward instead.The record is translated exactly once — when no ledger file exists — into an entry whose phase is asserted rather than observed: it suppresses a duplicate and it authorizes no transport until this build sees evidence of its own. Live example of the class this protects, from a seat on dev3 right now:
{"schema":"st2.opencode-delivery-state.v1","agent":"dev3.effect-utils.deps.pnpm-catalog.worker", "sessionId":"ses_f991e1f40ffezqotaZ64Q8QQ2h","filename":"1788438569588-fkdm5c.md", "messageId":"msg5865fa445127136869744674c2","phase":"accepted"}Five such records exist on this host (2 opencode, 3 codex) and no
delivery-ledger.jsonexists anywhere yet, so every one of them is an attempt the next upgrade would otherwise have re-sent or forgotten.Why this shape
Decision Q17/Q18: a boundary arm is the default for a format the newest release retired, and canonical code may gain a version-free word for a distinction a legacy record makes — never a version- or adoption-named field.
Canonical
src/delivery_ledger.rskeeps one schema (st2.delivery-ledger.v1) and gains exactly one concept,Attestation{Observed, Asserted}onEntry: a phase this build graded throughProfile::gradedversus a phase another authority asserted. An assertion bounds what already happened (so it holds), and is not evidence (so it sends nothing).begin,recordandnegativeall promote an entry back toObserved, so this build's own observation is what clears a carried claim — including aNegativeReceipt::Absentfrom Codex's resume sweep or OpenCode's 404 read-back, the only receipts that re-authorize the same identity.Coupling, exhaustively: canonical → boundary is one call; boundary → canonical is types +
asserted(); drivers → boundary is nothing (production or test).The two harnesses'
acceptedlabel meant different things and nothing on disk said which — Codex wrote it only from the typed in-turnitem/completed{userMessage, clientId}(the model received it →Phase::Consumed, which releases), OpenCode fromGET /session/{s}/message/{m}returning 200 (the server stored it →Phase::Persisted, which holds). That asymmetry lives in the two version files and nowhere else.Entry::originfrom the prototype is dropped: the deletion trigger's second clause is answerable fromattestationalone (any(. == "asserted")), so an uninterpreted free-text field on the canonical type buys nothing.Deletion trigger (Q8: delta plus live query)
docs/vrs/.delta/DELTA-006-delivery-state-v1-arm.md, referenced at the seam asDELETION TRIGGER: docs/vrs/.delta/DELTA-006. Its Resolution Signal is two commands that must print nothing on every admitted host for seven days: nodelivery-state.jsonleft under any codex/opencode state dir, and no ledger entry still carrying an asserted phase.axe vrs check --profile strict docs/vrsreports 104 errors, all pre-existing (identical count with the new file removed; they are decision/experiment/link shapes onmain).Deletion cost, measured.
mv src/migrations /tmp && sed -i '/^pub mod migrations;$/d' src/lib.rs:cargo check --lib: 1 error,E0433atsrc/delivery_ledger.rs:260— the seam. The fix isOk(()), which is byte-for-byte a first run on a fresh seat.cargo check --lib --tests: still 1 error — the boundary's seven tests live inside the deleted directory, and the canonicalasserted/seedtest does not reference it.Accepted hole (Q2: previous-release rollback)
Roll back to a pre-ledger release → it writes
delivery-state.json→ roll forward: the ledger file already exists, so the seam does not fire and that attempt is not held. Pinned bymigrations::delivery_state::tests::a_rollback_then_roll_forward_does_not_see_the_record_written_in_between, so changing it is deliberate. Closing it in code costs a second seam (per-filename consultation before a first transport, or merge-on-every-open, which resurrects entries the recipient already archived). Per Q2 it closes by policy when rollback to a pre-ledger release stops being supported — trigger clause 1's second half.Also unchanged and out of scope: the boundary reads a file a rolled-back peer could be writing under no lock. Single-owner-per-state-dir is what makes that safe, as before.
Proof
nix build .#st2 --no-link -L(itscargoTestFlagsrun--lib, so the tests below are inside the gate).New tests:
delivery_ledger::tests::an_asserted_phase_suppresses_a_duplicate_and_authorizes_no_transport— the falsifier for the safety claim:Hold(UnattestedClaim)for retention and retry, durable across reopen, cleared by a negative receipt and by graded evidence.migrations::delivery_state::tests::deletion_trigger_absent_old_record_makes_this_module_a_no_op— the local half of the trigger: no record → no entries, no writes, no state dir created.…::a_carried_forward_attempt_is_an_assertion_that_authorizes_no_transport— a driftedruntimeId(which the old Codex loader hard-errored on) is carried forward and held, keeping the incarnation that made it so no live typed frame can settle it.…::accepted_adopts_at_the_evidence_each_harness_actually_proved,…::translation_happens_once_and_leaves_the_old_record_in_place,…::a_record_belonging_to_someone_else_is_ignored_and_ours_that_lies_fails_closed,…::unreadable_or_unlabelled_bytes_are_ignored_rather_than_quarantining_a_working_pump,…::a_rollback_then_roll_forward_does_not_see_the_record_written_in_between.cargo test --lib: 740 + 17 + 14 + 7 passed, 0 failed.INVARIANTS.md's delivery row gains the carry-forward clause and these test names.Posted on behalf of @schickling
agent_identitysessionagent_personaagent_supervisoragent_toolagent_tool_versionagent_runtimetooling_profile