# Statifier v2.0.0 - Table of Contents

> A W3C SCXML-conformant statecharts engine for Elixir

## Pages

- [Statifier](readme.md)
- [Changelog](changelog.md)

- Guides
  - [Architecture](architecture.md)
  - [Datamodel](datamodel.md)
  - [Extending Statifier: &lt;invoke&gt; handlers](extending.md)
  - [Persistence](persistence.md)
  - [Durable Timers: Delayed Sends That Outlive the Process](durable-timers.md)
  - [Observability](observability.md)
  - [OpenTelemetry](opentelemetry.md)
  - [Testing your own charts](testing-charts.md)
  - [Chart patterns: external-resource verdicts](chart-patterns.md)
  - [Family reference: what the sibling repos copy from here](family-reference.md)

- Architecture Decision Records
  - [Architecture Decision Records](adr-index.md)
  - [ADR-0001: Record architecture decisions](0001-record-architecture-decisions.md)
  - [ADR-0002: Port the W3C SCXML algorithm literally (Appendix D)](0002-literal-w3c-appendix-d-port.md)
  - [ADR-0003: Pure functional core returning effects](0003-pure-core-with-effects.md)
  - [ADR-0004: Predicator is the datamodel; no ECMAScript, no Elixir eval](0004-predicator-as-the-datamodel.md)
  - [ADR-0005: Store the full configuration; intern states to integer indexes](0005-full-configuration-and-interned-state-indexes.md)
  - [ADR-0006: Reuse the v1 conformance corpus and regression ratchet; commit a generator](0006-reuse-conformance-corpus-and-regression-ratchet.md)
  - [ADR-0007: Beads for issue tracking](0007-beads-for-issue-tracking.md)
  - [ADR-0008: UXID for generated identifiers](0008-uxid-for-identifiers.md)
  - [ADR-0009: ex_quality is the quality gate](0009-ex-quality-as-quality-gate.md)
  - [ADR-0010: Parallel development via worktrees, coordinated through beads](0010-worktree-parallel-development.md)
  - [ADR-0011: Quality gate config is not agent-editable](0011-quality-gate-config-not-agent-editable.md)
  - [ADR-0012: Debuggability is designed into the core](0012-debuggability-designed-into-the-core.md)
  - [ADR-0013: Archive the v1 statifier repo in place](0013-archive-v1-statifier-repo-in-place.md)
  - [ADR-0014: Expression-level spans are part of the retained-location constraint](0014-expression-spans-in-cond-diagnostics.md)
  - [ADR-0015: Skill mechanics live in scripts, judgment lives in prose](0015-skill-mechanics-in-scripts.md)
  - [ADR-0016: The wurk skills live in their own repo; this repo gates its extensions](0016-wurk-skills-out-of-repo-extensions-gated.md)
  - [ADR-0017: Judgment is not scriptable, scoped to the wurk extension surface](0017-judgment-not-scriptable-in-wurk-extensions.md)
  - [ADR-0018: Process artifacts are not code comments](0018-no-process-jargon-in-code-comments.md)
  - [ADR-0019: A round budget bounds the macrostep fold](0019-macrostep-round-budget.md)
  - [ADR-0020: A round ordinal joins the step counters](0020-round-ordinal-joins-the-step-counters.md)
  - [ADR-0021: A failed donedata content expr yields no data](0021-donedata-content-expr-failure-yields-no-data.md)
  - [ADR-0022: A parallel is never the LCCA; SCION's contrary tests leave the corpus](0022-parallel-is-never-the-lcca.md)
  - [ADR-0023: Numeric-type gaps are fixed in predicator, never coerced at the boundary](0023-numeric-type-fixes-upstream-not-boundary-coercion.md)
  - [ADR-0024: &lt;data src&gt; is never fetched](0024-data-src-is-never-fetched.md)
  - [ADR-0025: Cross-repo tracker authority and the mirror obligation](0025-cross-repo-tracker-authority-and-mirrors.md)
  - [ADR-0026: &lt;script&gt; bodies are predicator statement programs](0026-script-as-predicator-statement-programs.md)
  - [ADR-0027: Embedder-placed session runtime with a named registry](0027-embedder-placed-session-runtime.md)
  - [ADR-0028: Executable-content blocks thread one context and bind/3 each write](0028-executable-content-blocks-thread-one-context.md)
  - [ADR-0029: Session.interpret/2 stays public; replay records four inputs](0029-session-interpret-stays-public.md)
  - [ADR-0030: In/1 becomes a provider; the built context still is not a MachineState field](0030-in1-becomes-a-provider-context-stays-off-machinestate.md)
  - [ADR-0031: A failed invoke argument evaluation aborts the invocation](0031-invoke-argument-failure-aborts-the-invocation.md)
  - [ADR-0032: The round budget spans the invoke pass's re-entry](0032-round-budget-spans-the-invoke-re-entry.md)
  - [ADR-0033: The validator gets a warning tier](0033-validator-warning-tier.md)
  - [ADR-0034: Replay re-drives the core, not a live session](0034-replay-re-drives-the-core-not-a-live-session.md)
  - [ADR-0035: The send id is send_&lt;n&gt; off a new machine_state.send_counter](0035-send-id-is-a-machinestate-counter.md)
  - [ADR-0036: A failed &lt;send&gt; argument discards the message](0036-send-argument-failure-discards-the-message.md)
  - [ADR-0037: Unbound is spelled :undefined at the writer; nil means null](0037-unbound-spelled-undefined-at-the-writer.md)
  - [ADR-0038: &lt;invoke&gt;'s source resolves at the session boundary, never inside the library](0038-invoke-source-resolves-at-the-session-boundary.md)
  - [ADR-0039: Session-detected send failures re-enter the core](0039-session-detected-send-failures-re-enter-the-core.md)
  - [ADR-0040: Session telemetry event contract](0040-session-telemetry-event-contract.md)
  - [ADR-0041: &lt;content&gt; markup lowers to a source slice, compiled at invoke time](0041-content-markup-lowers-to-a-source-slice.md)
  - [ADR-0042: Invoke content markup compiles under the relaxed namespace rule](0042-invoke-content-compiles-under-the-relaxed-namespace-rule.md)
  - [ADR-0043: Attribute values normalize per XML 1.0 3.3.3, guided by the raw source](0043-attribute-values-normalize-per-xml-3-3-3.md)
  - [ADR-0044: Re-entry effects defer to the outer batch](0044-re-entry-effects-defer-to-the-outer-batch.md)
  - [ADR-0045: Character data folds line breaks per XML 1.0 2.11, guided by the raw source](0045-character-data-folds-line-breaks-per-xml-2-11.md)
  - [ADR-0046: Every core effect carries round](0046-round-on-every-core-effect.md)
  - [ADR-0047: Static send target/type invalidity rejects in the core](0047-send-static-target-type-invalidity-rejects-in-the-core.md)
  - [ADR-0048: Send reachability is judged in the core against a route snapshot](0048-send-reachability-judged-against-a-route-snapshot.md)
  - [ADR-0049: Late subscribers catch up by replaying the recording](0049-late-subscriber-catch-up-via-recording.md)
  - [ADR-0050: Invoked children inherit the parent's observers by opt-in](0050-invoked-children-inherit-observation-by-opt-in.md)
  - [ADR-0051: Invoke handlers are registered per session](0051-invoke-handlers-are-registered-per-session.md)
  - [ADR-0052: Chart identity and position serialization](0052-chart-identity-and-position-serialization.md)
  - [ADR-0053: The chart-author test helpers ship in lib/ under Statifier.Testing](0053-chart-test-helpers-ship-in-lib-under-statifier-testing.md)
  - [ADR-0054: Durable timers consume the effect vocabulary](0054-durable-timers-consume-the-effect-vocabulary.md)
  - [ADR-0055: Non-self delayed-send routes stay the library's](0055-non-self-delayed-send-routes-stay-the-librarys.md)
  - [ADR-0056: After a renumbering, pointer citations move and history stands](0056-renumbered-adr-citations-pointers-move-history-stands.md)
  - [ADR-0057: Recording identity and serialization](0057-recording-identity-and-serialization.md)
  - [ADR-0058: ADR number collisions fail the gate via a tree-local numbering invariant](0058-adr-number-collisions-fail-the-gate-tree-locally.md)
  - [ADR-0059: A per-execution ordinal joins the durable-timer effects](0059-per-execution-ordinal-on-durable-timer-effects.md)
  - [ADR-0060: Resuming a session from a persisted position](0060-resuming-a-session-from-a-persisted-position.md)
  - [ADR-0061: Consumers pin main SHAs under a documented contract until 2.0.0](0061-sha-pinning-contract-until-2-0-0.md)
  - [ADR-0062: The OpenTelemetry bridge is a separate package, opentelemetry_statifier](0062-opentelemetry-bridge-is-a-separate-package.md)
  - [ADR-0063: An opaque caller context rides external events and the durable-timer effects](0063-caller-context-on-external-events-and-durable-timer-effects.md)
  - [ADR-0064: The position blob drops the per-drive snapshot fields](0064-position-blob-drops-the-per-drive-snapshot-fields.md)
  - [ADR-0065: A handler conformance case joins the Statifier.Testing surface](0065-handler-conformance-case-in-statifier-testing.md)
  - [ADR-0066: Publishes 2.0.0 to Hex, ending the SHA-pinning contract](0066-publishes-2-0-0-ending-the-sha-pinning-contract.md)

## Modules

- [Mix.Statifier.AdrGuard](Mix.Statifier.AdrGuard.md): Flags likely violations of the mechanically-checkable ADRs in `docs/adr/`.
- [Mix.Statifier.AdrJudge](Mix.Statifier.AdrJudge.md): Judges the current branch's diff against a registry of judged ADRs, each
carrying its own path scope, ADR text, and failure vocabulary, using two
independent model calls per ADR: one proposes violations, a second is
prompted to refute each one. Only a proposed violation the refute pass
fails to overturn becomes a finding - a single pass reporting whatever it
first notices is exactly what the adversarial-verification requirement on
this check rules out, because a false positive here blocks a commit
(CLAUDE.md: "never go green by weakening the check" means the fix for a
bad finding has to be "the check was wrong," not "disable the check" - so
the bar to reach gate-failure status is higher than an FYI).
- [Mix.Statifier.GateGuard](Mix.Statifier.GateGuard.md): Finds changes to the quality gate's own configuration that no one has
justified in writing.
- [Mix.Statifier.RegressionRegistry](Mix.Statifier.RegressionRegistry.md): Reads and writes `test/passing_tests.json`, the regression ratchet registry.
- [Statifier](Statifier.md): The public entry point for statifier-ex.
- [Statifier.Chart](Statifier.Chart.md): The versioned binary contract for a *chart* - a `Statifier.Machine.t()`
reduced to the inputs that reproduce it: its SCXML source, the persisted
subset of the options it was compiled with, and its
`Statifier.Machine.Identity.t()`. No compiled term is written - `from_binary/1`
rebuilds a `Machine.t()` by recompiling the stored source with the stored
options through `Statifier.compile/2`, the same pipeline any other caller
runs, rather than by deserializing compiler output directly.
- [Statifier.Compiler](Statifier.Compiler.md): The fourth arrow of the parser pipeline: a validated `%Statifier.Document{}`
in, `{:ok, %Statifier.Machine{}} | {:error, [Statifier.Compiler.Error.t()]}`
out (`docs/architecture.md:47-51`). Nothing downstream of this pass ever
sees a `%Statifier.Document{}` again - the interpreter accepts only a
`Machine` (`docs/architecture.md` principle 4).
- [Statifier.Compiler.Error](Statifier.Compiler.Error.md): The compiler's own error shape: `{reason, message, location}`,
character-identical in style to `Statifier.Lowering.Error`
(`lib/statifier/lowering/error.ex:21-36`).
- [Statifier.Compiler.Expressions](Statifier.Compiler.Expressions.md): The expression-compilation seam: compiles raw predicator source - a
`cond`, an `expr`, or a `<content>` text body - into the single
`Machine.expr()` sum type, on its own, before either of its two consumers
(the transition pass's transitions, the executable-content pass's
content/donedata) so neither lands a raw-string field and changes its type
afterwards.
- [Statifier.Document](Statifier.Document.md): The typed parse target: what lowering produces, and what the validator and
the Machine compiler consume.
- [Statifier.Document.Assign](Statifier.Document.Assign.md): An `<assign>` executable-content element: spec 5.4's deep-path datamodel
write.
- [Statifier.Document.Block](Statifier.Document.Block.md): One `<onentry>` or `<onexit>` element: an ordered list of executable
content plus the location of the element that contains it.
- [Statifier.Document.Cancel](Statifier.Document.Cancel.md): A `<cancel>` element: spec 6.3's instruction to cancel a delayed `<send>`.
- [Statifier.Document.Content](Statifier.Document.Content.md): A `<content>` element: static text, an `expr`, markup, or (representably,
if not validly) any combination.
- [Statifier.Document.Data](Statifier.Document.Data.md): A `<data>` element: an `id`, and at most one of `expr`, `src`, or child
text as its value source.
- [Statifier.Document.Datamodel](Statifier.Document.Datamodel.md): A `<datamodel>` element: an ordered list of `<data>` children.
- [Statifier.Document.Donedata](Statifier.Document.Donedata.md): A `<donedata>` element: the optional payload a `:final` state's
`done.state.*` event carries (spec 5.7).
- [Statifier.Document.Foreach](Statifier.Document.Foreach.md): A `<foreach>` executable-content element (spec 4.6): iterates over an
array, binding `item` (and, optionally, `index`) in the datamodel for
each element, then running its own child content once per iteration.
- [Statifier.Document.If](Statifier.Document.If.md): An `<if>` executable-content element (spec 4.3): the partitioned form of
`<if>`/`<elseif>`/`<else>`, quoting spec 4.3.2 exactly
- [Statifier.Document.If.Branch](Statifier.Document.If.Branch.md): One partition of an `<if>` - the executable content between one
partitioning tag (`<if>`, `<elseif>`, or `<else>`) and the next, per
`Statifier.Document.If`'s moduledoc.
- [Statifier.Document.Initial](Statifier.Document.Initial.md): An `<initial>` element: spec 3.6's way to name a compound state's default
entry point via a `<transition>` rather than an `initial` attribute.
- [Statifier.Document.Invoke](Statifier.Document.Invoke.md): An `<invoke>` element: spec 6.4's instruction to create an instance of an
external service.
- [Statifier.Document.Log](Statifier.Document.Log.md): A `<log>` executable-content element: spec 4.7's diagnostic output point.
- [Statifier.Document.Param](Statifier.Document.Param.md): A `<param>` element under `<donedata>`: spec 5.7's key-value alternative to
`<content>`.
- [Statifier.Document.Raise](Statifier.Document.Raise.md): A `<raise>` executable-content element: spec 4.2's way to enqueue an
internal event.
- [Statifier.Document.Script](Statifier.Document.Script.md): A `<script>` element (spec 5.8): a predicator *statement program* body,
run for its side effects on the datamodel (ADR-0026) - not an
expression-bearing node like `<log>`/`<content>`, and compiled through
`Statifier.Compiler.Expressions.compile_program/3` rather than
`compile/3`. Legal both as executable content (`<onentry>`, `<onexit>`, a
transition, an `<if>` branch, a `<foreach>` body) and, spec 5.8, as a
direct child of `<scxml>`, evaluated at document load time -
`Statifier.Lowering.Builders.place/3` sorts the two by parent.
- [Statifier.Document.Send](Statifier.Document.Send.md): A `<send>` element: spec 6.2's instruction to send an event, immediately or
after a delay.
- [Statifier.Document.State](Statifier.Document.State.md): One `<state>`, `<parallel>`, `<final>`, or `<history>` element - a single
struct with a `kind` atom rather than four per-kind structs.
- [Statifier.Document.Transition](Statifier.Document.Transition.md): A `<transition>` element: spec 3.5, matched against events and guarded by
a condition to move the configuration from one set of states to another.
- [Statifier.Duration](Statifier.Duration.md): The one place this engine turns an SCXML duration designation - `<send
delay>`'s attribute string, or a `delayexpr` result - into milliseconds.
Wraps `Predicator.Duration` rather than reimplementing CSS2-style duration
parsing.
- [Statifier.Effect](Statifier.Effect.md): The effect vocabulary (ADR-0003) plus the nine trace effects
(`docs/observability.md` constraint 2) - one `@type t()` union, in this
one module, that every interpreter function emits from and every
consumer pattern-matches against, including `Statifier.Session`, which
drives `<send>`/`<cancel>`/`<invoke>`. This module defines the
vocabulary and the trace gate; it never emits an effect itself.
- [Statifier.Effect.Autoforward](Statifier.Effect.Autoforward.md): Payload for `{:autoforward, %__MODULE__{}}` - spec 6.4's `autoforward`
attribute, Appendix D's `if inv.autoforward: send(inv.id, externalEvent)`
in `mainEventLoop`'s finalize/autoforward pass (`:152-158`). `invoke_id`
names the invocation to forward to; `state_index` is the constraint-3
identity of the invoking state; `event` is the external event that
triggered the pass, carried verbatim; `macrostep`/`microstep`/`round` are
the counters as they stood at the moment of the pass.
- [Statifier.Effect.BudgetExhausted](Statifier.Effect.BudgetExhausted.md): Payload for `{:budget_exhausted, %__MODULE__{}}` - ADR-0019's outcome when
`Statifier.Interpreter.macrostep/1`'s fold spends
`Statifier.MachineState.max_macrostep_rounds` without reaching quiescence.
- [Statifier.Effect.Cancel](Statifier.Effect.Cancel.md): Payload for `{:cancel, %__MODULE__{}}` - spec 6.3's `<cancel>`. `send_id`
is the `sendid`/`sendidexpr` attribute naming the delayed send to cancel;
resolving it against the pending `SendDelayed` timers is
`Statifier.Session`'s job.
- [Statifier.Effect.CancelInvoke](Statifier.Effect.CancelInvoke.md): Payload for `{:cancel_invoke, %__MODULE__{}}` - the cancellation Appendix
D's `exitStates` and `exitInterpreter` both perform with `for inv in
s.invoke: cancelInvoke(inv)` when a state carrying live invocations
exits. `invoke_id` names the invocation to cancel; `state_index` is the
constraint-3 identity of the state that owned it. `macrostep`/`microstep`/
`round` are the counters as they stood at the moment of the cancel.
- [Statifier.Effect.DatamodelChange](Statifier.Effect.DatamodelChange.md): Payload for `{:datamodel_change, %__MODULE__{}}` - one successful datamodel
write, carrying enough to reconstruct the datamodel from the effect stream
alone, without ever calling `Session.snapshot/1` (plan decision 1).
Emitted for every successful write `write_location/4` performs (decision
2); a failed write emits nothing, since the datamodel did not change and
the failure is already observable on the error channel (decision 9). One
exception: a `<send>`'s `idlocation` write that ADR-0047 goes on to reject
(an invalid target or unsupported type, classified after the write lands)
emits no effect either, because the composite error return that carries
the rejection has no effects slot. The write is in the datamodel
regardless - a consumer reading it back through `_event.sendid` sees it -
and live and replay agree because both derive from the core.
- [Statifier.Effect.DatamodelInit](Statifier.Effect.DatamodelInit.md): Payload for `{:datamodel_init, %__MODULE__{}}` - the datamodel's starting
map, emitted once per `Statifier.Interpreter.initialize/2`, before the
first `<data>` value is evaluated (plan decision 1).
- [Statifier.Effect.Done](Statifier.Effect.Done.md): Payload for `{:done, %__MODULE__{}}` - the terminal effect
`exit_interpreter` (Appendix D) produces once, after top-level final
entry, when `Statifier.MachineState.status` becomes `:done`. `donedata`
is the top-level final's resolved `<donedata>` content, or `nil` when the
final carries none. `configuration` is the full configuration (ADR-0005,
ancestors included) as it stood at exit: the full set, so a consumer can
observe the terminal position without switching tracing on, since
`MachineState.configuration` is empty by then and
`Statifier.active_leaf_states/1` correctly reports nothing active. See
`Statifier.Interpreter.exit_interpreter/1`.
- [Statifier.Effect.Invoke](Statifier.Effect.Invoke.md): Payload for `{:invoke, %__MODULE__{}}` - spec 6.4's `<invoke>`. Fields are
the element's own attribute names: `invoke_id` (`id`/`idlocation`,
generated when the element has none), `type`, `src`, `params` (the
resolved `<param>`/namelist payload), `content` (the resolved `<content>`
payload), `autoforward` (the `autoforward` attribute).
- [Statifier.Effect.Log](Statifier.Effect.Log.md): Payload for `{:log, %__MODULE__{}}` - spec 4.7's `<log>`. `label` is the
`label` attribute (`nil` when the element omits it); `value` is the
resolved `expr` (or `nil` for a label-only `<log>`).
- [Statifier.Effect.Send](Statifier.Effect.Send.md): Payload for `{:send, %__MODULE__{}}` - spec 6.2's `<send>`, fired
immediately (no `delay`/`delayexpr`; that variant is
`Statifier.Effect.SendDelayed`). Fields are the element's own attribute
names so the not-yet-implemented session/invoke support, which will give
this effect its semantics, can extend rather than rename them: `event` is
the event name being sent, `target` and `type` are the `target`/`type`
attributes (`nil` when the element omits them), `data` is the resolved
payload, `send_id` is the `id` attribute (generated when the element has
none).
- [Statifier.Effect.SendDelayed](Statifier.Effect.SendDelayed.md): Payload for `{:send_delayed, %__MODULE__{}}` - spec 6.2's `<send>` when
`delay`/`delayexpr` is present. Carries every field
`Statifier.Effect.Send` does, plus `delay_ms`, the resolved delay in
milliseconds. The timer that fires this send is `Statifier.Session`'s to
schedule; this module only defines the shape it schedules.
- [Statifier.Effect.Trace.ContentExecuted](Statifier.Effect.Trace.ContentExecuted.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted when a block of
executable content ran (`docs/observability.md` constraint 2's "content
executed" row). `c_indexes` are the run content nodes' identities
(constraint 3), in execution order.
- [Statifier.Effect.Trace.Done](Statifier.Effect.Trace.Done.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted alongside
`Statifier.Effect.Done` at top-level final entry / `exit_interpreter`
(`docs/observability.md` constraint 2's "done" row). `donedata` and
`configuration` mirror the core `:done` effect's payload - both effects
are built from the same `configuration_at_exit` binding in
`Statifier.Interpreter.exit_interpreter/1`, so they can never disagree.
This effect exists for the observability row (ADR-0012,
`docs/observability.md:68`), not because it is the only carrier of the
configuration.
- [Statifier.Effect.Trace.EntrySet](Statifier.Effect.Trace.EntrySet.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted with
`compute_entry_set`'s result, before any state is entered
(`docs/observability.md` constraint 2's "entry set" row). `indexes` are
the states to be entered (constraint 3, integer indexes), in entry order.
- [Statifier.Effect.Trace.EventDequeued](Statifier.Effect.Trace.EventDequeued.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted when an external or
internal event is selected for processing (`docs/observability.md`
constraint 2's "event dequeued" row). `event` is the dequeued
`Statifier.Event.t()`; `from` names which queue it came off.
- [Statifier.Effect.Trace.ExitSet](Statifier.Effect.Trace.ExitSet.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted before any state is
exited (`docs/observability.md` constraint 2's "exit set" row). `indexes`
are the states to be exited (constraint 3, integer indexes), in exit
order.
- [Statifier.Effect.Trace.FinalizeAutoforward](Statifier.Effect.Trace.FinalizeAutoforward.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted once per external
event, at the end of the finalize/autoforward pass: `for state in
configuration: for inv in state.invoke: if inv.invokeid ==
externalEvent.invokeid: applyFinalize(inv, externalEvent); if
inv.autoforward: send(inv.id, externalEvent)` (Appendix D,
`Statifier.Interpreter`'s own moduledoc section "The finalize/autoforward
pass runs once per external event, inside `handle_event/2`, before
transition selection"). This is a phase boundary Appendix D itself names,
just not one `docs/observability.md`'s constraint-2 table enumerated when
it was written - `<invoke>` did not exist in this interpreter yet
(ADR-0012's parenthetical is illustrative, not a closed list).
- [Statifier.Effect.Trace.InvokePass](Statifier.Effect.Trace.InvokePass.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted once the invoke pass
finishes: `for state in statesToInvoke.sort(entryOrder): for inv in
state.invoke.sort(documentOrder): invoke(inv)` followed by
`statesToInvoke.clear()` (Appendix D, `Statifier.Interpreter`'s own
moduledoc section "The invoke pass runs at the end of every fold, inside
`main_event_loop/3`"). This is a phase boundary Appendix D itself names,
just not one `docs/observability.md`'s constraint-2 table enumerated when
it was written - `<invoke>` did not exist in this interpreter yet
(ADR-0012's parenthetical is illustrative, not a closed list).
- [Statifier.Effect.Trace.MacrostepStable](Statifier.Effect.Trace.MacrostepStable.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted when the
configuration reaches quiescence, i.e. the macrostep's microstep loop has
no more eventless transitions or internal events to drain
(`docs/observability.md` constraint 2's "macrostep stable" row).
`configuration` is the full configuration (ADR-0005, ancestors included)
as it stood at quiescence.
- [Statifier.Effect.Trace.TransitionsSelected](Statifier.Effect.Trace.TransitionsSelected.md): Trace payload for `{:trace, %__MODULE__{}}` - emitted whenever
`select_transitions` returns, including the empty set
(`docs/observability.md` constraint 2's "transitions selected" row).
`t_indexes` are the selected transitions' `t_index` identities (constraint
3, never `%Statifier.Machine.Transition{}` structs), in the order
selection returned them. `event` is the event the selection matched
against, or `nil` for an eventless round.
- [Statifier.Evaluator](Statifier.Evaluator.md): The evaluation half of `docs/datamodel.md`'s evaluation contract
(ADR-0014): one module, one `evaluate/2` over both arms of
`Statifier.Machine.expr()`, built against a context this module's own
`context/1` produces. Mirrors `Statifier.Compiler.Expressions` - one
module per side of the compile/evaluate seam.
- [Statifier.Evaluator.Error](Statifier.Evaluator.Error.md): `Statifier.Evaluator.evaluate/2`'s own error value (ADR-0014 item 4).
- [Statifier.Evaluator.Functions](Statifier.Evaluator.Functions.md): The `Predicator.FunctionProvider` carrying `In/1` (spec 5.9.1), replacing
`Statifier.Evaluator`'s former private closure-building helper.
- [Statifier.Evaluator.SystemVariables](Statifier.Evaluator.SystemVariables.md): Spec 5.10's system variables, as the plain maps
`Statifier.MachineState.datamodel` carries them in. Two functions, so that
neither `Statifier.MachineState` nor `Statifier.Interpreter` grows spec
5.10 knowledge of its own - `MachineState.new/2` calls `initial/2` once,
and `MachineState.put_event/2` calls `event/1` on every write.
- [Statifier.Event](Statifier.Event.md): The value every queue holds and every selection round matches against -
spec 5.10.1's event, `name` plus `data` plus `type`, with the
constraint-4 cause slot (`docs/observability.md`) for events the platform
raised itself.
- [Statifier.Event.Cause](Statifier.Event.Cause.md): Why an internally raised event exists - `docs/observability.md` constraint
4. `origin` is a constraint-3 identity, never a struct; `macrostep`/
`microstep`/`round` are the counters as they stood when the event was
raised, per `Statifier.MachineState`'s counter contract.
- [Statifier.EventData](Statifier.EventData.md): `docs/datamodel.md`'s standing commitment discharged: one function, with
defined rules, that normalizes a value into `_event.data` per spec
B.2.8.1. `<param>` and `<content>` (under `<donedata>`) call it here;
`namelist`, `<send>`, and `<invoke>` extend it rather than reinventing it
when they land.
- [Statifier.ExecutableContent](Statifier.ExecutableContent.md): The one dispatch point every executable-content node implements. There is
no central `case`/`cond` anywhere in this tree that switches on a node's
kind (`docs/architecture.md:101-105`'s named v1 mistake); a node's runtime
behavior lives in exactly one place, this protocol's `defimpl` for that
node's struct, in the same file as the struct itself
(`Statifier.Machine.Content.Raise`, `Statifier.Machine.Content.Log`,
`Statifier.Machine.Content.If`, `Statifier.Machine.Content.Foreach`). A
future datamodel element (`<script>`) or session element
(`<send>`/`<cancel>`/`<invoke>`) adds a struct and a `defimpl`, never a
clause here or in the block runner.
- [Statifier.ExecutableContent.Context](Statifier.ExecutableContent.Context.md): The second argument every `Statifier.ExecutableContent.execute/2` call
receives, alongside the node itself.
- [Statifier.Interpreter](Statifier.Interpreter.md): Appendix D's outer loop, ported function for function (ADR-0002), with its
loop state reified onto `%Statifier.MachineState{}` per
`docs/observability.md` constraint 1: any `%MachineState{}` value is a
complete, resumable interpreter position, and this module keeps nothing
of that position on the call stack.
- [Statifier.Interpreter.Content](Statifier.Interpreter.Content.md): The block runner - spec 4.9's rule for a block of executable content,
ported once here rather than at each of `Statifier.Interpreter.ExitEntry`'s
four call sites: a block runs its nodes in document order; if a node
errors, the rest of the block does not run, and the error becomes an
`error.*` event on the internal queue - `error.execution` for every
failure but one, and `error.communication` for a `<send>` the core
judges undeliverable (ADR-0048) - the errors-are-events conversion
happens here and only here, never in a leaf node's own
`Statifier.ExecutableContent.execute/2` implementation. Other blocks are
unaffected: a block that errors leaves every other block - another
`<onentry>` on the same state, an `<onexit>`, a transition's own content -
to run exactly as if nothing had happened, since each call to
`execute_block/3` is independent.
- [Statifier.Interpreter.Datamodel](Statifier.Interpreter.Datamodel.md): Datamodel creation and early/top-level binding - the `interpret` preamble
hook (`Statifier.Interpreter.initialize/2`).
- [Statifier.Interpreter.Datamodel.Write](Statifier.Interpreter.Datamodel.Write.md): What `Statifier.Interpreter.Datamodel.write_location/4` wrote - a report of
a write that already happened, never an instruction to perform one. `path`
is the resolved `Predicator.ContextLocation.location_path()`, `new_value` is
what was written, and `prior_value` is what stood at that full path
immediately before the write - `:undefined` when nothing did, per
ADR-0037's single spelling for an unbound value. This does conflate "the
path was absent" with "the path held `:undefined`" already; that is
accepted, since `prior_value` exists for diffing and undo, never for
reconstruction.

- [Statifier.Interpreter.ExitEntry](Statifier.Interpreter.ExitEntry.md): Appendix D's exit and entry blocks, ported function for function
(ADR-0002) - the half of the algorithm that changes the configuration.
`Statifier.Interpreter.Selection` answers "which transitions fire and
what would they leave"; this module actually leaves and enters states.
- [Statifier.Interpreter.NameMatch](Statifier.Interpreter.NameMatch.md): Spec 3.13 event descriptor matching - Appendix D's `nameMatch`, under
ADR-0002's predicate-naming amendment.
- [Statifier.Interpreter.Selection](Statifier.Interpreter.Selection.md): Appendix D transition selection, ported function for function (ADR-0002).
- [Statifier.Invoke.Handler](Statifier.Invoke.Handler.md): The extension seam `docs/datamodel.md` has always pointed hosts at
("real computation belongs in the host application, reached through
`<invoke>` handlers") but never had until ADR-0051: a behaviour a host
implements to serve `<invoke type="...">` values beyond the built-in
`scxml` handler (`Statifier.Invoke.Handler.Scxml`, sitting beside this
module the way `Statifier.Invoke.Source` does).
- [Statifier.Invoke.Handler.Scxml](Statifier.Invoke.Handler.Scxml.md): The built-in `type=scxml` (and long-URI, `http://www.w3.org/TR/scxml/`)
`Statifier.Invoke.Handler` - `Statifier.Session.Effects.plan_invoke/3`'s
default entry for the built-in type set, not a name it special-cases
(ADR-0051 decision 4).
- [Statifier.Invoke.Source](Statifier.Invoke.Source.md): Turns an `%Statifier.Effect.Invoke{}`'s `content`/`src` pair into a
`Statifier.Machine.t()` ready to start as a child session - the seam
ADR-0038 decided: **the library never dereferences `src`.**
- [Statifier.Invoke.Types](Statifier.Invoke.Types.md): A caller-declared, point-in-time claim about which `<invoke type>` values
this deployment implements beyond the built-in `scxml` handler (ADR-0051
decision 2) - a plain value in `Statifier.Invoke`'s namespace, mirroring
`Statifier.Send.Routes`'s own shape and moduledoc posture.
- [Statifier.Lowering](Statifier.Lowering.md): The second arrow of the parser pipeline: a generic
`%Statifier.Parser.DOM.Element{}` tree in, a typed `%Statifier.Document{}`
tree out (`docs/architecture.md`, "Parser: DOM first, then lowering").
- [Statifier.Lowering.Attributes](Statifier.Lowering.Attributes.md): The four attribute operations every builder in `Statifier.Lowering.Builders`
needs: read a raw value, split a whitespace-separated value into a list,
map a value onto a known atom with a default, and record a value span into
`attribute_locations`.
- [Statifier.Lowering.Builders](Statifier.Lowering.Builders.md): One `build_*` function per supported SCXML element, reached through
`Statifier.Lowering`'s dispatch map - the structural fix for v1's
903-line, 73-clause `state_stack.ex` (`docs/architecture.md`,
"adding an element touches one builder").
- [Statifier.Lowering.Error](Statifier.Lowering.Error.md): Lowering's own error shape: never raised, always collected into a list.
- [Statifier.Lowering.Namespace](Statifier.Lowering.Namespace.md): Prefix scope resolution for `Statifier.Lowering`'s walk.
- [Statifier.Machine](Statifier.Machine.md): The compiled, valid-by-construction interpreter input
(`docs/architecture.md:47-51`, principle 4). `Statifier.Compiler.compile/1`
is the only producer; the interpreter is the only consumer that matters -
every other layer stops at `%Statifier.Document{}`.
- [Statifier.Machine.Block](Statifier.Machine.Block.md): One compiled `<onentry>` or `<onexit>` element - the interned counterpart
to `Statifier.Document.Block`, built by the compiler's executable-content
pass.
- [Statifier.Machine.Content](Statifier.Machine.Content.md): Namespace for the compiled executable-content node family: one struct per
node kind, `Statifier.Machine.Content.Raise`, `Statifier.Machine.Content.Log`,
`Statifier.Machine.Content.Assign`, `Statifier.Machine.Content.If`,
`Statifier.Machine.Content.Foreach`, `Statifier.Machine.Content.Script`,
`Statifier.Machine.Content.Send`, and `Statifier.Machine.Content.Cancel`,
the interned counterpart to `Statifier.Document.Raise` /
`Statifier.Document.Log` / `Statifier.Document.Assign` /
`Statifier.Document.If` / `Statifier.Document.Foreach` /
`Statifier.Document.Script` / `Statifier.Document.Send` /
`Statifier.Document.Cancel`. This module owns the family's shared
vocabulary - `owner/0` and the `t()` union - and no longer a struct
itself: an Elixir protocol dispatches on the struct module, so each node
kind needs its own struct for `Statifier.ExecutableContent` to implement
without a central `case` on a `kind` field. Each future executable-content
node gets its own struct here too, and its own `Statifier.ExecutableContent`
implementation, never a clause added to this module.
- [Statifier.Machine.Content.Assign](Statifier.Machine.Content.Assign.md): A compiled `<assign>` executable-content node (spec 5.4, 5.9.2) - the
interned counterpart to `Statifier.Document.Assign`.
- [Statifier.Machine.Content.Cancel](Statifier.Machine.Content.Cancel.md): A compiled `<cancel>` executable-content node (spec 6.3) - the interned
counterpart to `Statifier.Document.Cancel`.
- [Statifier.Machine.Content.Foreach](Statifier.Machine.Content.Foreach.md): A compiled `<foreach>` executable-content node (spec 4.6) - the interned
counterpart to `Statifier.Document.Foreach`. `array` is the compiled
`Machine.expr()` the iteration source evaluates once, before any
iteration (spec 4.6.3's shallow copy - see step 3 in `execute/2`'s doc
below for why one evaluation is enough). `item`/`index` are the raw
attribute strings - bare variable names by 4.6.2, so neither is compiled
or resolved any earlier than `execute/2`. `content` is the dense,
document-order `c_index` list of `<foreach>`'s own body, resolved through
`Statifier.Machine.content/2` at runtime rather than carried inline
(`Statifier.Compiler`'s Decision 2).
- [Statifier.Machine.Content.If](Statifier.Machine.Content.If.md): A compiled `<if>` executable-content node (spec 4.3, 4.4, 4.5) - the
interned counterpart to `Statifier.Document.If`. `branches` is the
document-order partition list: each `Statifier.Machine.Content.If.Branch`
holds its compiled `cond` (`nil` for the `<else>` branch - spec 4.5.1:
"`<else>` ... is equivalent to an `<elseif>` with a 'cond' that always
evaluates to true"), the diagnostic span that `cond` compiled against, and
the dense `c_index` list assigned to that partition's own content
(`Statifier.Compiler`'s Decision 2), resolved through
`Statifier.Machine.content/2` at runtime rather than carried inline.
- [Statifier.Machine.Content.If.Branch](Statifier.Machine.Content.If.Branch.md): One compiled `<if>`/`<elseif>`/`<else>` partition - a small struct
alongside `Statifier.Machine.Content.If` (Decision 8 of the plan cited on
the parent module), parallel to `Statifier.Document.If.Branch` without
being identical to it: this struct carries no `c_index` of its own (a
branch is not itself a dispatchable content node, only its own content
is), and its `cond` is already compiled.
- [Statifier.Machine.Content.Log](Statifier.Machine.Content.Log.md): A compiled `<log>` executable-content node (spec 4.7) - the interned
counterpart to `Statifier.Document.Log`. `label` is the optional
diagnostic label; `expr` is the optional `Machine.expr()` to evaluate and
log; `expr_location` is `attribute_locations[:expr]`'s value span, `nil`
when `expr` was never written.
- [Statifier.Machine.Content.Raise](Statifier.Machine.Content.Raise.md): A compiled `<raise>` executable-content node (spec 4.2) - the interned
counterpart to `Statifier.Document.Raise`. `event` is the literal event
name being enqueued - never tokenized, unlike a `<transition>`'s `event`
attribute (`lib/statifier/document/raise.ex:6-13`).
- [Statifier.Machine.Content.Script](Statifier.Machine.Content.Script.md): A compiled `<script>` executable-content node (spec 5.8, ADR-0026) - the
interned counterpart to `Statifier.Document.Script`.
- [Statifier.Machine.Content.Send](Statifier.Machine.Content.Send.md): A compiled `<send>` executable-content node (spec 6.2) - the interned
counterpart to `Statifier.Document.Send`.
- [Statifier.Machine.Data](Statifier.Machine.Data.md): One compiled `<data>` element - the interned counterpart to
`Statifier.Document.Data`, dense from `d_index` 0 across the whole machine
(ADR-0012 item 3), read via `Statifier.Machine.data/2`.
- [Statifier.Machine.Donedata](Statifier.Machine.Donedata.md): One compiled `<donedata>` element - the interned counterpart to
`Statifier.Document.Donedata`, built by the compiler's executable-content
pass, reachable only through its owning `:final` state as
`elem(machine.states, i).donedata`.
- [Statifier.Machine.Identity](Statifier.Machine.Identity.md): A chart's identity: a content hash taken over the SCXML source
`Statifier.compile/2` received, plus an optional embedder-supplied name and
version. `Statifier.compile/2` stamps one onto every `Statifier.Machine.t()`
it produces (`Statifier.Machine.identity/1`).
- [Statifier.Machine.Invoke](Statifier.Machine.Invoke.md): One compiled `<invoke>` element (spec 6.4) - the interned counterpart to
`Statifier.Document.Invoke`, reachable only through its owning state as
`elem(machine.states, i).invoke`, in document order.
- [Statifier.Machine.Param](Statifier.Machine.Param.md): One compiled `<param>` element - the interned counterpart to
`Statifier.Document.Param`. A `%Param{}` is not reachable only through
`Statifier.Machine.Donedata.params`: `Statifier.Machine.Content.Send` and
`Statifier.Machine.Invoke` each own a `namelist` and a `params` list of
`Param.t()` too.
- [Statifier.Machine.State](Statifier.Machine.State.md): One compiled `<scxml>`, `<state>`, `<parallel>`, `<final>`, or `<history>`
element - the interned, indexed counterpart to `Statifier.Document.State`
(and, for index 0, to `Statifier.Document` itself).
- [Statifier.Machine.Transition](Statifier.Machine.Transition.md): One compiled `<transition>` element - the interned counterpart to
`Statifier.Document.Transition`, built by the compiler's transition pass.
- [Statifier.MachineState](Statifier.MachineState.md): The reified interpreter position - every Appendix D global and loop
variable this core keeps, per `docs/observability.md` constraint 1
(ADR-0012): any `%MachineState{}` value is a complete, inspectable,
resumable position. `Statifier.Machine` is the compiled document this
struct walks; interpreter modules alias `Statifier.MachineState` as
`MachineState` and `Statifier.Machine.State` as `State`, never
abbreviating either further, because the two names are one character
apart and mean very different things - a compiled state versus a runtime
position.
- [Statifier.Parser](Statifier.Parser.md): XML source in, generic DOM tree out.
- [Statifier.Parser.DOM](Statifier.Parser.DOM.md): The generic document tree `Statifier.Parser.parse/1` produces, and the three
accessors every lowering builder would otherwise re-implement.
- [Statifier.Parser.DOM.Attribute](Statifier.Parser.DOM.Attribute.md): One attribute of an element, carrying two spans rather than one.
- [Statifier.Parser.DOM.Element](Statifier.Parser.DOM.Element.md): A generic XML element: a name, an ordered attribute list, an ordered child
list, and the source span it occupies.
- [Statifier.Parser.DOM.Text](Statifier.Parser.DOM.Text.md): A run of character data between two markup constructs.
- [Statifier.Parser.Handler](Statifier.Parser.Handler.md): The `Saxy.Handler` that builds a `Statifier.Parser.DOM` tree, attaching the
positions Saxy does not supply.
- [Statifier.Parser.Location](Statifier.Parser.Location.md): A source span: 1-based line/column (columns counted in Unicode codepoints),
0-based byte offsets, exclusive end - the shape ADR-0014 fixed for
expression spans, used here for XML nodes so the two compose.
- [Statifier.Parser.Markup](Statifier.Parser.Markup.md): A total, left-to-right scan of an XML source binary that produces the
positions Saxy does not.
- [Statifier.Position](Statifier.Position.md): The versioned binary contract for a *position* - a `Statifier.MachineState.t()`
with the compiled chart it walks stripped out and its `Statifier.Machine.Identity.t()`
carried alongside instead.
- [Statifier.Replay](Statifier.Replay.md): Re-drives a `Statifier.Session.Recording` through the pure core, with no
process and no timer (ADR-0034).
- [Statifier.Send.Routes](Statifier.Send.Routes.md): A caller-declared, point-in-time claim about which `<send>` routes are
live (ADR-0048 decision 1) - a plain value in `Statifier.Send.Target`'s
neutral namespace (ADR-0047 decision 3), carrying exactly what
`Statifier.Session.deliver/5` resolves today: the set of session ids
reachable by `{:session, sid}`, whether a parent exists for `:parent`,
and the set of live invoke ids reachable by `{:invoke, id}`.
- [Statifier.Send.Target](Statifier.Send.Target.md): Spec 6.2.2's `target` attribute and C.1's special-target vocabulary,
parsed into a route, plus the supported-`type` predicate 6.2.5 asks for.
One pure module, no process, no effect calls - `Mix.Statifier.AdrGuard`
has nothing to say about it and no exemption is needed. It has two
consumers: the core's `<send>` node, which rejects a `{:invalid, _}`
target or an unsupported `type` under ADR-0047, and
`Statifier.Session.Effects`, which applies the same classification at
`Statifier.Session.interpret/2`'s boundary (ADR-0029).
- [Statifier.Session](Statifier.Session.md): The GenServer effect interpreter (ADR-0003): the outer `while running`
loop, the waiting external events, the delayed-send timers, and the
fan-out of the effect stream to subscribers. The pure core decides; this
module performs.
- [Statifier.Session.Effects](Statifier.Session.Effects.md): Turns the effect list the pure core returns into an ordered list of
instructions for `Statifier.Session` to perform (ADR-0003). Deciding is
here, where it is a pure function of the effect list; performing is there,
where the process is.
- [Statifier.Session.Inbox](Statifier.Session.Inbox.md): The waiting external events, plus Appendix D's `isCancelEvent` check.
- [Statifier.Session.Invocations](Statifier.Session.Invocations.md): The parent-held invocation table, as a value (ADR-0027 decision 3):
`invokeid -> {child_session_id, pid, monitor_ref}`, plus the `autoforward`
flag the delivery half (`{:forward, invoke_id, event}`) reads. A reverse
index, `pid -> invoke_id`, is carried alongside so a child's own `:DOWN`
can be resolved with no scan.
- [Statifier.Session.Recording](Statifier.Session.Recording.md): The four-input replay recording (ADR-0029), as a value.
- [Statifier.Session.Telemetry](Statifier.Session.Telemetry.md): The `:telemetry` bridge (ADR-0040) - the single authoritative reference for
every `[:statifier, :session, ...]` event `Statifier.Session` can emit.
`Statifier.Session` is the ADR-0003 effect interpreter; this module is the
emission half of that role, split out only because `.doctor.exs`'s 100%
Doctor bar puts the event contract in a `@moduledoc` a consumer can read
without opening the source (ADR-0040's "the session boundary is two
files"). It holds no state, drives no core function, and is called from
nowhere but `Statifier.Session`.
- [Statifier.Session.Timers](Statifier.Session.Timers.md): The pending delayed-send timers, as a value.
- [Statifier.Supervisor](Statifier.Supervisor.md): The ADR-0027 session runtime: a module-based supervisor holding the
library's named session registry and the flat dynamic supervisor sessions
started through `Statifier.start_session/2` land on.
- [Statifier.Testing.Case](Statifier.Testing.Case.md): Test case template for the SCION and W3C conformance corpora.
- [Statifier.Testing.FeatureDetector](Statifier.Testing.FeatureDetector.md): Detects SCXML features used in documents so the test harness can fail
precisely on unsupported features.
- [Statifier.Testing.HandlerCase](Statifier.Testing.HandlerCase.md): A reusable conformance case for `Statifier.Invoke.Handler` implementations
- the second member of the `Statifier.Testing` family ADR-0053 opened, and
the mechanical pin for the behaviour contract ADR-0051 decision 4 and
`docs/extending.md` state in prose. A host application `use`s this module
in a test alongside `use ExUnit.Case` and gets the contract checks as
generated tests against its own handler
- [Statifier.Validator](Statifier.Validator.md): The third arrow of the parser pipeline, and the only gate in front of the
Machine compiler (`docs/architecture.md` principle 4): a `%Statifier.Document{}`
in, `{:ok, document, warnings} | {:error, errors, warnings}` out. The
interpreter only ever accepts a compiled Machine, so there is no
"validate if not already validated" fallback anywhere downstream - this
pass is the single place a malformed document is ever caught.
- [Statifier.Validator.Checks.Assign](Statifier.Validator.Checks.Assign.md): Spec 5.4.2: "A conformant SCXML document MUST specify either 'expr' or
children of `<assign>`, but not both." Reports `{:assign_expr_and_text,
expr}` at the `<assign>`'s own element span.
- [Statifier.Validator.Checks.Boilerplate](Statifier.Validator.Checks.Boilerplate.md): Checks 9 and 10 (spec 3.2.1), which close the boilerplate gap that
relaxed parsing left open. Lowering accepts a boilerplate-free `<scxml>` fragment
unconditionally (`Statifier.Lowering.Namespace.scxml_vocabulary?/1`
treats a `nil` namespace as SCXML's own vocabulary), so this is the only
place in the pipeline that ever refuses one.
- [Statifier.Validator.Checks.Cancel](Statifier.Validator.Checks.Cancel.md): Spec 6.3.1's single constraint on `<cancel>`: "A conformant SCXML document
MUST specify exactly one of sendid or sendidexpr." Reports
`{:cancel_sendid_and_sendidexpr}` when both are present and
`{:cancel_no_sendid}` when neither is, both at the `<cancel>` element's
own `location`.
- [Statifier.Validator.Checks.Content](Statifier.Validator.Checks.Content.md): Spec 5.6: a `<content>` element must not specify both an `expr`
attribute and inline content, whether that content is text or markup
(ADR-0041). Reports `{:content_expr_and_text, expr}` at the `<content>`
element's own `location` - same reason, same shape, regardless of which
form the content takes.
- [Statifier.Validator.Checks.Data](Statifier.Validator.Checks.Data.md): Check 13: `<datamodel>` and `<data>` structural rules that lowering leaves
representable on purpose (`lib/statifier/document/data.ex`,
`lib/statifier/document/datamodel.ex`), following the same division of
labour `Checks.Content` and `Checks.Donedata` already have with their own
document nodes.
- [Statifier.Validator.Checks.DefaultEntry](Statifier.Validator.Checks.DefaultEntry.md): Check 7 (spec 3.3): a compound `<state>` with no `initial`
attribute and no `<initial>` element falls back to entering its first
child in document order (spec 3.3). That fallback is only legal when the
first child is itself enterable - a `:history` pseudo-state is not, since
spec 3.10 makes it entered only by a transition that targets it
explicitly - "enterable" here means "not a history pseudo-state".
- [Statifier.Validator.Checks.DefaultTransition](Statifier.Validator.Checks.DefaultTransition.md): The sub-check checks 4 and 5 share: an `<initial>` element's
and a `:history` state's whole content model is one constrained
`<transition>` - required, exactly one, a non-null `target`, no `event`,
no `cond`. Spec 3.6 states this for `<initial>`; spec 3.10 states it for
`<history>`'s default transition, more strictly than a looser
"when present" reading - the spec's stricter wording wins.
- [Statifier.Validator.Checks.Donedata](Statifier.Validator.Checks.Donedata.md): Check 8 (spec 3.7, 5.7): `<donedata>` is only legal on a `:final` state.
Reports `{:donedata_not_on_final, id}` for any non-`:final` state
carrying a non-nil `donedata`, at the `donedata`'s own `location` -
`lib/statifier/document/donedata.ex` names this check as the layer that
reports the shape rather than one that refuses to build it.
- [Statifier.Validator.Checks.Enums](Statifier.Validator.Checks.Enums.md): Out-of-range enumerated attribute values (spec 3.2.1 and 3.5).
- [Statifier.Validator.Checks.Final](Statifier.Validator.Checks.Final.md): Check 6 (spec 3.7): a `:final` state's content model is `onentry`,
`onexit`, and `donedata` - nothing else. Two reasons, each reported once
per offending child and at the **child's own** `location` rather than the
`<final>`'s, so the caret lands on the element that should not be there
- [Statifier.Validator.Checks.FinalParent](Statifier.Validator.Checks.FinalParent.md): Check 12 (spec 3.7, Appendix D `enterStates`): a `<final>` state's parent
carries no `id`. Entering a non-top-level `<final>` raises
`done.state.{parent.id}` (`lib/statifier/interpreter/exit_entry.ex`'s
`raise_parent_completion/3`), so a parent with no written `id` has a
completion event the spec names after a name it does not have.
- [Statifier.Validator.Checks.History](Statifier.Validator.Checks.History.md): Check 5 (spec 3.10): a `:history` state's placement, default transition,
and `type`. Four independent facts, per `:history` state in the document
- [Statifier.Validator.Checks.Ids](Statifier.Validator.Checks.Ids.md): Check 1 (spec 3.14): an `ID`-typed attribute's value is unique across the
document - not only a state's `id`, but a `<data>`'s too. 3.14: "all
attributes of type "ID" MUST have unique values within an SCXML
document", and `<data>`'s `id` is type `ID` (5.3.1) - so a
`<data id="s1">` colliding with a `<state id="s1">` is exactly as much a
violation as two states sharing one id, and both join **one** uniqueness
set rather than two separate ones. `nil` ids are excluded
(`lib/statifier/document/state.ex` - a `nil` id means "the author omitted
an optional attribute", not "no id"; `<data>` has no `nil` id, since `id`
is required to build a `Data` struct at all), and document scope, not
session scope, is what this layer can see.
- [Statifier.Validator.Checks.If](Statifier.Validator.Checks.If.md): Spec 4.3.2: "In a conformant SCXML document, `<else>` MUST occur after all
`<elseif>` tags." `Statifier.Lowering.Builders.build_if/2` has already
partitioned an `<if>`'s children into `branches` by the time a
`%Statifier.Document.If{}` reaches the validator, so this check reads
branch order directly rather than re-parsing `<elseif>`/`<else>` element
names.
- [Statifier.Validator.Checks.InitialElement](Statifier.Validator.Checks.InitialElement.md): Check 4 (spec 3.3, 3.6): a state's own `<initial>` element.
- [Statifier.Validator.Checks.InitialTargets](Statifier.Validator.Checks.InitialTargets.md): Check 3 (spec 3.2, 3.3, 3.6): every `initial` reference - a state's
`initial` attribute, a state's `<initial>` element, and the document's own
root `initial` attribute - resolves and lands on a legal target. Three
reasons, in this precedence
- [Statifier.Validator.Checks.Invoke](Statifier.Validator.Checks.Invoke.md): Spec 6.4.1's five mutual-exclusion constraints on `<invoke>`'s attributes
and children, each reported at the `<invoke>` element's own `location`
- [Statifier.Validator.Checks.Param](Statifier.Validator.Checks.Param.md): Spec 5.7: "A conformant SCXML document MUST specify either the 'expr'
attribute of `<param>` or the 'location' attribute, but MUST NOT specify
both." Reports `{:param_expr_and_location, name}` when both are present
and `{:param_no_value, name}` when neither is, both at the `<param>`
element's own `location`.
- [Statifier.Validator.Checks.Script](Statifier.Validator.Checks.Script.md): Spec 5.8.2: "A conformant SCXML document MUST specify either the 'src'
attribute or child content, but not both." The `src`-and-content pair is
unreachable through this codebase's lowering (`Statifier.Lowering.
Builders.build_script/2` already refuses to build a struct when `src` is
written, per ADR-0026 decision 2 - `src` is rejected regardless of any
child text), so this check has exactly one remaining job: a `<script>`
with **neither** `src` nor non-blank text is an empty script, which the
spec's MUST also forbids. Reports `{:script_no_src_or_text}` at the
`<script>`'s own element span.
- [Statifier.Validator.Checks.Send](Statifier.Validator.Checks.Send.md): Spec 6.2.2's mutual-exclusion constraints on `<send>`'s attributes and
children, each reported at the `<send>` element's own `location`
- [Statifier.Validator.Checks.Targets](Statifier.Validator.Checks.Targets.md): Check 2 (spec 3.5): every `<transition>`'s `target` id resolves to a
state in the document. Walks `Context.transitions` - every owner
(`:plain`, `:initial`, `:history`) in one traversal - and reports
`{:unresolved_target, id}` per unresolved id, at that transition's own
`target` span (falling back to the transition's own span when
unwritten).
- [Statifier.Validator.Context](Statifier.Validator.Context.md): The throwaway index the checks share, built once per `Statifier.Validator.validate/2`
call and discarded afterward. It must never be returned, cached, or handed
to the compiler: `Statifier.Compiler` builds the real interned index, and
sharing this one would couple two layers the architecture keeps
independent. Correctness over speed here, per the bead's own design note.
- [Statifier.Validator.Error](Statifier.Validator.Error.md): The validator's own error shape: never raised, always collected into a
list. Mirrors `Statifier.Lowering.Error`'s shape (`reason`, `message`,
`location`) with character-identical field names, so a future common
diagnostic protocol can adopt both without either layer's reason union
leaking into the other's. The two layers' error lists are never observed
together - `Statifier.Validator.validate/2` only ever receives a document
lowering already accepted - so sharing the *shape* rather than the type is
enough.
- [Statifier.Validator.Warning](Statifier.Validator.Warning.md): The validator's non-fatal finding shape: never raised, always collected
into a list, and never gating compilation. Mirrors
`Statifier.Validator.Error`'s shape character for character - the same
three enforced fields (`reason`, `message`, `location`), a closed
`reason` union declared once in full, one public constructor per variant,
and a `code/1` tag extractor. `Error`'s own moduledoc already states that
it and `Statifier.Lowering.Error` share a *shape*, not a type, precisely so
a later diagnostic struct can join the family without any layer's reason
union leaking into another's; this module is that later member.

- Exceptions
  - [Statifier.Parser.ParseError](Statifier.Parser.ParseError.md): The parser's own error shape: never `%Saxy.ParseError{}` directly, so
callers get one error type regardless of what failed inside.

## Mix Tasks

- [mix adr.check](Mix.Tasks.Adr.Check.md): Reports lines the branch adds that look like violations of ADR-0002 (Appendix
D naming), ADR-0003 (pure core with effects), ADR-0004 (predicator as the
datamodel), ADR-0008 (generated identifier formats), or ADR-0018 (process
artifacts are not code comments) - plus, since ADR-0058, three checks that
are not about the diff at all: `docs/adr/` numbers colliding,
`docs/adr/README.md`'s table falling out of bijection with the directory,
and a branch-added ADR number that already exists on the base ref under a
different filename.
- [mix adr.judge](Mix.Tasks.Adr.Judge.md): Reports likely violations of any judged ADR (`Mix.Statifier.AdrJudge`'s
registry) in the current branch's diff against its base, each one proposed
by one model call and required to survive an independent second call
prompted to refute it.
- [mix gate.check](Mix.Tasks.Gate.Check.md): Reports changes to the quality gate's own configuration that the branch does
not also record in `docs/quality-gate-changes.md`.
- [mix gate.verify](Mix.Tasks.Gate.Verify.md): Runs `mix quality` and attests that what it ran was the full gate.
- [mix test.baseline](Mix.Tasks.Test.Baseline.md): Finds conformance tests that pass but are not yet in the regression
registry, and adds them once they are verified.
- [mix test.regression](Mix.Tasks.Test.Regression.md): Runs exactly the tests listed in `test/passing_tests.json`.

