Skip to main content

lean_ctx/core/
verification_observability.rs

1use serde::Serialize;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::time::SystemTime;
4
5static SLO_EVALS: AtomicU64 = AtomicU64::new(0);
6
7#[derive(Debug, Clone, Serialize)]
8pub struct VerificationObservabilityV1 {
9    pub schema_version: u32,
10    pub created_at: String,
11    pub role: String,
12    pub profile: String,
13    pub budgets: crate::core::budget_tracker::BudgetSnapshot,
14    pub slo: crate::core::slo::SloSnapshot,
15    pub verification: crate::core::output_verification::VerificationSnapshot,
16    pub proof: crate::core::context_proof::ProofStatsSnapshot,
17    pub pipeline: crate::core::pipeline::PipelineStats,
18    pub counters: CountersSnapshot,
19}
20
21#[derive(Debug, Clone, Serialize)]
22pub struct CountersSnapshot {
23    pub slo_evals: u64,
24}
25
26pub fn record_slo_eval() {
27    SLO_EVALS.fetch_add(1, Ordering::Relaxed);
28}
29
30pub fn snapshot_v1() -> VerificationObservabilityV1 {
31    let created_at = chrono::Utc::now().to_rfc3339();
32    let role = crate::core::roles::active_role_name();
33    let profile = crate::core::profiles::active_profile_name();
34
35    let budgets = crate::core::budget_tracker::BudgetTracker::global().check();
36    let slo = crate::core::slo::evaluate_quiet();
37    let verification = crate::core::output_verification::stats_snapshot();
38    let proof = crate::core::context_proof::proof_stats_snapshot();
39    let pipeline = crate::core::pipeline::PipelineStats::load();
40
41    VerificationObservabilityV1 {
42        schema_version: crate::core::contracts::VERIFICATION_OBSERVABILITY_V1_SCHEMA_VERSION,
43        created_at,
44        role,
45        profile,
46        budgets,
47        slo,
48        verification,
49        proof,
50        pipeline,
51        counters: CountersSnapshot {
52            slo_evals: SLO_EVALS.load(Ordering::Relaxed),
53        },
54    }
55}
56
57pub fn format_compact(v: &VerificationObservabilityV1) -> String {
58    let proof_last = v
59        .proof
60        .last_written_at
61        .clone()
62        .unwrap_or_else(|| "-".to_string());
63    format!(
64        "{}\n{}\n{}\nProof: written={} last={proof_last}",
65        v.verification.format_compact(),
66        v.slo.format_compact(),
67        v.budgets.format_compact(),
68        v.proof.written
69    )
70}
71
72// Keep this module obviously "count-only": no secret content is stored.
73#[allow(dead_code)]
74fn _unix_ms_now() -> u128 {
75    SystemTime::now()
76        .duration_since(SystemTime::UNIX_EPOCH)
77        .map_or(0, |d| d.as_millis())
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn snapshot_has_schema_version() {
86        let s = snapshot_v1();
87        assert_eq!(s.schema_version, 1);
88        assert!(s.created_at.contains('T'));
89        let compact = format_compact(&s);
90        assert!(compact.contains("Verification:"));
91        assert!(compact.contains("Proof: written="));
92    }
93}