ADR-131
The resident's job door is public: admission by served name, digests as optional integrity assertions, the engine as the one producer
accepted · 2026-09-04 · L2 L4 · cites 4
0ADR-131: The resident's job door is public #
Context #
POST /v1/jobs took one body: an execution snapshot with a digest the
caller had to produce, whose domain was documented nowhere. The wave-7
gauntlet's operator persona spent nineteen attempts and twelve digest
constructions on it and was refused every time as snapshot_tampered —
a word that accuses. GET /v1/workflows listed a registry the resident
would never run from; nika explain snapshot_tampered knew no such
code (#1441). The SDK never hashed anything: it asked the local engine
(nika check <file> --json --sdk-snapshot) — the producer existed and
nothing said so.
The one-door law: external consumers must not reverse-engineer the snapshot's canonicalization or hashing; one Nika owner captures the execution world; the public SDK submits a real job without private filesystem, Rust or hidden-endpoint knowledge.
Decision #
- Two forms, one admission.
POST /v1/jobs(andPOST /v1/check) accept{"workflow": "<name>"}for a workflow the served registry lists: the resident captures its world throughExecutionService:: admit, exactly as a schedule fires — the one owner of the snapshot and of its digest domain. The snapshot form stays for a remote world; it is the bodynika check <file> --json --sdk-snapshotprints. - Digests are integrity assertions, optional. On the wire,
digestand the unit digests may be absent: the engine computes them (decodeverifies a present one, computes an absent one; the stored world is the engine's canonical encoding, digests present from admission on). A present digest that mismatches is refused assnapshot_tamperedwith the honest words: a caller-supplied integrity digest that failed, the producer named (never a signature: the bearer authenticates the caller, the digest asserts the content). - The producer is named everywhere. The OpenAPI (
JobByName·ExecutionSnapshot· the unitkindlegend · the jobs and check summaries), the listen banner,serve --workflows's help. - The resident's codes are taught.
nika explain <resident code>answers fromnika_error::codes::resident_help— the same table the MCPnika_explaintool reads (one voice).
Consequences #
- Positive: a human with the binary and
curlsubmits a served workflow by name; a remote client posts bytes and never hashes; the registry the resident lists is the registry it runs; a refusal teaches. - Negative:
POST /v1/jobsbodies without a snapshot are no longer amalformed_snapshotby construction (the by-name probe runs first); the OpenAPI'srequiredsets shrink (additive for every existing client). - Follow-ups: the SDK's by-name path (F9); the docs page.
Alternatives considered #
- Documenting the digest domain for clients to reimplement: rejected — the law forbids it, and a second implementation drifts.
- A
nika snapshot <file>verb: rejected — the producer exists as a hiddencheckadapter; a verb for it would grow the surface the consumer program is about to prune.
Amendment · 2026-09-04 (the freeze audit) #
« Attestation » was a word above the proof: nothing signs the digest a
caller sends; it is a SHA-256 the engine verifies against the bytes it
received — a content assertion. The OpenAPI, the refusal text, nika explain and this ADR now say « caller-supplied integrity digest ». The
wire code snapshot_tampered stays (a stable word since 0.116); its
words changed.
read at v0.118.7 · the decision record ships with the engine