Validation-first development
Define state machines from requirements before implementation. Specifications say what the system MUST do. Encode compile-time properties in types first, then layer state machine modeling for properties types cannot express.
Modern insight (2025): State machines exist on a spectrum from runtime enums to compile-time typestates. Use the strongest mechanism available. XState v5 introduces actor model semantics -- state machines are now first-class concurrent entities, not just enum switches.
See approaches for language-specific state machine mechanisms.
See examples for brief state machine patterns per language.
See formal-tools for specification and model checking tools.
State Machine Taxonomy (decision guidance)
| Level |
Mechanism |
Strength |
Use When |
| Typestate (compile-time) |
Generic type params, phantom data |
Invalid transitions unrepresentable |
Protocol APIs, builder patterns, Rust FFI |
| Statecharts (hierarchical) |
Nested states, parallel regions |
Complex workflows, entry/exit |
Game state, multi-modal UI, XState |
| Flat FSM (runtime) |
Enum + match/switch |
Simple, auditable |
Order lifecycle, connection mgmt |
| Actor model |
Independent entities, message passing |
Concurrent state |
Distributed systems, Erlang/Elixir, XState v5 |
Default choice: Use the strongest mechanism the language supports. Typestate in Rust, sealed classes in Kotlin, discriminated unions in TypeScript.
Validation Levels
Type system (strongest) > State machine > Contract > Runtime check (weakest)
When to Apply
- Protocol implementations (network, API, auth flows)
- Workflow engines (approval chains, CI/CD pipelines)
- Concurrent/distributed systems (coordination state)
- Order lifecycle (e-commerce, payments, shipping)
- Connection/session management
- Actor systems with message-driven state
- Event sourcing aggregates (command validation against current state)
When NOT to Apply
- Stateless REST endpoints
- Pure data transformations (map/filter/reduce)
- Simple CRUD without lifecycle
- Configuration parsing
- Batch processing without state
Anti-patterns
- Boolean soup:
{ isLoading: true, isError: true, data: X } -- contradictory states representable. Use discriminated unions instead.
- Stringly-typed states:
state: "pending" with no exhaustiveness check
- Partial transition coverage: Some transitions undefined -- runtime "impossible" states
- Split-brain: State and behavior in separate modules -- changes require cross-module updates
- Invariants at boundaries only: Check invariants at every transition, not just entry/exit
- Implicit transitions: State changes scattered across codebase -- impossible to audit
- State explosion without hierarchy: Flat FSM with 50+ states -- use statecharts (nested states)
Pseudocode Template
STATE MACHINE: <Name>
STATES: S1 | S2 | S3
VARIABLES: var1: type, var2: type
INIT: var1 = val, state = S1
ACTION name(args): PRE: guard -> POST: new_state, effects
INVARIANT: condition_that_always_holds
Event Sourcing Integration
When state machines guard event-sourced aggregates:
- Command arrives -> validate against current aggregate state machine
- If transition valid -> emit immutable event
- State rebuilt from event replay
- Invalid transitions rejected before events created -- impossible to corrupt event log
Workflow (language-neutral)
- PLAN -- Identify states, variables, actions, invariants from requirements. Draw state diagram.
- CREATE -- Define state machine spec using pseudocode template. Choose mechanism level (typestate/FSM/actor).
- VERIFY -- Type-check, confirm exhaustive matching on all states, validate invariants hold at every transition.
- IMPLEMENT -- Target code mirrors spec. One state type, one transition function, one invariant check per concern.
Constitutional Rules (Non-Negotiable)
- CREATE First: Define state machine specification from plan
- Invariants Must Hold: All invariants verified at every transition
- Actions Must Type: All actions type-check with exhaustive matching
- Implementation Follows Spec: Target code mirrors specification structure
Validation Gates
| Gate |
Pass Criteria |
Blocking |
| Typecheck |
No errors; exhaustive match where language enforces it |
Yes |
| Invariants |
All invariant assertions pass after each action |
Yes |
| Tests |
All state transition tests pass |
If present |
Exit Codes
| Code |
Meaning |
| 0 |
Specification verified, ready for implementation |
| 11 |
Checker not available |
| 12 |
Syntax/type errors in specification |
| 13 |
Invariant violation detected |
| 14 |
Specification tests failed |
| 15 |
Implementation incomplete |
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: validation-first3description: Validation-first development - design state machine specifications from requirements, then execute CREATE -> VERIFY -> IMPLEMENT cycle. Use when developing with formal state machine specifications, invariants, and temporal properties before writing implementation code. Use when this capability is needed.4---56# Validation-first development78Define state machines from requirements before implementation. Specifications say what the system MUST do. Encode compile-time properties in types first, then layer state machine modeling for properties types cannot express.910**Modern insight (2025)**: State machines exist on a spectrum from runtime enums to compile-time typestates. Use the strongest mechanism available. XState v5 introduces actor model semantics -- state machines are now first-class concurrent entities, not just enum switches.1112See [approaches](references/approaches.md) for language-specific state machine mechanisms.13See [examples](references/examples.md) for brief state machine patterns per language.14See [formal-tools](references/formal-tools.md) for specification and model checking tools.1516---1718## State Machine Taxonomy (decision guidance)1920| Level | Mechanism | Strength | Use When |21|-------|-----------|----------|----------|22| **Typestate** (compile-time) | Generic type params, phantom data | Invalid transitions unrepresentable | Protocol APIs, builder patterns, Rust FFI |23| **Statecharts** (hierarchical) | Nested states, parallel regions | Complex workflows, entry/exit | Game state, multi-modal UI, XState |24| **Flat FSM** (runtime) | Enum + match/switch | Simple, auditable | Order lifecycle, connection mgmt |25| **Actor model** | Independent entities, message passing | Concurrent state | Distributed systems, Erlang/Elixir, XState v5 |2627**Default choice**: Use the strongest mechanism the language supports. Typestate in Rust, sealed classes in Kotlin, discriminated unions in TypeScript.2829## Validation Levels3031```32Type system (strongest) > State machine > Contract > Runtime check (weakest)33```3435---3637## When to Apply3839- Protocol implementations (network, API, auth flows)40- Workflow engines (approval chains, CI/CD pipelines)41- Concurrent/distributed systems (coordination state)42- Order lifecycle (e-commerce, payments, shipping)43- Connection/session management44- Actor systems with message-driven state45- Event sourcing aggregates (command validation against current state)4647## When NOT to Apply4849- Stateless REST endpoints50- Pure data transformations (map/filter/reduce)51- Simple CRUD without lifecycle52- Configuration parsing53- Batch processing without state5455---5657## Anti-patterns5859- **Boolean soup**: `{ isLoading: true, isError: true, data: X }` -- contradictory states representable. Use discriminated unions instead.60- **Stringly-typed states**: `state: "pending"` with no exhaustiveness check61- **Partial transition coverage**: Some transitions undefined -- runtime "impossible" states62- **Split-brain**: State and behavior in separate modules -- changes require cross-module updates63- **Invariants at boundaries only**: Check invariants at every transition, not just entry/exit64- **Implicit transitions**: State changes scattered across codebase -- impossible to audit65- **State explosion without hierarchy**: Flat FSM with 50+ states -- use statecharts (nested states)6667---6869## Pseudocode Template7071```72STATE MACHINE: <Name>73 STATES: S1 | S2 | S374 VARIABLES: var1: type, var2: type75 INIT: var1 = val, state = S176 ACTION name(args): PRE: guard -> POST: new_state, effects77 INVARIANT: condition_that_always_holds78```7980## Event Sourcing Integration8182When state machines guard event-sourced aggregates:831. Command arrives -> validate against current aggregate state machine842. If transition valid -> emit immutable event853. State rebuilt from event replay864. Invalid transitions rejected before events created -- impossible to corrupt event log8788---8990## Workflow (language-neutral)91921. **PLAN** -- Identify states, variables, actions, invariants from requirements. Draw state diagram.932. **CREATE** -- Define state machine spec using pseudocode template. Choose mechanism level (typestate/FSM/actor).943. **VERIFY** -- Type-check, confirm exhaustive matching on all states, validate invariants hold at every transition.954. **IMPLEMENT** -- Target code mirrors spec. One state type, one transition function, one invariant check per concern.9697---9899## Constitutional Rules (Non-Negotiable)1001011. **CREATE First**: Define state machine specification from plan1022. **Invariants Must Hold**: All invariants verified at every transition1033. **Actions Must Type**: All actions type-check with exhaustive matching1044. **Implementation Follows Spec**: Target code mirrors specification structure105106## Validation Gates107108| Gate | Pass Criteria | Blocking |109|------|---------------|----------|110| Typecheck | No errors; exhaustive match where language enforces it | Yes |111| Invariants | All invariant assertions pass after each action | Yes |112| Tests | All state transition tests pass | If present |113114## Exit Codes115116| Code | Meaning |117|------|---------|118| 0 | Specification verified, ready for implementation |119| 11 | Checker not available |120| 12 | Syntax/type errors in specification |121| 13 | Invariant violation detected |122| 14 | Specification tests failed |123| 15 | Implementation incomplete |124125---126> Converted and distributed by [TomeVault](https://tomevault.io/claim/outlinedriven) — claim your Tome and manage your conversions.127<!-- tomevault:4.0:skill_md:2026-04-11 -->