ADR-130
One vocabulary, one owner: the task-record twin dies, the resident's status projects the settlement, copied spellings are pinned
accepted · 2026-09-04 · L2 L3 L4 · cites 5
0ADR-130: One vocabulary, one owner #
Context #
Three copies of one vocabulary survived ADR-128. nika-runtime-laws::compat_record
twinned nika-dataflow's TaskStatus · TerminalCause · TaskErrorRecord ·
TaskRecord with From conversions "to preserve the historical source API"
— two enums with the same variants, a struct copied field by field, and a
conversion at every RunOutcome. The resident's JobStatus mapped the
execution disposition to its own words by hand. nika-tui-core folds the
journal with string literals for the frame kinds and depends on nothing
that owns them — a rename on either side would fail nowhere.
Decision #
- The twin dies.
compat_recordis deleted;nika_runtime::{TaskStatus, TerminalCause, TaskErrorRecord, TaskRecord, legal}are re-exports ofnika-dataflow, the owner.RunOutcome::recordsholds the owner's records; the conversion is gone. - One mapping.
JobStatus: From<RunState>is the resident's only projection of a run state;ExecutionDisposition: Into<RunState>names the four states it can carry;JobStatus::run_statesays which statuses are run states at all (queued·running·interruptedare the job's own — ownership and evidence, never a run state). The words are equal by construction and proven by a test. - Copied spellings are pinned. A crate that must not depend on the
owner (the wasm-light
nika-tui-core) may copy a spelling only under a test that compares the copy to the owner (tests/wire_pins.rs· a dev-dependency edge). The rule generalises to every repository: a contract is AUTHORITATIVE, GENERATED, or PINNED by a gate — never a hand-written duplicate nothing checks.
Consequences #
- Positive: one task vocabulary, one status projection, one pin per copy;
nika-runtime-lawssheds a third of its lines. - Negative:
nika_runtime::TaskStatusandTerminalCauseare now#[non_exhaustive](the owner's contract): an exhaustive match outside the crate needs a wildcard arm. - Follow-ups: the SDK's types (generated · ADR follows F9); the teardown's outcome word.
Alternatives considered #
- Keeping the twin for source compatibility: rejected — no external
consumer exists (the runtime crates are
publish = false), and a twin nothing needs is the drift the program exists to remove. - A
nika-wirecrate: rejected as in ADR-128.
read at v0.118.7 · the decision record ships with the engine