runtime/turn/boundary.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! What the executor supplies at a phase change, and what a phase
7//! change answers back.
8
9use kernel::EventRef;
10
11use crate::conversation::Speaker;
12
13/// Boundary snapshot, supplied by the executor at every phase change.
14/// `Cancel` ends the turn at the boundary; `Steer` records and advances
15/// (the executor folds the text into its `Conversation`); `Policy`
16/// advances too, and the executor holds it in its `PolicyCell` until the
17/// next `SafePoint::BeforeWave` (`crates/runtime/spec/PolicyTake.lean`
18/// ยง8-62). `Policy` writes nothing: its `run_policy_changed` line is
19/// already on the ledger, which is how it reached this run.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum Interrupt {
22 None,
23 Cancel,
24 /// Who spoke is a type, so only the entrance that builds
25 /// [`Speaker::Person`] can make a steer render as the User's.
26 Steer {
27 speaker: Speaker,
28 text: String,
29 },
30 Policy {
31 policy: kernel::RunPolicy,
32 },
33}
34
35/// Whether the wave may start its next call, asked once before each of
36/// them.
37///
38/// Narrower than [`Interrupt`] on purpose. Between two calls of one
39/// wave, the only instruction this city can carry out at once is
40/// stopping: text that arrives to redirect the work belongs to the
41/// window the executor owns, and the executor folds it there before
42/// answering here.
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum NextCall {
45 /// Nothing has stopped this run; the call goes ahead.
46 Allowed,
47 /// A halt reached this run, and the wave ends where it stands.
48 Halted,
49}
50
51/// A phase change either advances or ends the turn at the boundary.
52/// Exhaustive, as every enum in this workspace is: a new outcome
53/// must force every executor to decide, not fall through a catch-all.
54#[derive(Debug)]
55pub enum PhaseOutcome<Next> {
56 Advanced(Next),
57 Cancelled(TurnCancelled),
58}
59
60/// The turn ended at a boundary: `cancel_received` is on the ledger and
61/// its ref is the last entry. Freezing (handoff + run_frozen) is the run
62/// loop's move, not the turn's.
63#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct TurnCancelled {
65 pub(super) refs: Vec<EventRef>,
66}
67
68impl TurnCancelled {
69 pub fn refs(&self) -> &[EventRef] {
70 &self.refs
71 }
72}