Expand description
The turn typestate: Assembling -> Calling ->
ToolWave -> Recording, phase changes carrying &mut dyn Ledger.
Interrupts are consumed only at phase boundaries — the boundary
snapshot is a parameter of every transition, and no method exists that
could observe one mid-phase. That absence is A9’s structural half.
A wave is many effects rather than one, so every call in it is a
boundary of the same kind: the executor is asked before each, and a
halt ends the wave there instead of after its last call.
Steer consumes at a boundary too, but advances: it is an addition to
the window, not an ending.
Lines that record a moment the turn waited for - model_called,
model_returned, tool_called, tool_result - carry that moment,
read from the clock the driver handed to Turn::begin; every other
line of the turn carries the turn’s stamp. Order is seq’s business.
crates/runtime/spec/Turn.lean proves what the boundaries must hold
(§8-3): a cancel before call k leaves exactly the first k calls
accounted, and a steer never ends a turn.
Structs§
- Assembling
- Call
Shape - Which model this run calls, how much it may say, and how hard it may
think — the frozen
[model]config section as the turn sees it.effortcomes fromkernel::FrozenConfigand cannot change within the run: the provider renders it into the cached prompt prefix. - Calling
- Prompt
Record - The
prompt_assembledpayload a run wrote last; empty before its first turn. It lives across turns, in the run’s own state. - Recording
- RunPrompt
- The prompt one turn is assembled from: the run’s frozen prefix, and what the run has already recorded of it.
- Tool
Wave - Turn
- The typestate carrier. Phase data lives in
Sand is private to this module: a phase literal cannot be forged, a phase cannot be skipped, and no method returns an earlier phase. Everything the turn writes goes throughjournal, which is the module’s only ledger door. - Turn
Cancelled - The turn ended at a boundary:
cancel_receivedis on the ledger and its ref is the last entry. Freezing (handoff + run_frozen) is the run loop’s move, not the turn’s. - Turn
Report - What a completed turn hands the run loop.
assistantandwave_resultsare the window-folding material — the turn’s exchange, compacted at the closing boundary ofrecord. The records are what the compaction works from:model_returned.data.contentkeeps the reply whole, and eachtool_resultis the payload the window text was printed from.runtime::forkrebuilds both from those records through the same compaction at the same boundary, so a rebuild and a live fold still share one source.
Enums§
- Admitted
- What admitting one call decided.
- Generating
- Who acts on a model’s answer while it is still being generated. The one place that decides which door of the model port a turn takes.
- Interrupt
- Boundary snapshot, supplied by the executor at every phase change.
Cancelends the turn at the boundary;Steerrecords and advances (the executor folds the text into itsConversation). - Next
Call - Whether the wave may start its next call, asked once before each of them.
- Phase
Outcome - A phase change either advances or ends the turn at the boundary. Exhaustive, as every enum in this workspace is: a new outcome must force every executor to decide, not fall through a catch-all.
Traits§
- Concurrent
Invoke - A wave’s tools in three stages, so the calls that only read can run at once while everything they decide stays in call order.