The state mapping between two compiled revisions of one document (ADR-0004's amendment of 2026-09-23, clauses M1 to M6).
"Migration" here means moving a waiting execution from one chart to
another, the act sp-ADR-0013 (statifier_persistence,
docs/adr/0013-the-migration-plan.md) decides. It is not a block type's
config migration: StatifierBlocks.BlockType.migrate_config/2 rewrites an
old block's stored config as the block resolves, and has nothing to do with
this module.
This package does not migrate anything. plan/2 reads two
%StatifierBlocks.Compiled{} artifacts and answers plain data a host copies
into the migration plan it writes; saving, compiling or publishing a document
never produces one, and applying a plan is the persistence layer's. The
answer names no timer, datamodel change, drop or chart hash: those are the
plan author's (M5, M6).
Summary
Types
One moved invocation, [from_state_id, from_ordinal, to_state_id, to_ordinal]: sp-ADR-0013 decision 1's encoding of an invocation key. An
ordinal is the zero-based, document-order position of an <invoke> among
its state's own <invoke> children.
The mapping (M5), with string keys and plain data only, so it encodes as JSON as it stands.
One state of the from chart with no counterpart in the to chart (M3): the
state id, and the block and role that owned it by the from side's provenance
map. "role" is nil for a block's own state.
Functions
Maps the states of from's chart onto the states of to's chart, for two
compiled revisions of one document.
Types
@type invocation() :: [String.t() | non_neg_integer()]
One moved invocation, [from_state_id, from_ordinal, to_state_id, to_ordinal]: sp-ADR-0013 decision 1's encoding of an invocation key. An
ordinal is the zero-based, document-order position of an <invoke> among
its state's own <invoke> children.
@type mapping() :: %{ required(String.t()) => %{required(String.t()) => String.t()} | [invocation()] | [unmapped()] }
The mapping (M5), with string keys and plain data only, so it encodes as JSON as it stands.
"states"- from state id to to state id, for every mapped state that is not a history pseudo-state."history"- the same, for every mapped history pseudo-state."invocations"-invocation/0entries, ordered by from state id and then ordinal."unmapped"-unmapped/0entries, ordered by state id.
One state of the from chart with no counterpart in the to chart (M3): the
state id, and the block and role that owned it by the from side's provenance
map. "role" is nil for a block's own state.
Functions
@spec plan(StatifierBlocks.Compiled.t(), StatifierBlocks.Compiled.t()) :: {:ok, mapping()} | {:error, :different_documents}
Maps the states of from's chart onto the states of to's chart, for two
compiled revisions of one document.
The clauses of ADR-0004's amendment of 2026-09-23, each as this function applies it:
- M1. A from state corresponds to a to state when both carry the same
state id and each side's
by_state_idnames the same block id and the same role for it; equal ids whose owners differ do not correspond. The states are the from chart's<state>,<parallel>,<final>and<history>elements, read from its SCXML:by_state_idalso keys a delayed<send>'s id, which is not a state. Only the two artifacts are read, and equal inputs give an equal answer. - M2. Every from state with a counterpart maps to it, roles included,
and each identity entry is written out. An
<invoke>of a mapped state maps to the<invoke>at the same ordinal of the state it maps to, when that state has one; otherwise it gets no entry. - M3. Every other from state - each state of a deleted block, and each
auxiliary state a surviving block no longer mints - is listed under
"unmapped"with its owner and appears in no other field. A to state with no from counterpart appears nowhere. - M4. Two artifacts whose compilation records carry different
document_ids are refused with{:error, :different_documents}, and nothing else is computed. Revisions are not compared: two artifacts of one document map in either order. - M5.
"states","history"and"invocations"carrysp-ADR-0013's field names and its map form (statifier_persistence,docs/adr/0013-the-migration-plan.md, decision 1), so a host copies them into its plan unchanged."unmapped"is a report, not a plan field.
Raises ArgumentError for an artifact StatifierBlocks.Compiler.compile/3
never produces: one whose scxml is not well-formed XML, or whose from
chart holds a state its own provenance map does not own.