Skip to main content

wire/answer/
note.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//! What a turn came to besides its calls (`crates/wire/spec/Reading.lean`
7//! ยง8-21, D36-D38).
8
9use kernel::event::record::SignalKind;
10use kernel::{Address, AxError, GitOid, RunId, Seq, TimeMs};
11use serde::{Deserialize, Serialize};
12
13/// What a turn came to besides the calls it made.
14///
15/// **The criterion is closed on purpose**: an event earns a `Note` when
16/// it changed what this turn did, or what it is waiting on. Everything
17/// else stays in the event stream, which is the Ledger's shape rather
18/// than a reader's. Without that line this enum would grow to one arm
19/// per event kind and stop meaning anything.
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
23pub enum Note {
24    /// A door refused something. The error travels whole because the
25    /// interface has one place where a refusal becomes the three parts a
26    /// person needs; taking it apart here would be the second.
27    Refused { error: AxError, at: Seq },
28    /// A checkpoint went up, and this is the commit it made. It is
29    /// what a change list is addressed by.
30    Checkpointed { oid: GitOid, at: Seq },
31    /// This turn stopped for a person. What waits and who answers is the
32    /// approval queue's; copying it here would be a third authority.
33    /// `t` is when the Ledger recorded the request and `answered` when
34    /// it recorded the answer, paired back by approval id from the
35    /// city's own run; `None` when the answer is outside that window or
36    /// has not come, and the page then draws no guessed end.
37    Waiting {
38        at: Seq,
39        t: TimeMs,
40        answered: Option<TimeMs>,
41    },
42    /// A word arrived - from the person watching, or from another
43    /// address that reached this one (D36). `t` is when this session
44    /// took it. A pulled signal's sender and words sit on its sending
45    /// line, under the sender's run, so `from` and `said` are `None`
46    /// until the server's fold pairs that line by its id, and stay
47    /// `None` when the sending is outside the window it searches.
48    Arrived {
49        from: Option<String>,
50        said: Option<String>,
51        by: Speaker,
52        t: TimeMs,
53        /// Present when the signal is a child session handing its work
54        /// back (D38).
55        handback: Option<HandbackNote>,
56        /// The kind the letter was sent as, from its sending line; `None`
57        /// for a steer, which is no letter, and when the sending was not
58        /// paired (D43).
59        #[cfg_attr(feature = "schema", schemars(with = "Option<String>"))]
60        kind: Option<SignalKind>,
61        /// The session that sent the letter: the run its sending line was
62        /// written under, which for a handback is the child's. `None` in
63        /// the same cases as `kind` (D43).
64        session: Option<RunId>,
65        at: Seq,
66    },
67    /// This turn sent with `wait` and stopped until a reply from `on`
68    /// or `until` (D37). `ended` is `None` while it waits, and when its
69    /// end is outside the window.
70    AwaitingReply {
71        on: Address,
72        until: TimeMs,
73        t: TimeMs,
74        ended: Option<ReplyEnded>,
75        at: Seq,
76    },
77    /// Files went away. Every one carries its way back, which is the
78    /// Recycle Bin's to state.
79    Discarded { count: usize, at: Seq },
80    /// A record of a kind that earns a note, whose payload did not read
81    /// back as that kind. The failure stays visible here instead of the
82    /// turn reading as if nothing happened; `cause` names the kind and
83    /// what the reading stopped at.
84    Unreadable { cause: String, at: Seq },
85}
86
87impl Note {
88    /// Where in the Ledger this note is, so every row can be read
89    /// further.
90    #[must_use]
91    pub fn at(&self) -> Seq {
92        match *self {
93            Self::Refused { at, .. }
94            | Self::Checkpointed { at, .. }
95            | Self::Waiting { at, .. }
96            | Self::Arrived { at, .. }
97            | Self::AwaitingReply { at, .. }
98            | Self::Discarded { at, .. }
99            | Self::Unreadable { at, .. } => at,
100        }
101    }
102}
103
104/// Who spoke a word that arrived: the person who owns the city, through
105/// a steer; the city itself, through a steer; or a resident, through a
106/// steer or a signal (D36, D41).
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
108#[serde(rename_all = "snake_case")]
109#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
110pub enum Speaker {
111    User,
112    City,
113    Resident,
114}
115
116/// How a child session's handed-back work ended, read through
117/// `collab::Handback::from_signal`; which session it was is
118/// [`Note::Arrived`]'s `session` (D38, D43).
119#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
120#[serde(rename_all = "snake_case")]
121#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
122pub enum HandbackNote {
123    Finished { verified_by: String },
124    Stopped { because: String },
125}
126
127/// The end of a reply wait, and when the Ledger recorded it (D37).
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
129#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
130pub struct ReplyEnded {
131    pub by: ReplyEnd,
132    pub t: TimeMs,
133}
134
135/// What ended a reply wait, one arm per arm of `kernel`'s `WaitEnd`;
136/// the reply itself is an `Arrived` note of its own.
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
138#[serde(rename_all = "snake_case")]
139#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
140pub enum ReplyEnd {
141    Reply,
142    Timeout,
143    Left,
144}