Skip to main content

clawft_kernel/node_facts/
measured.rs

1//! Load measured `perf.*` capabilities written by the cog conformance
2//! harness (`scripts/build.sh cogs-conformance sweep|probe`) or an
3//! admission probe.
4//!
5//! Accepts the harness `capabilities.json` (a list) or a probe document
6//! (`{"capabilities": [...]}`). Only `perf.*` entries with provenance
7//! `measured` are kept; attributes the harness writes as `null` are dropped
8//! before validation. Everything else is skipped and counted, never
9//! silently upgraded.
10
11use clawft_types::placement::{Capability, Provenance};
12use serde_json::Value;
13
14/// Largest measured-results file read, in bytes.
15pub const MAX_MEASURED_BYTES: usize = 4 << 20;
16
17/// Parsed results: kept capabilities and how many entries were skipped.
18#[derive(Debug, Clone, Default, PartialEq)]
19pub struct Measured {
20    /// Valid measured `perf.*` capabilities.
21    pub caps: Vec<Capability>,
22    /// Entries skipped (wrong family, not measured, or invalid).
23    pub skipped: usize,
24}
25
26/// Parse a harness results document.
27pub fn parse_measured(text: &str) -> Result<Measured, String> {
28    if text.len() > MAX_MEASURED_BYTES {
29        return Err("measured results file too large".into());
30    }
31    let doc: Value = serde_json::from_str(text).map_err(|e| format!("not JSON: {e}"))?;
32    let list = match &doc {
33        Value::Array(v) => v.clone(),
34        Value::Object(o) => match o.get("capabilities") {
35            Some(Value::Array(v)) => v.clone(),
36            _ => return Err("expected a list or {\"capabilities\": [...]}".into()),
37        },
38        _ => return Err("expected a list or {\"capabilities\": [...]}".into()),
39    };
40    let mut out = Measured::default();
41    for mut entry in list {
42        if let Some(Value::Object(attrs)) = entry.get_mut("attrs") {
43            attrs.retain(|_, v| !v.is_null());
44        }
45        match serde_json::from_value::<Capability>(entry) {
46            Ok(c) if c.id.family() == "perf" && c.provenance == Provenance::Measured => {
47                out.caps.push(c);
48            }
49            _ => out.skipped += 1,
50        }
51    }
52    Ok(out)
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn keeps_measured_perf_and_drops_nulls() {
61        let text = r#"[
62          {"id":"perf.cog.cycle_ms","attrs":{"cog_id":"fall-detect","value":790.5,"interval_s":null},
63           "provenance":"measured","state":"available","exclusive":false},
64          {"id":"perf.cog.cycle_ms","attrs":{"cog_id":"x","value":1.0},"provenance":"claimed"},
65          {"id":"cpu.arch.aarch64","provenance":"measured"},
66          {"id":"BAD ID","provenance":"measured"}
67        ]"#;
68        let m = parse_measured(text).unwrap();
69        assert_eq!(m.caps.len(), 1);
70        assert_eq!(m.skipped, 3);
71        assert!(!m.caps[0].attrs.contains_key("interval_s"));
72    }
73
74    #[test]
75    fn accepts_probe_document_and_rejects_other_shapes() {
76        let doc = r#"{"cog":"a","capabilities":[{"id":"perf.infer.tok_s","attrs":{"model":"m","value":42.0},"provenance":"measured"}]}"#;
77        assert_eq!(parse_measured(doc).unwrap().caps.len(), 1);
78        assert!(parse_measured(r#"{"x":1}"#).is_err());
79        assert!(parse_measured("nope").is_err());
80    }
81}