zeph_common/clock.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Injectable wall-clock source (#6361).
5//!
6//! [`ClockSource`] abstracts "what time is it now" so callers on the agent's time-awareness
7//! paths (the `get_current_time` tool and periodic time-reminder injection) never call
8//! [`std::time::SystemTime::now`] directly — tests substitute [`FixedClock`] instead, keeping
9//! them deterministic. Deliberately returns [`std::time::SystemTime`], not a `chrono` type: this
10//! crate has no external date/time dependency (see [`crate::timestamp`]).
11
12use std::time::SystemTime;
13
14/// A source of the current wall-clock time.
15///
16/// Implementors must guarantee `now()` is cheap (no I/O, no blocking) since it is called on
17/// hot paths (tool execution, per-turn system-prompt assembly). Callers may assume the
18/// returned [`SystemTime`] reflects UTC "now" for [`SystemClock`], or a fixed, caller-chosen
19/// instant for [`FixedClock`].
20pub trait ClockSource: Send + Sync {
21 /// Returns the current time.
22 fn now(&self) -> SystemTime;
23}
24
25/// Production clock: wraps [`SystemTime::now`].
26#[derive(Debug, Clone, Default)]
27pub struct SystemClock;
28
29impl ClockSource for SystemClock {
30 fn now(&self) -> SystemTime {
31 SystemTime::now()
32 }
33}
34
35/// Test/repro clock: always returns the same fixed instant.
36///
37/// Not gated behind `#[cfg(test)]` — reproducible-run harnesses outside this crate may also
38/// want a deterministic clock (mirrors Codex's `clock_source` override).
39#[derive(Debug, Clone)]
40pub struct FixedClock(pub SystemTime);
41
42impl ClockSource for FixedClock {
43 fn now(&self) -> SystemTime {
44 self.0
45 }
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn system_clock_returns_recent_time() {
54 let before = SystemTime::now();
55 let observed = SystemClock.now();
56 let after = SystemTime::now();
57 assert!(observed >= before && observed <= after);
58 }
59
60 #[test]
61 fn fixed_clock_returns_the_same_instant_every_call() {
62 let t = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_700_000_000);
63 let clock = FixedClock(t);
64 assert_eq!(clock.now(), t);
65 assert_eq!(clock.now(), t);
66 }
67}