Skip to content

Concepts: State & Durability

Invariant treats execution state as durable infrastructure, not ephemeral model memory.

"The model may forget. The runtime must not."


1. Execution State

Execution State (state) represents the accumulated progress of a single Workflow run.

Invariant persists that progress durably so later nodes—and recovered workers—continue from committed state rather than attempting to reconstruct context from model memory:

ts
const workflow = app.workflow("refund", {
  inputSchema: z.object({
    orderId: z.string(),
  }),
})
  .capability("load-order", loadOrder)
  .step("check-policy", ({ state }) => ({
    eligible: state.order.ageDays <= 30,
  }))
  .capability("issue-refund", ({ state }) => {
    // state.order and state.eligible came from previous node outputs
  });
text
input (orderId)


load-order

   ├── state.order

check-policy

   ├── state.eligible

issue-refund

2. Execution State Accumulates Through Node Outputs

Execution state is built incrementally as each graph node returns data:

ts
.step("normalize-payload", () => ({
  normalized: true,
}))
.step("calculate-totals", ({ state }) => {
  // state.normalized is automatically typed and available
  return { total: 100.00 };
})

Node outputs accumulate into Execution State. Unlike initial parameters (input), which remain immutable throughout execution, state extends sequentially with every node execution.


3. Session Context vs. Execution State

It is essential to keep long-lived session context separate from workflow execution state:

FeatureSession Context (session.context)Execution State (state)
ScopeAcross related activity & runsOne workflow run (runId)
Defined bycontextSchema & hydrate()Workflow node outputs
PurposeDurable continuityDurable progress

Canonical Home: For hydration, rehydration, and Session Context semantics, see Sessions & Hydration.


4. How State Becomes Durable (Event Reduction)

Execution State is not stored merely as a mutable database row. Invariant records the immutable facts (events) that produced it:

text
WORKFLOW_STARTED


CAPABILITY_COMPLETED
{ order: { ageDays: 14 } }


STEP_COMPLETED
{ eligible: true }


CAPABILITY_COMPLETED
{ refundId: "rf_99" }


WORKFLOW_COMPLETED

        │ reduce (pure reducer)


Materialized Execution State
{
  order: { ageDays: 14 },
  eligible: true,
  refundId: "rf_99"
}

State is derived deterministically by passing historical execution events through pure reducers.


5. Execution Event History

Every execution-relevant fact is represented durably in the execution history with a strictly monotonic sequence number (seq = 1..n):

  1. WORKFLOW_STARTED
  2. CAPABILITY_REQUESTED
  3. CAPABILITY_COMPLETED
  4. STEP_COMPLETED
  5. REASON_COMPLETED
  6. WAIT_ENTERED
  7. INPUT_RECEIVED
  8. WORKFLOW_COMPLETED

Event History Properties

  • Append-Only Execution History: Committed execution events are not rewritten as part of normal runtime execution. Payload retention or redaction may be governed separately by storage policy.
  • Monotonic Ordering: Events within an execution have strictly increasing sequence numbers (seq).
  • Data Provenance: Events preserve the execution facts and metadata required for auditing and replay, subject to configured payload retention or redaction policy.

6. Materialization & Storage Decoupling

Invariant decouples execution fact persistence from state materialization:

  • Execution Event History — The immutable source of execution facts.
  • Materialized Execution State — Current derived state persisted for fast runtime access.
  • Snapshots / Checkpoints — Optional storage optimizations for long event histories to accelerate worker recovery without altering the event log.

7. State & External Effects (Idempotency)

The state transition and the intent to perform an external effect are committed atomically. The effect itself executes afterward through the Outbox worker:

text
Atomic Transaction (BEGIN...COMMIT)
├── Execution State
├── Execution Event
└── Capability Intent


   Outbox Worker


 External System
text
At-Least-Once Dispatch


Stable Idempotency Key (e.g. `refund:${execution.id}`)


External System Honors Key?
   ┌────┴────┐
  yes        no
   │         │
   ▼         ▼
Effectively  At-Least-Once
  Once       Invocation

Capabilities supply stable idempotency keys across retries. Invariant guarantees repeatable intent, but effectively-once external side effects require the target API to honor idempotency keys.

"Invariant guarantees repeatable intent, not exactly-once effects in systems it does not control."


8. Crash Recovery Without AI Memory Reconstruction

When a worker crashes, Invariant does not ask the LLM to reconstruct execution history or re-run already committed reasoning results. Pending external effects may be retried according to their durable Outbox state and idempotency policy:

text
Worker Crash / Process Restart


   Read Event History facts


   Reconstruct Execution State


Resume from last committed execution state

Worker recovery resumes execution directly from committed durable facts.


Go Deeper

Invariant Durable Execution Engine.