Skip to main content

kernel/event/
moment.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//! Which lines record the moment their own event happened, read from the
7//! line's kind and version (`crates/kernel/spec/Event.lean` ยง8-4, "what the envelope `t`
8//! records"). A reader asks here rather than comparing neighbouring
9//! lines' `t` or guessing from the build that exported them.
10
11use super::{EventKind, EventRecord, TimeMs};
12use crate::consts_external::EVENT_LOG_V;
13
14/// The first ledger version whose waited-for lines record their own
15/// moment; a line written before carries its turn's stamp there.
16const MOMENTS_SINCE_V: u32 = 2;
17
18// A build that writes an older version than the one moments start at
19// would answer `None` for every line it writes itself.
20const _: () = assert!(MOMENTS_SINCE_V <= EVENT_LOG_V);
21
22impl EventKind {
23    /// Whether a line of this kind records the moment its own event
24    /// happened: a model attempt sent, a reply whole, a tool call started,
25    /// a call's answer. The roster of those four kinds.
26    pub fn records_a_moment(&self) -> bool {
27        matches!(
28            self,
29            EventKind::ModelCalled
30                | EventKind::ModelReturned
31                | EventKind::ToolCalled
32                | EventKind::ToolResult
33        )
34    }
35}
36
37impl EventRecord {
38    /// This line's own moment: `Some(t)` for a kind that
39    /// [`records_a_moment`](EventKind::records_a_moment), written at a
40    /// version that measures it; `None` for every other line. A `None` on
41    /// one of those four kinds means the moment was not measured, not
42    /// that it took no time.
43    pub fn moment(&self) -> Option<TimeMs> {
44        (self.v() >= MOMENTS_SINCE_V && self.kind().records_a_moment()).then(|| self.t())
45    }
46}
47
48#[cfg(test)]
49#[allow(clippy::unwrap_used, reason = "test code")]
50mod tests;