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/// What `ForgetSecret` carries: the vault reference whose key is deleted, spelled
80/// `secret:realm/name`. Refused while an attached endpoint or a configuration still names the
81/// reference, and for a key the environment supplies (gateway D33); writes nothing to the ledger
82/// (`crates/accounting/spec/Worker.lean` §8-37).
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
84#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
85pub struct SecretForgetting {
86    pub reference: String,
87    pub idem: IdemKey,
88}
89
90/// A person's decision on proposal cards of one document, landed as one
91/// save (`crates/wire/spec/Answer/Proposals.lean` §8-73).
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
93#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
94pub struct ProposalDecisions {
95    pub doc: Address,
96    pub decisions: Vec<ProposalDecision>,
97    pub idem: IdemKey,
98}
99
100/// One card and the verdicts on its changed sentences; a sentence left
101/// unnamed is rejected.
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
104pub struct ProposalDecision {
105    pub proposal: B3Hash,
106    pub verdicts: Vec<SliceVerdict>,
107}
108
109/// A building's whole `RULES.toml` from a page, and the text the page
110/// read: the city evaluates `body` before it lands, and only over `base`
111/// (`crates/wire/spec/Command/Step.lean` §8-60).
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
114pub struct RulesWrite {
115    pub building: Address,
116    pub base: String,
117    pub body: String,
118    pub idem: IdemKey,
119}
120
121/// The city's own layer from the settings page: `None` leaves a key as
122/// it is (`crates/wire/spec/Command/Step.lean` §8-61).
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
124#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
125pub struct CitySettings {
126    pub keep_warm: Option<KeepWarm>,
127    pub effort: Option<Effort>,
128    /// The city's whole `[search]` table, written before the other two
129    /// so a value the city refuses lands nothing.
130    pub search: Option<kernel::config::SearchConfiguration>,
131    pub idem: IdemKey,
132}
133
134/// What a new session at an address keeps from the previous one.
135///
136/// An enum rather than a flag: the two states are named actions with
137/// different results on disk, and `carry: true` at a call site says
138/// neither of them. `Nothing` is the first variant and the default,
139/// because that is what a person means by starting a new session — a
140/// new one, here, not a continuation (`crates/sprawling/Spec.lean` §8-82). The
141/// handoff is the exception a person states.
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
143#[serde(rename_all = "snake_case")]
144#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
145pub enum Carry {
146    /// Forget the shape the last session froze, and carry no summary.
147    #[default]
148    Nothing,
149    /// Forget the shape, keep the summary the last session wrote.
150    ///
151    /// The shape still goes, which is the point of the verb: a person
152    /// who carries the summary changed the model, and a room that kept
153    /// its frozen shape could not dispatch at all.
154    Handoff,
155}
156
157/// What a Halt, Release or Autonomy change applies to. Unlike modes and
158/// providers, this set is the protocol's own and has no upstream owner.
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
160#[serde(rename_all = "snake_case")]
161#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
162pub enum HaltScope {
163    City,
164    Building(Address),
165    Workshop(Address),
166}
167
168/// Which of the three documents that govern a city a `PutDocument`
169/// frame carries.
170///
171/// A closed set rather than a path, because where these files live is
172/// the city's answer and not the sender's: all three sit in the city's
173/// own reserved subtree, which no write domain reaches. A frame naming
174/// its own path would be a way to write anywhere inside the one place a
175/// resident may not edit.
176#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
177#[serde(rename_all = "snake_case")]
178#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
179pub enum GovernedDocument {
180    /// Who the Mayor is: `MAYOR.md`.
181    Mayor,
182    /// What the clerk answers by: `CLERK.md`.
183    Clerk,
184    /// How this person wants their city run: `PREFERENCES.md`. It
185    /// belongs to no resident, which is why it sits beside the other two
186    /// rather than at somebody's address.
187    Preferences,
188}
189
190/// One identity card's values (`crates/wire/spec/Answer/Identity.lean` §8-59).
191///
192/// Each key is the card's own: `None` removes it, which puts the default
193/// name back. What a name may be is the city's answer (`city::Naming`),
194/// so a value here is the text the person typed.
195#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
196#[serde(rename_all = "snake_case")]
197#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
198pub enum IdentityCard {
199    /// `PREFERENCES.md`: what the city calls the person, the host the
200    /// name was imported from, and, when `about` is `Some`, the body
201    /// that says what every agent should know about them.
202    Person {
203        user_id: Option<String>,
204        imported_from: Option<String>,
205        about: Option<String>,
206    },
207    /// `MAYOR.md`: what the Mayor is called. The body under the area is
208    /// left as it is.
209    Mayor { name: Option<String> },
210}
211
212/// Which of a building's own spine documents a write carries.
213///
214/// Named rather than addressed, for the reason [`GovernedDocument`]
215/// gives: where these files live is the city's answer and not the
216/// sender's. Unlike the three documents that govern a city, these have
217/// a second writer — a resident reaches `Roadmap.md` through `plan` and
218/// the others through `edit` — so a write to one of them is a write that
219/// can lose a race, and the caller says which text it started from.
220#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
221#[serde(rename_all = "snake_case")]
222#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
223pub enum SpineDocument {
224    /// The plan and the only source of progress in a building.
225    Roadmap,
226    /// The notepad: whatever needs recording and has no other home.
227    Memo,
228    /// What the next session needs and cannot get from the files.
229    Handoff,
230    /// What this project is and the decisions it holds.
231    Spec,
232}
233
234/// What a `Pursue` command does to a pursuit.
235///
236/// `Clear` and `Pause` are different actions and both exist: pausing
237/// keeps the goal so it can be taken up again, and clearing throws it
238/// away. Cancelling a *run* is a third thing again, and it has its own
239/// command.
240#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
241#[serde(rename_all = "snake_case")]
242#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
243pub enum PursuitStep {
244    /// Declare one, replacing any goal this building already had.
245    Set {
246        goal: String,
247    },
248    Pause,
249    Resume,
250    Clear,
251}
252
253/// What `CloseCity` carries: how the runs under way end
254/// (`crates/wire/spec/Command/Kind.lean` §19-2).
255#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
256#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
257pub struct CityClosing {
258    pub mode: CloseMode,
259    pub idem: IdemKey,
260}
261
262/// How a closing city treats the runs it still has.
263#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
264#[serde(rename_all = "snake_case")]
265#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
266pub enum CloseMode {
267    /// Let every run under way finish, then close.
268    Drain,
269    /// Stop every run now, then close.
270    Interrupt,
271}
272
273/// What `AddAgent` carries: the consent to one agent entry the city
274/// offered, named by the digest of its launch spec. The city recomputes
275/// the digest of the spec it would offer now and refuses on a mismatch,
276/// so what is written is what the person saw (`crates/wire/spec/Answer/Agents.lean` §8-90).
277#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
278#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
279pub struct AgentAdding {
280    pub spec_digest: B3Hash,
281    pub source: crate::answer::AgentSource,
282    /// The room whose resident this agent becomes as well, when the person
283    /// chose "add and use here".
284    pub seat_here: Option<Address>,
285    pub idem: IdemKey,
286}
287
288/// What `AgentLogin` carries: which agent, and which of the auth methods
289/// it declared in `initialize`.
290#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
291#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
292pub struct AgentLoginStart {
293    pub agent: String,
294    pub method: String,
295    pub idem: IdemKey,
296}
297
298/// What `ForgetDevice` carries: the paired browser whose key the city
299/// deletes (`crates/wire/spec/Answer/Devices.lean` §8-91).
300#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
301#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
302pub struct DeviceForgetting {
303    pub device: crate::answer::DeviceId,
304    pub idem: IdemKey,
305}