kernel/event/kind.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//! Event kinds: the closed set and its window classes.
7
8use serde::{Deserialize, Serialize};
9
10mod window;
11pub use window::WindowClass;
12
13/// The closed event vocabulary.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
15#[serde(rename_all = "snake_case")]
16#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
17pub enum EventKind {
18 // Genesis and space (4).
19 CityInitialized,
20 BuildingCreated,
21 /// A person changed what one building's runs may reach.
22 ///
23 /// The payload says which faces were written, never what they now
24 /// hold: `CONFIG.toml` is the authority for what a run is governed
25 /// by, and a copy of it here would be a second one. What this adds
26 /// is the fact the file cannot carry - that the change happened,
27 /// when, and to which building.
28 BuildingConfigured,
29 /// A person took a building out of the city.
30 ///
31 /// The payload names the building and where its files are kept
32 /// under the reserved subtree; nothing is deleted, and every record
33 /// the building wrote stays in this history.
34 BuildingRemoved,
35 // Base set (19).
36 /// A session started at an address: the shape the last one froze
37 /// was forgotten, and the summary it left was carried or not.
38 ///
39 /// A separate kind from `run_started` because it is a separate
40 /// fact: the first run of a session and the fifth are both
41 /// `run_started`, and only this line says where one session ended
42 /// and the next began. `carried` is recorded even when it is
43 /// false, because "this session carries nothing" is the answer to
44 /// the question a person asks when the model behaves as if it had
45 /// never met them.
46 SessionOpened,
47 RunStarted,
48 RunForked,
49 PromptAssembled,
50 /// One request's cache shape, and which of its regions moved since
51 /// the request before it. The line that turns a cache miss into a
52 /// named cause: system, tools or the conversation. It measures the
53 /// request rather than deciding any of its bytes, which is why it is
54 /// record-only.
55 PromptShapeCompared,
56 ModelCalled,
57 ModelReturned,
58 ToolCalled,
59 ToolResult,
60 ResultOffloaded,
61 GateChecked,
62 GateDenied,
63 CheckpointCommitted,
64 HandoffWritten,
65 SteerReceived,
66 CancelReceived,
67 WatchdogFired,
68 BudgetLimit,
69 RunFrozen,
70 LogTruncated,
71 // Collaboration (19).
72 SignalEnqueued,
73 SignalConsumed,
74 DraftHeld,
75 DraftResolved,
76 GoalRegistered,
77 GoalConflict,
78 ArbitrationVerdict,
79 RepairStarted,
80 RepairReused,
81 WorktreeOpened,
82 PrOpened,
83 PrMerged,
84 PrRejected,
85 RoadmapClaimed,
86 RoadmapFinished,
87 RoadmapReleased,
88 /// A branch was divided into children. The plan grew rather than
89 /// moved, which is a different fact from any row changing state and
90 /// is the only one that changes what the denominator is made of.
91 RoadmapSplit,
92 /// A node cannot proceed, and why. Distinct from `roadmap_released`:
93 /// a released node is back in the ready set, a blocked one is red
94 /// and everything behind it is waiting.
95 RoadmapBlocked,
96 /// A city was given a goal to keep working towards, or that goal
97 /// was paused, resumed or cleared. Recorded because it is the one
98 /// thing in the city that starts work without a person asking, and
99 /// "who set this running" has to be answerable afterwards.
100 PursuitChanged,
101 // Governance and facilities (18).
102 ApprovalRequested,
103 ApprovalResolved,
104 PolicyCreated,
105 PolicyRevoked,
106 TaintPromoted,
107 CrossBuildingTransfer,
108 CityHalted,
109 BackpressureShed,
110 DigestInvalidated,
111 EndpointAttached,
112 /// What a base URL says it serves, asked before anything is
113 /// attached. A separate fact from `EndpointAttached`: a person may
114 /// look at what a key buys and register none of it.
115 EndpointProbed,
116 EndpointLost,
117 ModelSelected,
118 ProviderDegraded,
119 /// A subscription login an older build began. This build signs in
120 /// to no subscription and writes none; the kind stays so a ledger
121 /// that holds one still reads, and nothing reads its payload
122 /// (`crates/gateway/Spec.lean` §8-5).
123 LoginStarted,
124 EvalRun,
125 AssetArchived,
126 CredentialLent,
127 // Privacy and Discard (5).
128 SecretCaptured,
129 SecretEgressBlocked,
130 FileDiscarded,
131 DiscardRestored,
132 AutonomyChanged,
133 // Unified history (2).
134 WentBack,
135 FileRestored,
136 /// One of the three documents that govern a city was written by a
137 /// person. Recorded because what governs a city decides what every
138 /// later run is given, and "who changed this, and when" has to be
139 /// answerable from the one history rather than from a file's
140 /// modification time.
141 GovernedDocumentWritten,
142 /// A person wrote one of a building's own spine documents.
143 SpineDocumentWritten,
144 /// One of the documents a dispatch stands under — the city's
145 /// `CONFIG.toml`, or a building's `CONFIG.toml` or `RULES.toml` —
146 /// holds other bytes than the last line booked. Booked after the city
147 /// agreed to the work and before the run reads a rule, so a replay
148 /// names the entry the change reached the city in.
149 RulesChanged,
150 /// A person asked to connect an outside application, and the broker
151 /// that holds its OAuth opened a consent session.
152 ///
153 /// The request is history and belongs here; **where that application
154 /// stands right now is not, and is deliberately absent from the
155 /// payload** (`crates/wire/Spec.lean` §8-35b): a recorded standing
156 /// would still read "connected" an hour after the person revoked
157 /// it. The consent page's own url is absent for a second reason -
158 /// it is a capability, and anybody replaying this log would be
159 /// holding one.
160 ToolkitLinkOpened,
161
162 // The two faces of an endpoint that are not the conversation (2).
163 /// One call to an attached endpoint's embeddings face, and what came
164 /// back for it. The vectors are absent for the reason `ModelCalled`
165 /// carries no request body: a replay recomputes them from the inputs
166 /// the call recorded.
167 EmbeddingCalled,
168 /// One call to an attached endpoint's rerank face, and how many
169 /// passages and ranks it was about.
170 RerankCalled,
171
172 // The adviser port, consulted about the window (3).
173 /// A judgment was asked of the adviser port about the window.
174 ///
175 /// Asking decides nothing on its own: whether the bytes the model
176 /// reads include the item in question is decided by the answer, or
177 /// by the fallback when none came.
178 AdviserAsked,
179 /// The adviser answered. This is the line a replay reads instead of
180 /// asking again, which is why the answer decides model-request bytes
181 /// and the question that produced it does not.
182 AdviserAnswered,
183 /// No adviser answer was used, and why. The deterministic strategy
184 /// answered instead, and this is the only line that says so: without
185 /// it a window an adviser shaped and a window the city's own policy
186 /// shaped would fold to the same history.
187 AdviserFellBack,
188
189 // Keep-warm (1).
190 /// One keep-warm renewal a worker sent for a room's cached prefix:
191 /// what the provider reported it cost, or its refusal. The request is
192 /// absent because it resends a prefix the run already recorded.
193 CacheRenewed,
194
195 // Harness residents (2).
196 /// One thing an official harness reported during a run: a piece of
197 /// its answer or reasoning, a tool call it started and its status,
198 /// or a permission it asked for and the city's answer. Written after
199 /// the harness said it, and never read back as a decision of the city.
200 HarnessReported,
201 /// The harness's answer to the city's prompt: the stop reason and the
202 /// text it answered with this turn, written as the stop reason arrives
203 /// and before the run freezes.
204 HarnessAnswered,
205
206 // The remote door (5).
207 /// The person opened the remote door: until when, and the address a
208 /// device reaches it at.
209 RemoteOpened,
210 /// The remote door closed, and who closed it: the person at the
211 /// console, a device that locked it behind itself, or its own time.
212 RemoteClosed,
213 /// A device presented a good pairing code and the city keeps it.
214 DevicePaired,
215 /// The person took a device's pairing away.
216 DeviceRevoked,
217 /// A paired device proved its key and holds a remote session.
218 RemoteSessionStarted,
219
220 // Documents (4).
221 /// A save through the page landed: which document, from which
222 /// version to which, and how long it now is; never the text.
223 DocumentWritten,
224 /// A run suggested replacing one stretch of one document version.
225 ProposalOffered,
226 /// A person decided a proposal card, sentence by sentence.
227 ProposalDecided,
228 /// The run that offered a card took it back while it was open.
229 ProposalWithdrawn,
230}
231
232impl EventKind {
233 /// Every kind, in the order the SPEC table lists them. Data face for counting tests
234 /// and `xtask specalign`.
235 pub const ALL: [EventKind; 89] = [
236 EventKind::CityInitialized,
237 EventKind::BuildingCreated,
238 EventKind::BuildingConfigured,
239 EventKind::BuildingRemoved,
240 EventKind::SessionOpened,
241 EventKind::RunStarted,
242 EventKind::RunForked,
243 EventKind::PromptAssembled,
244 EventKind::PromptShapeCompared,
245 EventKind::ModelCalled,
246 EventKind::ModelReturned,
247 EventKind::ToolCalled,
248 EventKind::ToolResult,
249 EventKind::ResultOffloaded,
250 EventKind::GateChecked,
251 EventKind::GateDenied,
252 EventKind::CheckpointCommitted,
253 EventKind::HandoffWritten,
254 EventKind::SteerReceived,
255 EventKind::CancelReceived,
256 EventKind::WatchdogFired,
257 EventKind::BudgetLimit,
258 EventKind::RunFrozen,
259 EventKind::LogTruncated,
260 EventKind::SignalEnqueued,
261 EventKind::SignalConsumed,
262 EventKind::DraftHeld,
263 EventKind::DraftResolved,
264 EventKind::GoalRegistered,
265 EventKind::GoalConflict,
266 EventKind::ArbitrationVerdict,
267 EventKind::RepairStarted,
268 EventKind::RepairReused,
269 EventKind::WorktreeOpened,
270 EventKind::PrOpened,
271 EventKind::PrMerged,
272 EventKind::PrRejected,
273 EventKind::RoadmapClaimed,
274 EventKind::RoadmapFinished,
275 EventKind::RoadmapReleased,
276 EventKind::RoadmapSplit,
277 EventKind::RoadmapBlocked,
278 EventKind::PursuitChanged,
279 EventKind::ApprovalRequested,
280 EventKind::ApprovalResolved,
281 EventKind::PolicyCreated,
282 EventKind::PolicyRevoked,
283 EventKind::TaintPromoted,
284 EventKind::CrossBuildingTransfer,
285 EventKind::CityHalted,
286 EventKind::BackpressureShed,
287 EventKind::DigestInvalidated,
288 EventKind::EndpointAttached,
289 EventKind::EndpointProbed,
290 EventKind::EndpointLost,
291 EventKind::ModelSelected,
292 EventKind::ProviderDegraded,
293 EventKind::LoginStarted,
294 EventKind::EvalRun,
295 EventKind::AssetArchived,
296 EventKind::CredentialLent,
297 EventKind::SecretCaptured,
298 EventKind::SecretEgressBlocked,
299 EventKind::FileDiscarded,
300 EventKind::DiscardRestored,
301 EventKind::AutonomyChanged,
302 EventKind::WentBack,
303 EventKind::FileRestored,
304 EventKind::GovernedDocumentWritten,
305 EventKind::SpineDocumentWritten,
306 EventKind::RulesChanged,
307 EventKind::ToolkitLinkOpened,
308 EventKind::EmbeddingCalled,
309 EventKind::RerankCalled,
310 EventKind::AdviserAsked,
311 EventKind::AdviserAnswered,
312 EventKind::AdviserFellBack,
313 EventKind::CacheRenewed,
314 EventKind::HarnessReported,
315 EventKind::HarnessAnswered,
316 EventKind::RemoteOpened,
317 EventKind::RemoteClosed,
318 EventKind::DevicePaired,
319 EventKind::DeviceRevoked,
320 EventKind::RemoteSessionStarted,
321 EventKind::DocumentWritten,
322 EventKind::ProposalOffered,
323 EventKind::ProposalDecided,
324 EventKind::ProposalWithdrawn,
325 ];
326}
327
328#[cfg(test)]
329#[allow(
330 clippy::unwrap_used,
331 clippy::expect_used,
332 clippy::panic,
333 clippy::indexing_slicing,
334 reason = "test code"
335)]
336mod tests;