Skip to main content

nv_runtime/
provenance.rs

1//! Provenance types — audit trail for stage and view-system decisions.
2
3use nv_core::id::StageId;
4use nv_core::timestamp::{Duration, MonotonicTs};
5use nv_view::view_state::{ViewEpoch, ViewVersion};
6use nv_view::{EpochDecision, MotionSource, TransitionPhase};
7
8/// Full provenance for one processed frame.
9///
10/// Every output carries this, making production debugging tractable.
11///
12/// # Timing semantics
13///
14/// All timestamps are [`MonotonicTs`] values — they share the same monotonic
15/// clock domain as [`FrameEnvelope::ts()`](nv_frame::FrameEnvelope::ts).
16///
17/// - `frame_receive_ts` — when the frame was dequeued from the bounded queue.
18/// - `pipeline_complete_ts` — when all stages finished and output was constructed.
19/// - Per-stage `start_ts` / `end_ts` — real wall-clock offsets converted to
20///   monotonic nanoseconds from the pipeline epoch for ordering consistency.
21#[derive(Debug, Clone)]
22pub struct Provenance {
23    /// Per-stage provenance records, in execution order.
24    pub stages: Vec<StageProvenance>,
25    /// View-system provenance for this frame.
26    pub view_provenance: ViewProvenance,
27    /// Timestamp when the frame was dequeued from the bounded queue
28    /// (start of pipeline processing for this frame).
29    pub frame_receive_ts: MonotonicTs,
30    /// Timestamp when the pipeline completed processing this frame.
31    pub pipeline_complete_ts: MonotonicTs,
32    /// Total pipeline latency (receive → complete).
33    pub total_latency: Duration,
34    /// Wall-clock age of the frame at processing time.
35    ///
36    /// Computed as `WallTs::now() - frame.wall_ts()` when the frame
37    /// enters pipeline processing. A large value indicates the frame
38    /// was stale before the executor even touched it — typically due
39    /// to buffer-pool starvation, TCP backlog, or slow decode.
40    ///
41    /// `None` if wall-clock age could not be determined (e.g., if the
42    /// frame's wall timestamp is in the future due to clock skew).
43    pub frame_age: Option<Duration>,
44    /// Time the frame spent waiting in the bounded queue.
45    ///
46    /// Measured from `push()` to `pop()` using `Instant`. A
47    /// consistently low value combined with high `frame_age` proves
48    /// that staleness originates upstream of the queue (e.g., in the
49    /// decoder or TCP receive buffer), not from queue backlog.
50    pub queue_hold_time: std::time::Duration,
51    /// Whether this output includes the source frame.
52    ///
53    /// Always `true` for `FrameInclusion::Always`, always `false` for
54    /// `FrameInclusion::Never`, and periodic for
55    /// `FrameInclusion::Sampled`.
56    pub frame_included: bool,
57}
58
59/// Per-stage provenance record.
60#[derive(Debug, Clone)]
61pub struct StageProvenance {
62    /// Which stage.
63    pub stage_id: StageId,
64    /// When the stage started processing (monotonic nanos from pipeline epoch).
65    pub start_ts: MonotonicTs,
66    /// When the stage finished processing.
67    pub end_ts: MonotonicTs,
68    /// Stage processing latency.
69    pub latency: Duration,
70    /// Whether the stage succeeded, failed, or skipped.
71    pub result: StageResult,
72}
73
74/// Outcome of a stage's processing for one frame.
75#[derive(Debug, Clone, PartialEq)]
76pub enum StageResult {
77    /// Stage completed successfully.
78    Ok,
79    /// Stage failed on this frame.
80    Error(StageOutcomeCategory),
81    /// Stage opted out for this frame.
82    Skipped,
83}
84
85/// Typed failure category for stage provenance.
86///
87/// A summary for programmatic filtering and dashboarding.
88/// Full diagnostic detail remains in tracing logs.
89#[derive(Debug, Clone, PartialEq)]
90pub enum StageOutcomeCategory {
91    /// Inference or computation failed.
92    ProcessingFailed,
93    /// Stage ran out of a resource (GPU OOM, buffer limit, etc.).
94    ResourceExhausted,
95    /// Model or external dependency unavailable.
96    DependencyUnavailable,
97    /// Stage panicked (caught by executor).
98    Panic,
99    /// Uncategorized — carries a short, stable tag chosen by the stage author.
100    Other {
101        /// A static tag for filtering (e.g., `"calibration_stale"`).
102        tag: &'static str,
103    },
104}
105
106/// Per-frame provenance of the view system's decisions.
107///
108/// Consumers can audit exactly why the view system made the choices
109/// it did for any given frame.
110#[derive(Debug, Clone)]
111pub struct ViewProvenance {
112    /// The motion source used for this frame.
113    pub motion_source: MotionSource,
114    /// The epoch decision made this frame.
115    /// `None` if the view system was not consulted (no motion detected,
116    /// or `CameraMode::Fixed`).
117    pub epoch_decision: Option<EpochDecision>,
118    /// Transition phase at this frame.
119    pub transition: TransitionPhase,
120    /// Stability score at this frame.
121    pub stability_score: f32,
122    /// View epoch at this frame.
123    pub epoch: ViewEpoch,
124    /// View version at this frame.
125    pub version: ViewVersion,
126}