RFD 0014 — Runtime Serving Surface
State: discussion
Question
Should Argon expose a first-party serving surface for executing a loaded
.oxbin against tenant/fork scoped runtime state?
Context
The §19 runtime contract defines the in-process Engine / Module / Store
semantics, but Ode and Tide workflows need an executable boundary: load the
workspace .oxbin, keep Store state warm, dispatch generated SDK descriptors,
and expose forks, snapshots, derive output, and debug traces.
The old kernel and devbox-kernel path mixed this runtime work with live source
loading, generated SDK transport concerns, tenant hardcoding, workflow state,
and Tide-specific globals. New Argon has a compiled .oxbin, so the runtime
serving layer can be Argon-native and narrower.
Decision
Add ox runtime serve backed by an oxc-serve crate. The command serves a
versioned /v1 API around a loaded .oxbin:
GET /v1/healthGET /v1/moduleGET /v1/schemaPOST /v1/dispatch/queryPOST /v1/dispatch/mutationPOST /v1/dispatch/compute- fork-scoped dispatch aliases under
/v1/forks/{fork}/dispatch/* GET /v1/forks,POST /v1/forks,GET /v1/forks/{fork}DELETE /v1/forks/{fork},POST /v1/forks/{fork}/promoteGET /v1/forks/{fork}/diff/{other}POST /v1/forks/{fork}/derivePOST /v1/forks/{fork}/derive/traceGET /v1/snapshotGET /v1/derived/individuals/{id}GET /v1/derived/individuals/{id}/explainGET /v1/derived/facts/{fact_id}/explain
The serving layer supports mem and pg storage. Both backends preserve the
append-only ABox event-log model; derived state and snapshots are projections
over .oxbin plus visible events. Postgres additionally owns durable fork
records, generation counters, scoped/as-of scans, and projection-cache
invalidation.
The generated SDK remains dependency-free and transport-agnostic. It emits types, validators, metadata, descriptors, and wire parse/serialize helpers. It does not import or generate a runtime client.
Rationale
This keeps the core runtime responsibilities inside Argon, where the .oxbin,
storage, rule evaluation, and fork semantics live. It also keeps environment
concerns outside Argon:
- tenant/principal selection belongs to the caller or proxy,
- Tide workflow state and run journals belong to Tide,
- Ode UI state and visualization layout belong to Ode,
- SDK transport adapters belong to the host application.
The /v1 API is descriptor-based so generated SDKs can call it through a small
host transport without coupling generated code to HTTP, Tide, fetch, or a
specific deployment.
Alternatives
One alternative was a separate ontology-tooling service that wrapped Argon. That would have duplicated runtime semantics and left forks, storage, and derive behavior outside the implementation that owns them.
Another alternative was generating a full SDK runtime client. That is more ergonomic for simple workflows, but it couples generated output to transport and deployment concerns. The chosen design leaves that as a hand-written host adapter.
Consequences
ox runtime serve is a long-running process and therefore introduces async
HTTP dependencies in the compiler workspace. The serving layer must keep a
strict boundary: no generic entity writes, no ad-hoc raw query/mutation
execution, no Tide or Ode state, no tenant hardcoding, and no SDK transport
generation.
Hot reload is allowed only after compatibility checks. Additive schema changes may load; declaration removal or field/relation type changes are rejected when live ABox data exists.
unsafe_logic and forget remain capability-gated. Where the underlying
language/runtime substrate is not enabled, the serving API refuses the request
instead of pretending the capability exists.
Open Questions
- Whether the full PosBool DNF provenance witness tree should be exposed by the current explain endpoints or by a later provenance-specific API.
- Whether projection caches should become durable response caches for selected read endpoints or stay as backend-maintained invalidation state until DBSP arrangements land.
- The final production IAM mapping for
fork,forget, and futureunsafe_logicexecution budgets.