Finite State Machines (FSM)
Appendix C: FSM (Finite State Machines)
Purpose Standardize how application states and complex workflows are modeled as FSMs across stacks.
C1. Non-Negotiables • All non-trivial workflows are FSMs or statecharts. • State is a closed set; transitions are named events with optional guards and actions. • Side-effects attach to transitions; no direct mutation from effects. • Invalid transitions are prevented by types or rejected with explicit reasons.
C2. Modeling Checklist • States: mutually exclusive, include terminal states. • Events: small, well-named vocabulary. • Context: minimal, immutable, versioned for persistence. • Transitions: defined for each (state, event) pair with guards and actions. • Invariants: documented and, where possible, enforced by types. • Time: model timers and deadlines as events (e.g., EXPIRE, TIMEOUT). • Retries: explicit attempt counts and terminal conditions.
C3. Testing Strategy • Table-driven tests for the transition function. • Property tests for invariants and reachability. • Model-based tests: random event sequences with oracles. • Contract tests for actions at IO boundaries.
C4. Observability • Emit one structured log per transition: from, to, event, guards evaluated, actions scheduled, context hash, correlation ID. • Metrics: per-transition counters, per-state occupancy, dwell time distributions.
C5. Persistence and Rehydration • Persist entity ID, state (enum string), context snapshot (versioned), updated_at. • Rehydrate the machine on read; never infer state from scattered columns. • Use DB constraints for state values where supported; otherwise enforce in repositories.
C6. Documentation Artifacts
• Transition table included in PRs and stored in /docs/machines/
C7. Minimal Transition Table Template (text-only) • Columns to include: • From State • Event • Guard(s) • To State • Action(s) • Notes • Rules: guards are pure predicates; actions are named effects; document rejection cases explicitly.
C8. Review Gate • Any PR changing a workflow must include an updated transition table, tests for new pairs, and an updated diagram reference. • No merge if totality or determinism is broken.
C9. Where code lives
• Rust machine files under core/machines or app/machines.
• Laravel machine files under app/Domain/