Storage
WorkflowStorage is the durable contract. The in-memory adapter is for tests. SupabaseWorkflowStorage is the PostgreSQL adapter.
The durable adapter persists the runtime kernel in a dedicated product-owned schema (normally workflow_runtime):
workflow_versionsworkflow_runsworkflow_eventsworkflow_commands- a queryable work-item projection
- an idempotent signal inbox
final storage = SupabaseWorkflowStorage(
client: serviceRoleClient,
durableStorage: SupabaseDurableStorage(client: serviceRoleClient),
schema: WorkflowRuntimeSchema.defaultWorkflowSchema,
);The product repository owns the generated baseline and every forward migration. Apply database migrations before starting a server built against a new storage contract. At startup, call verifyDecisionFencingCompatibility() before workers begin polling; an unmigrated or incorrectly granted database must fail closed.
Decision concurrency contract
A decision is one closed durable operation:
- Atomically claim an exact run with a worker ID, claim generation, and lease.
- Load and deterministically evaluate the claimed revision.
- Commit the run, history events, commands, continuation, consumed signals, and output/error in one database transaction.
- Accept the commit only while the worker ID, claim generation, lease, and expected revision still match.
claim_lost, terminal, and revision mismatch are protocol outcomes, not generic database failures. They must not enter an unbounded retry loop. The unfenced commit function is internal and service_role execution is revoked. This permits many decider replicas to poll concurrently while allowing only the current claim holder to publish effects for a run.
The schema declaration rejects incompatible shapes. Products share the kernel through tenant_id and application_id.
The generated migration grants service_role only and enables RLS. Never place a service-role key in a Flutter client. The command table is the durable queue. An external broker, if introduced, must be fed through a transactional outbox.
Validate the real PostgreSQL contract with concurrent workers, expired-lease reassignment, stale-worker completion, duplicate delivery, and post-workload invariant checks. Compute-only tests do not prove locking, grants, or RPC atomicity.