| # | Decision | Status |
|---|---|---|
| 0001 | Record architecture decisions | accepted |
| 0002 | Port the W3C SCXML algorithm literally (Appendix D) | accepted (amended 2026-08-09: predicate naming) |
| 0003 | Pure functional core returning effects | accepted |
| 0004 | Predicator is the datamodel; no ECMAScript, no Elixir eval | accepted (amended in part by 0026: <script>) |
| 0005 | Full configuration; interned state indexes | accepted |
| 0006 | Reuse conformance corpus and ratchet; commit a generator | accepted |
| 0007 | Beads for issue tracking | accepted |
| 0008 | UXID for generated identifiers | accepted (amended 2026-08-15: invoke id format; invoke platformid is a session counter, not a UXID; amended 2026-08-15: the uxid dependency is dropped, the format decisions stand) |
| 0009 | ex_quality is the quality gate | accepted |
| 0010 | Worktree parallel development via beads | accepted |
| 0011 | Quality gate config is not agent-editable | accepted |
| 0012 | Debuggability is designed into the core | accepted |
| 0013 | Archive the v1 statifier repo in place | accepted |
| 0014 | Expression-level spans are part of the retained-location constraint | accepted (amended 2026-08-15: item 4 stops at the predicator seam; engine policy checks are not expression failures; amended 2026-08-18: item 4's protected-root refusal is a policy check, not a predicator error) |
| 0015 | Skill mechanics live in scripts, judgment lives in prose | superseded by 0017 (amended in part by 0016) |
| 0016 | The wurk skills live in their own repo; this repo gates its extensions | accepted (amends 0015 in part; amended by 0017) |
| 0017 | Judgment is not scriptable, scoped to the wurk extension surface | accepted (supersedes 0015; amends 0016 in part) |
| 0018 | Process artifacts are not code comments | accepted |
| 0019 | A round budget bounds the macrostep fold | accepted (amended in part by 0020: round ordinal; amended in part by 0032: invoke re-entry) |
| 0020 | A round ordinal joins the step counters | accepted (amends 0019 in part; amended in part by 0046: the core-effect exemption is withdrawn) |
| 0021 | A failed donedata content expr yields no data | accepted |
| 0022 | A parallel is never the LCCA; SCION's contrary tests leave the corpus | accepted |
| 0023 | Numeric-type gaps are fixed in predicator, never coerced at the boundary | accepted |
| 0024 | <data src> is never fetched | accepted |
| 0025 | Tracker authority follows the artifact; mirrors pull (adopts predicator ADR-0010) | accepted |
| 0026 | <script> bodies are predicator statement programs | accepted (amends 0004 in part) |
| 0027 | Embedder-placed session runtime with a named registry | accepted |
| 0028 | Executable-content blocks thread one context and bind/3 each write | accepted |
| 0029 | Session.interpret/2 stays public; replay records four inputs | accepted |
| 0030 | In/1 becomes a provider; the built context still is not a MachineState field | accepted (amended 2026-08-15: predicator 8.0 memoization; hoist kept) |
| 0031 | A failed invoke argument evaluation aborts the invocation | accepted |
| 0032 | The round budget spans the invoke pass's re-entry | accepted (amends 0019 in part) |
| 0033 | The validator has a warning tier; warnings ride on the Machine | accepted |
| 0034 | Replay re-drives the core, not a live session; recording carries ordinal order, no clock | accepted |
| 0035 | The send id is send_<n> off a new machine_state.send_counter | accepted (amended 2026-08-15: cross-session sendid collision recorded harmless) |
| 0036 | A failed <send> argument discards the message (amends 0021 in part) | accepted |
| 0037 | Unbound is spelled :undefined at the writer; nil means null | accepted |
| 0038 | <invoke>'s source resolves at the session boundary, never inside the library | accepted |
| 0039 | Session-detected send failures re-enter the core through deliver_internal/5 | accepted (amended in part by 0047: the rejected alternative is scoped to liveness; amended in part by 0048: the core may judge reachability against a caller-declared route snapshot) |
| 0040 | Session telemetry event contract: the [:statifier, :session, ...] bridge, measurements-vs-metadata split, and trace-off policy | accepted (amended 2026-08-16: singleton location carve-out withdrawn; no trace event carries a location; amended 2026-08-16: :datamodel_change joins the core effect events; amended in part by 0046: round joins every core-effect event's measurements; amended in part by 0059: ordinal joins the :send_delayed and :cancel events' measurements; amended in part by 0063: caller_context joins the macrostep and durable-timer events' metadata) |
| 0041 | <content> markup lowers to a source slice, compiled at invoke time | accepted (amended 2026-08-16: namespace limitation corrected - the corpus child documents do not compile standalone; amended in part by 0042) |
| 0042 | Invoke content markup compiles under the relaxed namespace rule | accepted (amends 0041 in part) |
| 0043 | Attribute values normalize per XML 1.0 3.3.3, guided by the raw source | accepted |
| 0044 | Re-entry effects defer to the outer batch; subscriber delivery is monotone in (macrostep, round) and {:halted, _} is end-of-stream | accepted |
| 0045 | Character data folds line breaks per XML 1.0 2.11, guided by the raw source (resolves 0043's open question) | accepted |
| 0046 | Every core effect carries round; the ADR-0020 exemption is withdrawn and round joins the core-effect event measurements | accepted (amends 0020 in part; amends 0040 in part) |
| 0047 | Static send target/type invalidity rejects in the core; reachability stays session-side, test496 deferred to its own record | accepted (amends 0039 in part) |
| 0048 | Send reachability is judged in the core against a caller-declared route snapshot; core-detected unreachability aborts the block (discharges 0047 decision 6's deferral) | accepted (amends 0039 in part) |
| 0049 | Late subscribers catch up by replaying the recording; no header effect joins the stream | accepted |
| 0050 | Invoked children inherit the parent's observers by opt-in; the invocation table gets a public accessor | accepted |
| 0051 | Invoke handlers are registered per session; the registered invoke-type set becomes core-visible deployment state | accepted |
| 0052 | Chart identity is a content hash of the SCXML source; a position blob carries identity and a format version, checked before use | accepted |
| 0053 | The chart-author test helpers ship in lib/ under Statifier.Testing | accepted (amends 0006 in part) |
| 0054 | Durable timers consume the effect vocabulary; the host owns keying and the 6.2 discard | accepted (amended 2026-08-19: decisions 2, 3, and 4 corrected; decision 2's recorded gap decided by 0055; decision 3's residual foreach collision decided by 0059) |
| 0055 | Non-self delayed-send routes stay the library's: #_parent/#_invokeid/#_internal permanently, the external-session route deferred with a named trigger; no route field joins %SendDelayed{} | accepted (decides 0054's recorded gap) |
| 0056 | After a renumbering, pointer citations move (path fix plus an at-the-time note) and historical statements stand; cross-repo ADR citations must name the repo | accepted |
| 0057 | A recording blob nests the chart blob in the compiled %Machine{}'s place; the codec lives on the @opaque owner; :invoke_handlers cross the boundary as strings, never as atoms or code | accepted (answers 0052 decision 8's follow-up) |
| 0058 | ADR number collisions fail the gate via a tree-local numbering invariant; the README table becomes machine-read | accepted (amended 2026-08-19: decision 2's bite point corrected - the base-ref half fires after the rebase, not merely after a fetch; its addition is the rename/renumber shape; renumbered from 0056 before merge) |
| 0059 | %SendDelayed{} and %Cancel{} carry a per-execution ordinal off a new timer_counter; the durable dedup key gains it as its eighth component and the foreach author guidance retires | accepted (amends 0054 in part; amends 0040 in part) |
| 0060 | Session.start_link/2 gains a :resume option for a position blob or %MachineState{}; resume requires an identified chart, keeps the position's _sessionid, refuses a non-quiescent or terminated position, carries active_invocations verbatim, and anchors a resumed session's recording at the resumed position | accepted (amends 0057 in part; amends 0049 in part) |
| 0061 | Consumers pin main SHAs under a documented contract until 2.0.0: no pre-release is published, 2.0.0-dev stands on updated grounds, the fragment rule widens to cover breaks between pins, package/0 metadata lands without publishing, and the no-publish rule defers to a named trigger | accepted (contract ended with the 2.0.0 release per its own decision 5; re-decided by 0066) |
| 0062 | The OpenTelemetry bridge is a separate package, opentelemetry_statifier: family-scoped, public-events-only, git-pinned and unpublished until statifier is on Hex; span topology and propagation in docs/opentelemetry.md | accepted |
| 0063 | An opaque caller_context :: term() (default nil, never read by the library) rides %Event{} via external/2, is stamped by the core onto %SendDelayed{}/%Cancel{}, surfaces in four telemetry events' metadata, and recordings carry it (format 2 -> 3); ADR-0054's keys untouched | accepted (amends 0040 in part) |
| 0064 | The position blob drops routes and invoke_types: to_binary/1 omits both alongside :machine, from_binary/2 blanks both on decode regardless of blob vintage, and the format version stays 2 | accepted (amends 0052 in part) |
| 0065 | Statifier.Testing.HandlerCase: a use-injected conformance case any Statifier.Invoke.Handler implementation runs against itself - planning purity, perform/2 idempotency against a declared observation point (fail-not-skip), and the library-half pins via probe handlers | accepted |
| 0066 | Publishes 2.0.0 to Hex, ending the SHA-pinning contract - ADR-0061's satellite trigger fired; known issues recorded; SemVer and the changelog take over | accepted |
New ADRs: next number, same three-section format (Context, Decision, Consequences),
drafted or reviewed at the direction level per docs/workflow.md. Pick the number
against a freshly fetched remote - git fetch origin && git ls-tree origin/main --name-only docs/adr/ - so a branch does not start behind a record that has
already landed; mix quality's ADR guard catches a collision that materializes
later, but only once the colliding file is in your tree.