Architecture
One gate, at the moment before commitment.
Agents run concurrently and share state. The only place their intentions are brought together is a single interception seat at the commit boundary — and that is deliberate, because a joint hazard is not visible anywhere else.
The airlock
Every commit_clearance passes through one Mozaik InterceptionHandler.
It suspends the pending function_call without ending the turn, holds it beside
whatever else is pending, and evaluates the set. Awaiting inside handle() suspends that
agent and nobody else — which is what makes the hold real rather than a metaphor.
If the set is jointly hazardous, one call is resumed with rewritten arguments. Because Mozaik appends the post-interception call to the agent's own context, the agent then reasons about having been narrowed. It is a narrowing, not a veto: the aircraft still gets a clearance it can fly.
Aborting instead would be the database answer, and agent runtimes cannot afford it — an aborted turn costs minutes of inference and dollars of tokens. That economic difference is the reason the repair is a rewrite.
Three preemption mechanisms, never conflated
Each is logged under its own name, because collapsing them is how a demo starts overclaiming.
| mechanism | what actually happens |
|---|---|
| transition.rewritten | a pending call's arguments are replaced; the rewritten call executes |
| transition.substituted | a completed inference whose premise died is replaced before it becomes an action |
| runner.abort | our runner closed the provider stream — we do not claim tokens stop billing |
What the framework does not provide
Six subsystems, each answering a finding we could point at in the shipped bundle. They are the reason the concurrency is real rather than asserted.
- OutboxDispatcher —
publishis synchronous and re-entrant, so two participants can observe the same two events in opposite orders. Deferred dispatch gives every participant one identical sequence. Filed as #115. - TurnScheduler —
ModelContext.addContextItemsmutates in place, so concurrent turns sharing one agent's memory interleave a call with a foreign output and the provider rejects it. One in-flight turn per agent, each with an owned context. - OrphanRepair — every abort synthesises the missing
function_call_output, so being overruled becomes reasoning material rather than a dangling call. - Supervising driver —
runLoopswallows every failure, so a dead agent is indistinguishable from a silent one. A halted participant is announced. Filed as #114. - VirtualClock — nothing outside the clock adapter reads wall-clock time, and a test greps the tree to keep it that way. Without it there is no replay.
- Content-addressed inference cache — a recorded run replays byte-for-byte with zero API calls, which is why every command on this site is free to run.
Determinism is the substrate, not a feature
Headings are integer milli-degrees; time is an integer tick; fuel is integer milligrams. The
repo bans Math.sin, cos, pow and friends outright, with one
exemption — an 18 000-entry heading table with 720 checked-in golden vectors, so a platform whose
trigonometry differs in the last bit fails loudly at build time instead of drifting quietly.
That is what lets the same seed produce byte-identical runs, and what lets RETRACE explore alternative schedules over the surface this architecture actually exposes.