Amends 0097, decision 1: the state machine moves out of
@stackra/model into its own package.Context
A state machine was first placed inside@stackra/model, and the first draft used a transition(entity, ...) call on a field. The owner’s
state-machine answers SM1 and SM2 (mem L857–858, 2026-10-20) give the final shape: a package of its own, typed class definitions, and
a call through stateMachine.apply. The earlier shape (L405) is replaced (contradiction C-17). The package uses no XState.
Decision
- Package.
@stackra/state-machineis a data package (0127). It uses no XState. - Definitions (SM1). A machine is a typed class declared with
@StateMachine({ key, initial }). States are a const object plus a union type. Each transition hasfrom,to, a registered guard, a permission and effects (an event, a workflow or a notification). - Attachment (SM1). A machine attaches to a model field with
@UsesStateMachine(Flow). It runs withstateMachine.apply(entity, 'approve', ctx). A direct write to the field is blocked by a lint and by a model hook. - History and surfaces (SM2). Each transition is recorded in the history and the audit log. The available transitions appear as panel actions and as MCP tools. A Mermaid diagram comes from the registry.
- Timed transitions (SM2). They use the scheduler (0148).
- Tenant customisation (SM2). Tenants can customise states and transitions at the allowed extension points, from the console. Such customisation references registered guards and effects only.
Consequences
- A field cannot be changed by a direct write, so every transition has a guard, a permission and a history entry.
- A machine can run without a model, for UI flows or workflows, because it is its own package.
Enforcement
planned — the lint and model hook that block direct field writes, and the history check in the package’s tests.Alternatives
- The
transition(entity, ...)call with the machine on the field (L405): replaced by SM1 (C-17). - XState: not chosen; the package is typed in-house.
Supersedes and sources
Supersedes: none. Amends: 0097 decision 1. Sources: owner answers SM1 and SM2 (stackra-decisions-2026-10-19.md
L857–858, 2026-10-20), placement and no-XState rule (L405); contradiction C-17.