Architecture
Use a restricted workflow DSL in Dart. A workflow function may use normal control flow, but every durable boundary goes through WorkflowContext:
performfor I/O and side effects;requestfor assigned work;waitForEventfor external events;sleepfor durable time;- a stable operation
idon every await.
Direct I/O, wall-clock reads, randomness, mutable globals, and unregistered futures are forbidden in orchestration code.
WorkflowRuntime is the canonical runtime.
Component Split
| Component | Owns | Must not own |
|---|---|---|
| Schema | Reusable structural shape, typed encoder/decoder, validation, examples, sensitivity | Workflow orchestration |
| Workflow definition | Immutable identity and input/output/failure schemas | Executable orchestration |
| Workflow handler | Deterministic orchestration and await IDs | I/O, clocks, randomness |
| Decider / runtime | Replay, commands, retries, status | Business side effects or SQL |
| Operation worker | Versioned handlers, heartbeats, idempotency | Workflow control-flow state |
| Work API | Audience, claim, response, validation, expiry | A long-lived process |
| Storage interface | Atomic run/history/command transitions | Supabase-specific SQL |
| Postgres adapter | Transactions, row locks, SKIP LOCKED, fencing | Workflow-domain branching |
| Timer / recovery | Timers, expiry, expired leases, interrupted decisions | Arbitrary business code |
| Designer | Constrained document and visualization | Runtime state |
API, decider, worker, and recovery roles can be separate processes or one WorkflowServerApplication. Correctness comes from storage contracts, not from which replica handled the last request.
Progress Model
history.sequenceis the ordered audit trail.runs.revisionfences concurrent decisions.- commands are pending, claimed, completed, failed, or cancelled.
operationKeyidentifies a logical await across replay.claimGenerationfences stale workers after lease reaudience.
blocked is healthy. It means the run is waiting for durable external work.
Definition Digest
A run stores code, version, and digest. Workers reject a digest mismatch instead of replaying history against changed logic. Changing behavior requires a new version.
Visualization
Arbitrary Dart cannot be converted into a complete graph. Attach an optional WorkflowDocument when you need a pre-run inspector map. Without it, the inspector builds an observed operation map from history as the run executes.