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 // Sessions and the shelf (3).
232 /// The room's run policy, changed while a session is open
233 /// (`crates/kernel/spec/Event/Record.lean` D21).
234 RunPolicyChanged,
235 /// The name a person gave one session (D22).
236 SessionNamed,
237 /// One audit of one version of a skill on the shelf (D23).
238 SkillAudited,
239
240 // The reply wait (2).
241 /// A run that sent with `wait` stopped at its safe point for a reply
242 /// (`crates/kernel/spec/Event/Record.lean` D32).
243 SignalWaitStarted,
244 /// The one line that ends a `signal_wait_started`: the reply came,
245 /// the deadline passed, or the run left its room (D32).
246 SignalWaitEnded,
247
248 // Where a letter landed (1).
249 /// Where the accounting thread put one `signal_enqueued`: a running
250 /// run's slot, the queue, or a knock (`crates/kernel/spec/Event/Record.lean` D38).
251 SignalLanded,
252
253 // The shelf (1).
254 /// One version of a skill landed on a shelf through the city's door,
255 /// and where it came from (`crates/kernel/spec/Event/Record.lean` D23).
256 SkillShelved,
257}
258
259impl EventKind {
260 /// Every kind, in the order the SPEC table lists them. Data face for counting tests
261 /// and `xtask specalign`.
262 pub const ALL: [EventKind; 96] = [
263 EventKind::CityInitialized,
264 EventKind::BuildingCreated,
265 EventKind::BuildingConfigured,
266 EventKind::BuildingRemoved,
267 EventKind::SessionOpened,
268 EventKind::RunStarted,
269 EventKind::RunForked,
270 EventKind::PromptAssembled,
271 EventKind::PromptShapeCompared,
272 EventKind::ModelCalled,
273 EventKind::ModelReturned,
274 EventKind::ToolCalled,
275 EventKind::ToolResult,
276 EventKind::ResultOffloaded,
277 EventKind::GateChecked,
278 EventKind::GateDenied,
279 EventKind::CheckpointCommitted,
280 EventKind::HandoffWritten,
281 EventKind::SteerReceived,
282 EventKind::CancelReceived,
283 EventKind::WatchdogFired,
284 EventKind::BudgetLimit,
285 EventKind::RunFrozen,
286 EventKind::LogTruncated,
287 EventKind::SignalEnqueued,
288 EventKind::SignalConsumed,
289 EventKind::DraftHeld,
290 EventKind::DraftResolved,
291 EventKind::GoalRegistered,
292 EventKind::GoalConflict,
293 EventKind::ArbitrationVerdict,
294 EventKind::RepairStarted,
295 EventKind::RepairReused,
296 EventKind::WorktreeOpened,
297 EventKind::PrOpened,
298 EventKind::PrMerged,
299 EventKind::PrRejected,
300 EventKind::RoadmapClaimed,
301 EventKind::RoadmapFinished,
302 EventKind::RoadmapReleased,
303 EventKind::RoadmapSplit,
304 EventKind::RoadmapBlocked,
305 EventKind::PursuitChanged,
306 EventKind::ApprovalRequested,
307 EventKind::ApprovalResolved,
308 EventKind::PolicyCreated,
309 EventKind::PolicyRevoked,
310 EventKind::TaintPromoted,
311 EventKind::CrossBuildingTransfer,
312 EventKind::CityHalted,
313 EventKind::BackpressureShed,
314 EventKind::DigestInvalidated,
315 EventKind::EndpointAttached,
316 EventKind::EndpointProbed,
317 EventKind::EndpointLost,
318 EventKind::ModelSelected,
319 EventKind::ProviderDegraded,
320 EventKind::LoginStarted,
321 EventKind::EvalRun,
322 EventKind::AssetArchived,
323 EventKind::CredentialLent,
324 EventKind::SecretCaptured,
325 EventKind::SecretEgressBlocked,
326 EventKind::FileDiscarded,
327 EventKind::DiscardRestored,
328 EventKind::AutonomyChanged,
329 EventKind::WentBack,
330 EventKind::FileRestored,
331 EventKind::GovernedDocumentWritten,
332 EventKind::SpineDocumentWritten,
333 EventKind::RulesChanged,
334 EventKind::ToolkitLinkOpened,
335 EventKind::EmbeddingCalled,
336 EventKind::RerankCalled,
337 EventKind::AdviserAsked,
338 EventKind::AdviserAnswered,
339 EventKind::AdviserFellBack,
340 EventKind::CacheRenewed,
341 EventKind::HarnessReported,
342 EventKind::HarnessAnswered,
343 EventKind::RemoteOpened,
344 EventKind::RemoteClosed,
345 EventKind::DevicePaired,
346 EventKind::DeviceRevoked,
347 EventKind::RemoteSessionStarted,
348 EventKind::DocumentWritten,
349 EventKind::ProposalOffered,
350 EventKind::ProposalDecided,
351 EventKind::ProposalWithdrawn,
352 EventKind::RunPolicyChanged,
353 EventKind::SessionNamed,
354 EventKind::SkillAudited,
355 EventKind::SignalWaitStarted,
356 EventKind::SignalWaitEnded,
357 EventKind::SignalLanded,
358 EventKind::SkillShelved,
359 ];
360}
361
362#[cfg(test)]
363#[allow(
364 clippy::unwrap_used,
365 clippy::expect_used,
366 clippy::panic,
367 clippy::indexing_slicing,
368 reason = "test code"
369)]
370mod tests;