1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! One type system, two clock drivers.
//!
//! The identity and coordinate authority is unified - every participant reads
//! [`RobotInstant`](crate::bus::RobotInstant)s on one
//! [`TimelineId`](crate::bus::TimelineId) - but the *tick mechanism*
//! deliberately is not:
//!
//! - **Real execution.** Robot time zero is host boot, so a real reading is the
//! host's suspend-aware monotonic boot clock
//! ([`LocalInstant`](crate::bus::LocalInstant)) read straight onto the
//! execution's timeline - there is no origin to anchor against and nothing to
//! distribute. Control ticks never wait on a bus message: making real-mode
//! cadence depend on a published clock would put the control loop behind a
//! transport that is explicitly allowed to drop samples under saturation, and
//! one-way published ticks cannot bound offset across hosts anyway.
//! - **Simulation and replay.** Exact discrete steps advanced by the world
//! authority (the simulation controller). No interpolation. Pause means no
//! new step; reset means a new timeline.
//!
//! # Losing clock discipline
//!
//! A participant that cannot trust its clock does **not** freeze, and does not
//! wait to see whether the clock comes back. Freezing the steps is exactly the
//! failure mode that leaves an actuator commanded, and a grace window would be
//! an invented uncertainty bound: nothing in this design estimates how wrong an
//! untrustworthy clock is, so there is no honest threshold to wait out.
//!
//! Instead the clock reports [`ClockReading::Unsynchronized`] and the runner
//! fails the participant immediately. Teardown runs, so `Participant::shutdown`
//! parks the hardware; time-sensitive publication stops because the process
//! stops; leases and actuator permits stop being renewed, so the receiver-side
//! deadlines and the driver-local watchdogs stop the machine on their own
//! clocks. The reason travels in the failure, and the supervisor's ordinary
//! restart and start-limit policy decides what happens next - a transient fault
//! recovers by restarting with no retained state at all, and a persistently
//! broken host clock exhausts the start limit and stops the graph.
//!
//! A real participant whose clock is already untrustworthy at startup never
//! reaches its first step: it fails there, for the same reason.
use crateRobotInstant;
pub
pub
/// Why a participant cannot currently produce a trustworthy robot instant.
///
/// One trigger per clock. The origin-shaped failures went with the origin:
/// real robot time is now the
/// host boot clock itself, so there is no supplied anchor to be missing and no
/// minted boot identity for a reading to disagree with - a process reads its
/// clock or it does not. Transport loss is deliberately not a trigger either:
/// same-host robot time has no bus discipline feed, so a dropped sample says
/// nothing about the clock.
///
/// `pub` because it is named by [`ClockReading`], which [`ClockSource::read`]
/// returns and the in-process runner seam therefore exposes.
/// Which clock a launched participant runs on.
///
/// The launch contract's `--simulation` flag is the whole of this decision:
/// simulation is a launcher
/// choice, never a bundle fact, and there is no third mode. A real participant
/// that declares no `#[phoxal::step]` simply never steps; it does not become a
/// different kind of participant.
pub
/// What a clock can currently say.
/// A source of robot time.