Skip to content

Replay Profile

The Replay Profile defines three distinct operations over Durable history: reconstruction, re-evaluation, and continuation from history. The unqualified word “replay” is informative shorthand and MUST NOT be used in a conformance claim or portable interface without identifying which operation is meant.

An implementation claiming this profile MUST claim the Durable Execution Profile and MUST validate the history, its resolved-content pins, and the requested operation before acting. It MUST refuse an operation when required history is absent, withheld, corrupt, internally inconsistent, or uses an unsupported Standard version.

Refusal MUST identify the earliest unusable boundary and MUST NOT silently invoke external work as a substitute.

Reconstruction materializes the state represented by history at a selected durable boundary. It reads recorded scopes, bindings, outcomes, active timers and subscriptions, state entries, recovery generation, holds, and terminal result exactly as stored, including the accepted stop result when present.

Reconstruction MUST NOT evaluate an expression or template, invoke a filter, action, child workflow, embedded program, or agent, read a clock, select a branch, advance a timer, deliver an event, retry, reconcile, compensate, or continue execution. It can therefore reconstruct history even when executable dependencies are unavailable, provided their recorded identities and required values are intelligible.

The reconstructed state MUST preserve runtime kinds, step paths, null behavior, active-versus-superseded history, and unresolved ambiguity. It is an observation, not a new run: run.id, outcomes, and history are unchanged. Reconstructed dry-run values follow the suppression recording rules under Dry Runs.

Re-evaluation executes pure workflow logic again from the root using the pinned definition while supplying recorded values at every nondeterministic boundary. Those values include run metadata, workflow and trigger inputs, accepted events, action and child results, agent results, operator decisions, timer eligibility, retry jitter and server delay, and permitted scheduling decisions that affected execution.

Expressions, templates, built-in and resolved package filters, projections (including stop results), guards, routes, and other pure decisions are evaluated anew. Recorded action results are inputs, not invocations.

Re-evaluation MUST NOT contact a connector, start a child or agent, consume a live event, read the current clock, or produce a new external effect. At each recorded boundary, the re-evaluated operation identity and evaluated arguments MUST be compatible with the recorded entry.

If pure evaluation selects a different path, produces different arguments, requires an unrecorded boundary, or yields a different workflow result, fault, or decision, the implementation MUST report divergence at the earliest point. It MUST NOT force the recorded branch or continue with a result belonging to a different invocation.

Re-evaluation does not alter the original history or create a continuation.

Continuation from history evaluates from the beginning, reuses compatible recorded boundaries, and switches to live execution after the usable history ends. Resuming the same run preserves run.id and MUST use its original pinned definition and dependencies.

Reusing history with another resolved definition creates a successor run with a new run.id; authorization to create that run is a deployment operation, while its reuse and invalidation behavior is governed below. A recorded boundary is reusable only when all of the following match the continuation definition: stable step path and recovery generation; operation kind and resolved artifact identity; connection identity where relevant; evaluated argument value and type; dry-run, timeout, idempotency, and attempt context; required profile inputs; and result compatibility with the current declared contract.

Pure boundaries before it MUST also have re-evaluated compatibly. The first absent or incompatible boundary invalidates that boundary and every causally dependent suffix entry.

Independent completed branches whose inputs and joins remain compatible MAY remain reusable. Superseded entries are never reusable.

The implementation MUST expose which boundary caused invalidation and which suffix was discarded from active consideration; original history remains immutable. Live execution begins only from a durable boundary with a complete active state.

A definitely completed compatible action MUST NOT be invoked again. An invocation recorded as not dispatched can be dispatched normally.

One recorded as definitely failed follows current applicable policy. One dispatched without a definite result remains ambiguous under Connector Execution Contract and MUST use explicit on_unknown or Core Ambiguity Disposition; it MUST NOT be treated as absent history.

If invalidation would reissue an action whose prior effect might exist, continuation is safe only when the prior history establishes no effect, the action is inherently idempotent, the same durable key satisfies keyed idempotency, or compensation has definitely succeeded. Otherwise the run is held for operator resolution.

This rule applies even when the changed definition no longer contains that action. Continuation MUST pin the definition and dependencies it actually uses and record a lineage link for a successor plus every reuse and invalidation decision.

Continuation MUST NOT splice together incompatible connector versions, filter packages, overlays, time-zone data, or Standard semantics. Once live execution begins, ordinary base and Durable rules apply.