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}