Modules
Block document model, one-way SCXML compiler, and LiveView editor components for composing Statifier statecharts from typed blocks.
May this block land in this slot? Answered by two independent gates - structural admission by kind tag, and data-flow compatibility by opaque string identity plus a host-supplied widening relation (ADR-0003).
A host's widening relation. Consulted only after identity has failed, so an implementation can only widen, never narrow (ADR-0003 decision 6).
One node of a block document (ADR-0001).
The authoring-time extension seam. A host implements this behaviour once
per palette entry; the core.* structural vocabulary this package will
ship itself lands in a later record (ADR-0002 decision 10) and is not
present yet.
The join between a block document and the chart it compiled to (ADR-0004 decision 7).
What one successful compile produced (ADR-0004 decision 1).
The one-way compile: a block document plus a palette in, one artifact out (ADR-0004 decisions 1-4, 6-7).
Resolves each element of one block's emission to the block an author would recognise (ADR-0004 decision 5).
The scope-shaped cancel: a delayed send armed by a child block is
cancelled in the <onexit> of the state that armed it (ADR-0004's
2026-08-29 amendment, "a delayed send's cancel, emitted in the arming
state's <onexit>").
The Chart stage: run the generated SCXML through statifier's own pipeline and route every finding back to a block (ADR-0004 decisions 9 and 10).
What a block type is entitled to know while emitting, and nothing more (ADR-0004 decision 4).
How a block type contributes a compiler-declared <data> root to the
chart's one top-level <datamodel> (ADR-0004's 2026-08-29 foreach
amendment, F2 and F3), and the collision refusal F6 records.
One thing the compiler has to say about one block (ADR-0004 decision 10).
The two-registry gap, surfaced as data and linted only on request (ADR-0004 decision 8).
The direct self-reference refusal: a document may not run itself
(ADR-0004's 2026-08-29 amendment on what core.subchart's src
resolves against).
The secrets rule, checked against a document: a declared-sensitive
datamodel path may not be read into a trace-visible position (ADR-0002,
the accepted 2026-08-29 amendment "decision 7, an optional sensitive?
key, and the secrets rule behind it").
Turns an StatifierBlocks.Emission tree into SCXML bytes, and records
where every one of them came from (ADR-0004 decisions 5 and 6).
State ids derived from block ids by a pure function (ADR-0004 decision 3).
Connector geometry: pure functions from measured rectangles to SVG path data (ADR-0005 decision 10, and the 2026-08-29 amendment to decision 7).
One connector: the vocabulary it is drawn in, and its SVG path data.
One measured rectangle, in the stage's untransformed coordinate space.
The core.* structural vocabulary: the block types this package ships
itself (ADR-0002 decision 10).
core.assign: a leaf step that writes one literal to one datamodel path.
core.branch: one slot per condition arm, plus otherwise (ADR-0002
decision 10).
The two duration spellings a :duration field may hold, and the one
form the engine reads.
The SCXML shapes the core.* vocabulary compiles to (ADR-0004 decisions
2-4), and the small builders the core types share.
core.foreach: a container whose body runs once per item of a
datamodel list (ADR-0004's 2026-08-29 amendment, F1 through F6).
core.group: a boundary around a run of steps that interrupt rules can
fire against.
core.invoke: a step that calls the host and waits for it to answer,
with an optional subtree for the failure case (ADR-0002 decision 10, as
amended 2026-08-29 section D).
core.on_event: an interrupt handler, valid inside an interrupts slot
and nowhere else (ADR-0002 decision 10).
core.parallel: one slot per lane, with no ordering between the lanes
(ADR-0002 decision 10).
core.raise: a leaf that raises one event for an enclosing group's
interrupt rail (ADR-0002 decision 10's amendment, section D).
core.resumable_group: a group whose config carries a history mode
(ADR-0002 decision 10).
core.send: a leaf step that names an event and says when.
core.sequence: an ordered run of steps, and the conventional document
root (ADR-0002 decision 10).
core.subchart: a step that runs another chart and waits for it to
finish, routing on the outcome that chart finished with (ADR-0004's
2026-08-29 amendment, C1 through C3).
core.wait: a leaf whose whole meaning is its config (ADR-0002 decision
10).
The host's datamodel as the editor consumes it, and the one check it makes against it (ADR-0005 decision 11, amended 2026-08-29 as 11e-11g).
A block document: one tree, one envelope (ADR-0001).
One root the document itself declares (ADR-0001 decision 11).
The :duration control's reading of the text an author typed.
The editor's command algebra. Pure, serializable, invertible - and deliberately free of any UI framework dependency, so it is tested with no editor shell present at all (ADR-0005 decision 1).
Undo and redo over StatifierBlocks.Edit.t() commands (ADR-0005
decision 3), and the one funnel every editor command actually goes
through: commit/4 runs Edit.check_config/3 before Edit.apply/2, so
"invalid config never reaches the document" is a property of this
module, not a rule an editor shell has to remember to enforce itself.
Drop-target enumeration (ADR-0005 decision 5): which slots would accept a dragged block, at slot granularity rather than gap granularity.
The block editor: the only stateful module in the package's rendered half (ADR-0005 decisions 6, 8, 9, 13).
One block's chrome, dispatching to its slots (ADR-0005 decisions 10, 11, 12, 13).
The tree's root and the drag hook's element (ADR-0005 decisions 7, 13, 14).
The selected block's config form (ADR-0005 decisions 9 and 13).
The drawn connectors, and the element the measurement hook rides on (ADR-0005 decision 10, and the 2026-08-29 amendment to decision 7).
The full-width drawer row (ADR-0005, the 2026-08-29 shell amendment, rulings 1A and 2A).
One config field, dispatching on the closed field-type set (ADR-0005 decision 9, ADR-0002 decision 7).
The document-level findings list (ADR-0005 decision 11), rendered as the drawer's Findings tab.
The shipped default icon set, and the seam a host overrides it through
(ADR-0005 decision 10's icon key, decision 14's "markup, not styling"
line).
The tabbed inspector: Config, Findings, Condition (ADR-0005, the 2026-08-29 shell amendment, ruling 3A).
The grouped, searchable, filterable palette (ADR-0005 decisions 8, 10, 13).
One named slot: its header, its children, its gaps, and its "+" buttons (ADR-0005 decisions 5, 6, 8, 11, 13).
The canvas toolbar (ADR-0005, the 2026-08-29 shell amendment, ruling 8A).
One SCXML subtree, structurally (ADR-0004 decision 4).
A finding as the editor renders it: normalized for presentation, and the anchor routes it (ADR-0005 decision 11).
Mints block and document ids: "blk_" <> uxid and "bdoc_" <> uxid,
following the family's identifier convention (st-ADR-0008, as amended to
drop the uxid dependency and mint inline -
statifier-ex/lib/statifier/machine_state.ex:571-585).
A palette names the block types a host makes available: a map from a
block's type_name to the module implementing StatifierBlocks.BlockType
for it (ADR-0002 decision 2).
The evaluation seam: a condition source string plus a binding context in,
{:ok, boolean()} | {:error, reason()} out, through predicator.
The path/type index over a datamodel document (sb ADR-0006, accepted 2026-08-29), and the projections that record promises.
A table spec plus rows in, a struct with per-cell outcomes, first-match-wins selection and expectation status out.
One row/column intersection: the raw evaluation outcome, whether the
column was selected? under first-match-wins, the row's declared
expected answer (if any), and the derived status. See
StatifierBlocks.Predicates.TruthTable's moduledoc for what each
status value means.
One truth-table column: a key, a display label, and a predicator source
string, or source: nil for the otherwise column.
One truth-table row: the bindings that build its context, the resulting
cells (or a row-level error when the bindings themselves fail), and an
optional author-facing note.
Which generated element came from which block (ADR-0004 decision 5).
The shell's arrangement, as pure functions (ADR-0005, the 2026-08-29 shell amendment: rulings 1A, 2A, 3A, 7A, 8A).
ADR-0002 decision 6's two properties, checked over a whole document
against a palette: declared slots are the complete set a block may carry
(:undeclared_slot), and a slot's child count must satisfy the arity
its type declares for it (:slot_arity_violated).
Everything the editor renders, derived from {document, palette, findings} (ADR-0005 decisions 9, 10, 11, 12, 13).
One config field, its schema and its current value (ADR-0005 decision 9).
A resolved node's config form: its fields, plus any :config finding
whose key matched no field (ADR-0005 decision 11's fourth routing row).
One block, rendered: its resolved status, its presentation metadata, its slots (recursive), its form, and its own findings.
One palette section: types sharing entry.group, sorted by
entry.order then entry.label (ADR-0005 decision 10's grouping
rule).
One named slot: declared or raw, with its children and its own findings.