Skip to main content

wire/command/
step.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//! The values a Command carries beside its scalars, and the closed sets: which scope a halt applies to, which governed document is being written,
7//! what is being done to a pursuit, and what a new session keeps from
8//! the one before it.
9//!
10//! Each of them is the protocol's own vocabulary with no upstream
11//! owner, which is what separates them from the carried names in
12//! `wire::carried_name`: those defer to whoever owns the value set,
13//! and these have no one to defer to.
14
15use kernel::event::record::SliceVerdict;
16use kernel::{Address, B3Hash, Effort, IdemKey, KeepWarm};
17use serde::{Deserialize, Serialize};
18
19/// A page's save of one document: edits made on the version `baseline`,
20/// refused once that version has moved (`crates/wire/spec/Command/Step.lean` §8-72).
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
22#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
23pub struct RangeWrite {
24    pub doc: Address,
25    pub baseline: B3Hash,
26    pub edits: Vec<documents::TextEdit>,
27    pub idem: IdemKey,
28}
29
30/// A display name for the session of `room` that began at `began`; an
31/// empty name takes it back (`crates/wire/spec/Answer/Sessions.lean` D27).
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
34pub struct SessionNaming {
35    pub room: Address,
36    pub began: kernel::Seq,
37    pub name: String,
38    pub idem: IdemKey,
39}
40
41/// A room's new run policy, which the run under way takes at its next
42/// safe point (`crates/wire/spec/Answer/Sessions.lean` D27).
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
45pub struct PolicyChange {
46    pub room: Address,
47    pub policy: kernel::model::RunPolicy,
48    pub idem: IdemKey,
49}
50
51/// What `OpenRemoteDoor` asks for: the remote door open for `lasting_ms`, one minute to seven
52/// days. The request does nothing by itself; the city prints a code at its own console and
53/// refuses the frame with `E_APPROVAL_PENDING` (`crates/wire/spec/Command/Kind.lean`,
54/// remote_access D4).
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
57pub struct DoorOpening {
58    pub lasting_ms: u64,
59    pub idem: IdemKey,
60}
61
62/// What `ConfirmRemoteDoor` carries: the code the city's console printed, read however it was
63/// retyped. Every answer, right or wrong, ends the request it answers.
64#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
66pub struct DoorAnswer {
67    pub code: String,
68    pub idem: IdemKey,
69}
70
71/// A door verb with nothing to say but its key: `ReplaceCityKey`, guarded the way opening is,
72/// and `CloseRemoteDoor`, unguarded because closing only takes access away (remote_access D5).
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
75pub struct DoorStep {
76    pub idem: IdemKey,
77}
78
79/// A person's decision on proposal cards of one document, landed as one
80/// save (`crates/wire/spec/Answer/Proposals.lean` §8-73).
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
83pub struct ProposalDecisions {
84    pub doc: Address,
85    pub decisions: Vec<ProposalDecision>,
86    pub idem: IdemKey,
87}
88
89/// One card and the verdicts on its changed sentences; a sentence left
90/// unnamed is rejected.
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
93pub struct ProposalDecision {
94    pub proposal: B3Hash,
95    pub verdicts: Vec<SliceVerdict>,
96}
97
98/// A building's whole `RULES.toml` from a page, and the text the page
99/// read: the city evaluates `body` before it lands, and only over `base`
100/// (`crates/wire/spec/Command/Step.lean` §8-60).
101#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
102#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
103pub struct RulesWrite {
104    pub building: Address,
105    pub base: String,
106    pub body: String,
107    pub idem: IdemKey,
108}
109
110/// The city's own layer from the settings page: `None` leaves a key as
111/// it is (`crates/wire/spec/Command/Step.lean` §8-61).
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
114pub struct CitySettings {
115    pub keep_warm: Option<KeepWarm>,
116    pub effort: Option<Effort>,
117    pub idem: IdemKey,
118}
119
120/// What a new session at an address keeps from the previous one.
121///
122/// An enum rather than a flag: the two states are named actions with
123/// different results on disk, and `carry: true` at a call site says
124/// neither of them. `Nothing` is the first variant and the default,
125/// because that is what a person means by starting a new session — a
126/// new one, here, not a continuation (`crates/sprawling/Spec.lean` §8-82). The
127/// handoff is the exception a person states.
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
129#[serde(rename_all = "snake_case")]
130#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
131pub enum Carry {
132    /// Forget the shape the last session froze, and carry no summary.
133    #[default]
134    Nothing,
135    /// Forget the shape, keep the summary the last session wrote.
136    ///
137    /// The shape still goes, which is the point of the verb: a person
138    /// who carries the summary changed the model, and a room that kept
139    /// its frozen shape could not dispatch at all.
140    Handoff,
141}
142
143/// What a Halt, Release or Autonomy change applies to. Unlike modes and
144/// providers, this set is the protocol's own and has no upstream owner.
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146#[serde(rename_all = "snake_case")]
147#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
148pub enum HaltScope {
149    City,
150    Building(Address),
151    Workshop(Address),
152}
153
154/// Which of the three documents that govern a city a `PutDocument`
155/// frame carries.
156///
157/// A closed set rather than a path, because where these files live is
158/// the city's answer and not the sender's: all three sit in the city's
159/// own reserved subtree, which no write domain reaches. A frame naming
160/// its own path would be a way to write anywhere inside the one place a
161/// resident may not edit.
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(rename_all = "snake_case")]
164#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
165pub enum GovernedDocument {
166    /// Who the Mayor is: `MAYOR.md`.
167    Mayor,
168    /// What the clerk answers by: `CLERK.md`.
169    Clerk,
170    /// How this person wants their city run: `PREFERENCES.md`. It
171    /// belongs to no resident, which is why it sits beside the other two
172    /// rather than at somebody's address.
173    Preferences,
174}
175
176/// One identity card's values (`crates/wire/spec/Answer/Identity.lean` §8-59).
177///
178/// Each key is the card's own: `None` removes it, which puts the default
179/// name back. What a name may be is the city's answer (`city::Naming`),
180/// so a value here is the text the person typed.
181#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
182#[serde(rename_all = "snake_case")]
183#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
184pub enum IdentityCard {
185    /// `PREFERENCES.md`: what the city calls the person, the host the
186    /// name was imported from, and, when `about` is `Some`, the body
187    /// that says what every agent should know about them.
188    Person {
189        user_id: Option<String>,
190        imported_from: Option<String>,
191        about: Option<String>,
192    },
193    /// `MAYOR.md`: what the Mayor is called. The body under the area is
194    /// left as it is.
195    Mayor { name: Option<String> },
196}
197
198/// Which of a building's own spine documents a write carries.
199///
200/// Named rather than addressed, for the reason [`GovernedDocument`]
201/// gives: where these files live is the city's answer and not the
202/// sender's. Unlike the three documents that govern a city, these have
203/// a second writer — a resident reaches `Roadmap.md` through `plan` and
204/// the others through `edit` — so a write to one of them is a write that
205/// can lose a race, and the caller says which text it started from.
206#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
207#[serde(rename_all = "snake_case")]
208#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
209pub enum SpineDocument {
210    /// The plan and the only source of progress in a building.
211    Roadmap,
212    /// The notepad: whatever needs recording and has no other home.
213    Memo,
214    /// What the next session needs and cannot get from the files.
215    Handoff,
216    /// What this project is and the decisions it holds.
217    Spec,
218}
219
220/// What a `Pursue` command does to a pursuit.
221///
222/// `Clear` and `Pause` are different actions and both exist: pausing
223/// keeps the goal so it can be taken up again, and clearing throws it
224/// away. Cancelling a *run* is a third thing again, and it has its own
225/// command.
226#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
227#[serde(rename_all = "snake_case")]
228#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
229pub enum PursuitStep {
230    /// Declare one, replacing any goal this building already had.
231    Set {
232        goal: String,
233    },
234    Pause,
235    Resume,
236    Clear,
237}