Skip to main content

kmp_observability/
quality_telemetry_observation.rs

1use std::time::{SystemTime, UNIX_EPOCH};
2
3use kmp_domain::{BundleQualityMetrics, QualityObservationContext};
4use serde::{Deserialize, Serialize};
5
6/// One typed, timestamped quality observation persisted by local telemetry.
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct QualityTelemetryObservation {
9    observed_at_millis: u64,
10    rpc: String,
11    root_node_id: String,
12    role: String,
13    #[serde(default)]
14    revision: Option<u64>,
15    raw_equivalent_tokens: u32,
16    compression_ratio: f64,
17    causal_density: f64,
18    noise_ratio: f64,
19    detail_coverage: f64,
20}
21
22impl QualityTelemetryObservation {
23    pub fn capture(metrics: &BundleQualityMetrics, context: &QualityObservationContext) -> Self {
24        Self {
25            observed_at_millis: SystemTime::now()
26                .duration_since(UNIX_EPOCH)
27                .map(|elapsed| u64::try_from(elapsed.as_millis()).unwrap_or(u64::MAX))
28                .unwrap_or(0),
29            rpc: context.rpc.clone(),
30            root_node_id: context.root_node_id.clone(),
31            role: context.role.clone(),
32            revision: context.revision,
33            raw_equivalent_tokens: metrics.raw_equivalent_tokens(),
34            compression_ratio: metrics.compression_ratio(),
35            causal_density: metrics.causal_density(),
36            noise_ratio: metrics.noise_ratio(),
37            detail_coverage: metrics.detail_coverage(),
38        }
39    }
40
41    pub fn observed_at_millis(&self) -> u64 {
42        self.observed_at_millis
43    }
44
45    pub fn rpc(&self) -> &str {
46        &self.rpc
47    }
48
49    pub fn root_node_id(&self) -> &str {
50        &self.root_node_id
51    }
52
53    pub fn role(&self) -> &str {
54        &self.role
55    }
56
57    pub fn revision(&self) -> Option<u64> {
58        self.revision
59    }
60
61    pub fn raw_equivalent_tokens(&self) -> u32 {
62        self.raw_equivalent_tokens
63    }
64
65    pub fn compression_ratio(&self) -> f64 {
66        self.compression_ratio
67    }
68
69    pub fn causal_density(&self) -> f64 {
70        self.causal_density
71    }
72
73    pub fn noise_ratio(&self) -> f64 {
74        self.noise_ratio
75    }
76
77    pub fn detail_coverage(&self) -> f64 {
78        self.detail_coverage
79    }
80}