Skip to content

sdk: journal guard combinator enforces reserve-before-effect#629

Merged
mfw78 merged 1 commit into
dev/m1from
feat/609-sdk-guard
Jul 25, 2026
Merged

sdk: journal guard combinator enforces reserve-before-effect#629
mfw78 merged 1 commit into
dev/m1from
feat/609-sdk-guard

Conversation

@mfw78

@mfw78 mfw78 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

What

Adds a Journal::guard combinator to the nexum-sdk keeper: it reserves the submission key with the encoded body, runs the async submit closure, then disposes of the reservation as the closure's Disposition directs (Commit on accept, Release on requires-signing or a terminal refusal, Park { until } on a rate-limit hint, Retain to leave the marker RESERVED for the reconcile pass). The result is a Guarded<T>: Ran(T) when the closure ran, Skipped(Mark) when an existing COMMITTED (idempotent duplicate) or RESERVED (reconcile-owned) marker short-circuited it without running the effect.

Why

The reserve-before-effect, commit-or-release-after pattern is inlined by both the videre-sdk keeper run and the composable-cow run; a hand-rolled caller can mis-sequence it and either run an effect unreserved or strand a reservation. The combinator fixes the ordering by API shape so it cannot be mis-sequenced (#609, ADR-0014). It is purely additive: the existing keeper run, reconcile pass, and composable-cow run are behaviour-unchanged, a commit-write fault stays best-effort (the marker rides to reconcile, never a release), and the Journal's single-key markers stay on plain set.

Testing

nix develop --command just ci green (fmt, clippy -D warnings, doc, wasm module builds, workspace tests), plus just check-venue-agnostic and just check-cow-orderbook-only both green. New unit tests in crates/nexum-sdk/tests/keeper.rs pin the combinator semantics (reserve visible before the effect, commit/release/park/retain dispositions, skip-on-marker, reserve-fault aborts before the effect); new tests in crates/videre-sdk/src/keeper.rs drive it through the reserve/commit/reconcile path with the FlakyCommit and counting-venue fixtures, asserting exactly-once submission and no stranded reservation.

AI Assistance

Implemented with AI assistance under maintainer direction.

Part of #609.

Add Journal::guard to the nexum-sdk keeper: it reserves the submission key with the encoded body, runs the async submit closure, then disposes of the reservation as the closure's Disposition directs (Commit on accept, Release on a known non-accept, Park on a rate-limit hint, Retain for reconcile). The reserve-effect-commit order is fixed by the API shape, so a caller cannot run the effect unreserved or leave the marker unsettled; an existing marker short-circuits without running the closure.

The combinator factors out the pattern the videre-sdk keeper run and the composable-cow run already inline, without changing either; markers stay on plain set. Tests cover the combinator semantics over the mock store and drive it through the reserve/commit/reconcile path with the FlakyCommit and counting-venue fixtures, asserting exactly-once and no stranded reservation.
@mfw78
mfw78 force-pushed the feat/609-sdk-guard branch from 6e5578e to 7905afc Compare July 25, 2026 10:58
@mfw78
mfw78 merged commit 37b82c6 into dev/m1 Jul 25, 2026
7 checks passed
@mfw78
mfw78 deleted the feat/609-sdk-guard branch July 25, 2026 12:28
mfw78 added a commit that referenced this pull request Jul 25, 2026
Rewire submit_ready onto Journal::guard: the six inline journal.mark/reserve/commit/release calls that carry the #572 reserve-before-effect ordering fold into one guard call, with the venue outcome mapped to a Disposition (Accepted commits, requires-signing and known refusals release, an unknown outcome retains for reconcile). Behaviour is identical: all 23 composable-cow run tests including w1/w2/w3 and anti_572 pass unchanged. The remaining code is the CoW-specific outcome handling (refusal clear, retry ledger, tracing) that no primitive absorbs; the value is that the durable-effect ordering is no longer inlined, so a second venue's keeper reuses it rather than re-deriving it.

Part of #609. Stacks on the Journal::guard combinator (#629).
mfw78 added a commit that referenced this pull request Jul 25, 2026
Rewire submit_ready onto Journal::guard: the six inline journal.mark/reserve/commit/release calls that carry the #572 reserve-before-effect ordering fold into one guard call, with the venue outcome mapped to a Disposition (Accepted commits, requires-signing and known refusals release, an unknown outcome retains for reconcile). Behaviour is identical: all 23 composable-cow run tests including w1/w2/w3 and anti_572 pass unchanged. The remaining code is the CoW-specific outcome handling (refusal clear, retry ledger, tracing) that no primitive absorbs; the value is that the durable-effect ordering is no longer inlined, so a second venue's keeper reuses it rather than re-deriving it.

Part of #609. Stacks on the Journal::guard combinator (#629).
mfw78 added a commit that referenced this pull request Jul 26, 2026
Rewire submit_ready onto Journal::guard: the six inline journal.mark/reserve/commit/release calls that carry the #572 reserve-before-effect ordering fold into one guard call, with the venue outcome mapped to a Disposition (Accepted commits, requires-signing and known refusals release, an unknown outcome retains for reconcile). Behaviour is identical: all 23 composable-cow run tests including w1/w2/w3 and anti_572 pass unchanged. The remaining code is the CoW-specific outcome handling (refusal clear, retry ledger, tracing) that no primitive absorbs; the value is that the durable-effect ordering is no longer inlined, so a second venue's keeper reuses it rather than re-deriving it.

Part of #609. Stacks on the Journal::guard combinator (#629).
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.

1 participant