state machine
rule
- one closed semantic-state contract, one pure exhaustive fold from durable facts to it
- every reader, guard, reconciler, and interface uses the same fold
- producers commit facts; they never write, transition, or repair a second stored state
- a long-running operation uses this machine as its status authority: the operation resource owns how clients observe work; the state machine owns what the observed state means
why
- a stored status column is a second copy of truth; any interruption between effect and update leaves the two permanently disagreed with no way to tell which is right
- a pure fold over durable facts has no second copy: facts are the evidence, state is derived, replay always rebuilds the same answer
- guards, migrations, and diagnosis operate on one shared definition of what the recorded evidence means
fact model
facts record durable evidence: intent accepted, work claimed, result committed, failure classified, cancellation authorized, external outcome observed. a state answers what those facts mean together.
the fold contract declares:
- a closed state domain
- which states are terminal and nonterminal
- every fact kind the machine consumes
- explicit precedence when several facts exist
- a typed invalid result for contradictory or impossible fact sets
- an explicit unknown state only when missing knowledge is a real domain outcome, never a catch-all fallback
terminal facts outrank nonterminal progress. within one terminal class, domain policy chooses precedence explicitly; array order, last read, or arrival timing never chooses it accidentally.
type OperationState = "accepted" | "running" | "succeeded" | "failed" | "cancelled";type StateProjection =| { kind: "state"; state: OperationState }| { kind: "invalid"; code: "conflicting_terminal_facts" };function deriveOperationState(facts: OperationFacts): StateProjection {if (facts.succeeded && facts.failed) {return { kind: "invalid", code: "conflicting_terminal_facts" };}if (facts.succeeded) return { kind: "state", state: "succeeded" };if (facts.failed) return { kind: "state", state: "failed" };if (facts.cancelled) return { kind: "state", state: "cancelled" };if (facts.started) return { kind: "state", state: "running" };return { kind: "state", state: "accepted" };}
guarded fact commits
- a command legal in only one state: read the required facts, derive the state, check the guard, commit the next fact — one serialized transaction or conditional statement; never compare and update a stored status column
- the fact has a stable idempotency key: retrying commits the same fact or observes it already exists, then derives the same state
- atomicity belongs to the fact invariant; retry safety never depends on a producer reaching a later state-write statement
replay and reconciliation
- the complete fact set can replay the machine from nothing: usable for reads, migrations, incident diagnosis, rebuilding disposable projections
- a reconciler records missing canonical facts or external observations, then runs the same fold; it never edits state to make a display look current
- a cache may store a projection only when its owner, rebuild path, and freshness window are explicit; deleting and replaying it must restore the same answer
verification
- exhaust every fact kind and every closed output state
- replay the same facts in different read orders; prove one result
- deliver duplicate facts; prove the result does not change
- interrupt each producer between durable writes; prove the fold stays honest about committed evidence
- combine conflicting terminal facts; prove a typed invalid result, not an arbitrary state
- rebuild any projection cache from facts; compare every output
good and bad
bad
await operationTable.update({ state: "running" });await performWork();await operationTable.update({ state: "succeeded" });
the process can stop after the effect and before the final update. each producer becomes another partial copy of the state machine, observers read stale or impossible states, and no replay can tell which stored value reflects what actually happened.
good
await commitOperationFact({ kind: "result_committed", operationId });const projection = deriveOperationState(await readOperationFacts(operationId));
the durable fact survives interruption; every consumer obtains the same semantic result from one fold. guards, polling, reconciliation, and migrations all read one shared definition; replaying the recorded evidence always rebuilds the identical answer.