Sans-I/O interpreter
Deterministic interpreter
The interpreter is a pure function over state. It takes verified facts, current replicated state, local node context, and completed call results from the secret kernel. It returns updated state, outgoing peer messages, local service requests, and a status.
admitted peer factreplicated state + local node contextCallResult from the kernelstep(ingress, context, call_results)pure · deterministic · Sans-I/O · does no I/O of its ownDonePendingRemoteAbortFailedpublish-readyto peer nodesinput to the next stepCallRequest to local servicesCallRequest →secret-dependent steps run behind the kernel — the interpreter only sees handles and results← CallResultInputs and outputs
Facts only enter the interpreter after they've been validated: transport checked, peer signatures verified, sender binding confirmed, replay safety established, session admitted. Local CallResult values from the secret kernel follow the same path — bound to call ids and merged with replicated state. The step function returns one of five statuses: Done, PendingRemote, Abort, Failed, or a publication-ready terminal state.
Replayable execution
Determinism is scoped to execution over admitted inputs. Approvals, policy decisions, and publication holds are admission-time events: each produces a recorded decision artifact, and execution is a deterministic function of those recorded facts. Variability lives at admission; replay operates over the decisions as recorded.
Because the interpreter is deterministic and depends only on facts and call results, a DVM transition replays from durable state. The enabler is content-addressing: every value in DVM state is indexed by a content-addressed id (Cid), so the replay inputs are fully determined by those ids, independent of mutable in-memory state. That keeps regression tests, inspection, recovery, and evidence export tractable.
The same semantic score also runs against different backend profiles. Swapping backends changes L0 microcode details but leaves the L1 operation contract and public evidence shape stable, which is why the API surface and audit records don't change across backend upgrades.
Layer contract
The three-layer separation is what gives the interpreter its determinism guarantee. It evaluates L1 operations against facts and call results, leaving L0 wire details and L2 product decisions outside its view. Share multiplication stays one L1 instruction whether the backend runs MRR21 setup, OT extension, DKLS23 gadget work, or a witness closure. Promoting L0 substeps to L1 opcodes would tie the score to one backend and break the replay guarantee, so the layer boundary holds them apart.
Two input kinds, no I/O of its own
The step function distinguishes two kinds of input. External API commands — a user's signing request — reach the interpreter only through the client API and the admission contour. Intra-cluster messages — the round traffic of the signing protocols — arrive over the transport bridge as already-admitted ingress representations. Only that second kind is handed to step() as a fact.
The interpreter performs no I/O itself. Outgoing messages are returned to the host, which drives the transport layer; every secret-dependent operation is expressed as a CallRequest to the local node and resolved later as a CallResult. Holding I/O and secret access outside the function keeps the transition pure, content-addressed, and replayable.