feat(durable): durable step, &self context, and replay divergence guard#4970
Merged
Conversation
Implement the execution heart of spec-064 (epic #4707, child C4): the DurableStep typestate, the &self DurableContext, and the fingerprint-guarded replay cursor that every adapter wraps. - step.rs: StepDescriptor with the construction-time ambiguity rule (FR-DE-09), StepHandle exposing the IdempotencyKey for boundary dedup, StepError, the Live/Replayed StepOutcome, and the DurableStep record. JSON payload codec. - effect.rs: EffectIntentSubClass and the OnAmbiguous policy with the cost-bearing default and the explicit-policy requirement. - handle.rs: DurableContext (&self, AtomicU32 step ids) with step/step_recorded, parallel()/ParallelScope for completion-order-independent batches (INV-2), the exactly-once intent-before-op / result-after protocol (FR-DE-04), the BLAKE3 replay-divergence guard that aborts and restarts fresh (INV-3, FR-DE-03), the ambiguous-window resolution with a mandatory audit record (FR-DE-10), the INV-13 idempotency-key point lookup, and writer-timeout degradation (INV-12). - replay.rs: segment-buffered ReplayCursor with O(segment) resident memory. - backend: DurableBackendEnum now holds Arc<LocalBackend> so the writer and the cursor share one durable.db; lookup_committed_result added to the sealed ExecutionBackend trait and the enum dispatch. 79 zeph-durable tests pass; clippy, rustdoc, and RUSTFLAGS are clean under both the sqlite and postgres backends.
2121041 to
d48533f
Compare
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.
Part of epic #4707 (native durable execution layer, spec-064), child issue C4. Builds on C1 #4944 (scaffold), C2 #4945 (cipher), C3 #4946 (writer/backend).
What
Implements the execution heart every adapter wraps: the
DurableSteptypestate, the&selfDurableContext, the effect-class ambiguity model, and the fingerprint-guarded replay cursor.step.rs—StepDescriptorwith the construction-time ambiguity rule (FR-DE-09);StepHandle(exposes theIdempotencyKeyfor boundary dedup);StepError; theLive/ReplayedStepOutcome; theDurableSteprecord; JSON payload codec.effect.rs—EffectIntentSubClassand theOnAmbiguouspolicy (cost-bearing defaults toSkip; destructive/security/money/custom require an explicit policy).handle.rs—DurableContext(&self,AtomicU32step ids):step/step_recorded,parallel()→ParallelScopewith eagerly-assigned contiguous ids, the exactly-once intent-before-op / result-after protocol, the BLAKE3 replay-divergence guard, the ambiguous-window resolution with a mandatory audit record, the INV-13 idempotency-key point lookup, and writer-timeout degradation. Asleep_untilstub is reserved for the C5 timer layer.replay.rs— segment-bufferedReplayCursorwithO(segment)resident memory (range reads, consume-on-lookup, defer-last-step boundary handling).DurableBackendEnum::Localnow holdsArc<LocalBackend>so the writer and the cursor share onedurable.db;lookup_committed_result(idem-key point lookup) added to the sealedExecutionBackendtrait and the enum dispatch.Acceptance criteria (all covered by unit tests)
parallel_step_ids_are_completion_order_independentreplay_divergence_on_fingerprint_mismatchfresh_step_runs_op_and_journals_resultreplayed_idempotent_step_skips_opguarded_step_commits_intent_before_resultinv13_committed_guarded_result_is_not_refiredguarded_destructive_requires_explicit_policyFailsurfaces, no re-fireambiguous_window_fail_policy_surfaces_errorstep()under&selfsoundconcurrent_steps_under_shared_ref_are_soundValidation
cargo nextest run -p zeph-durable— 79 passed.cargo clippy -p zeph-durable --all-targets -- -D warnings— clean undersqliteandpostgres.cargo test --doc -p zeph-durable— 30 doc-tests passed.RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc— clean (0 warnings).cargo check --features postgresandRUSTFLAGS="-D warnings" cargo check --all-targets— clean.Spans
durable.step.run/durable.step.replay/durable.replay.cursor.*are present.Out of scope (follow-ups)
DurablePromise/DurableTimerbodies (C5), retention/compaction (C5), CLI/config/TUI (C6), the agent-loop and other adapters (A1–A4). The live testing playbook (.local/testing/playbooks/durable.md) records scenarios 1–10 as blocked until the C6 CLI + adapters land.Closes #4947