Skip to main content

g2g_core/
conformance.rs

1//! Conformance vocabulary + derived maturity (M614).
2//!
3//! g2g grows fast under agent-driven development, so "how validated is this
4//! element?" must be answerable honestly. The trap is a hand-authored maturity
5//! field: under fast iteration it drifts into an overclaim (a level bumped in the
6//! same change that adds the feature). This module removes that trap by making
7//! maturity a **pure function of evidence**, where evidence is produced only by a
8//! conformance case that actually ran and passed.
9//!
10//! An element's [`MaturityRecord`] is a bag of [`Evidence`], each tagging one
11//! [`ConformanceDimension`] that was verified (optionally with the platform, codec,
12//! or external peer it was verified against). [`MaturityRecord::level`] derives a
13//! conservative headline [`MaturityLevel`] from that bag: you cannot reach
14//! [`InteropTested`](MaturityLevel::InteropTested) without an [`Oracle`] evidence
15//! naming a *peer*, nor [`HardwareValidated`](MaturityLevel::HardwareValidated)
16//! without a [`Hardware`] evidence naming a *platform*. There is no setter for the
17//! level, so the record cannot claim more than its evidence supports.
18//!
19//! Crucially, the *absence* of evidence is itself the honest signal: an element that
20//! round-trips in-process but has never been checked against an external
21//! implementation carries no `Oracle` evidence and so lands at
22//! [`UnitTested`](MaturityLevel::UnitTested), which is exactly the
23//! "loopback-tested, not interop-validated" caveat expressed as data rather than a
24//! comment.
25//!
26//! [`Oracle`]: ConformanceDimension::Oracle
27//! [`Hardware`]: ConformanceDimension::Hardware
28
29use alloc::format;
30use alloc::string::{String, ToString};
31use alloc::vec::Vec;
32
33/// A kind of check a conformance case can verify about an element.
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ConformanceDimension {
36    /// The element constructs and advertises its metadata / pad caps.
37    Instantiate,
38    /// Every advertised property round-trips through `set` / `get` and rejects a
39    /// bad value.
40    Properties,
41    /// Data survives the element (or a packetize / depacketize, encode / decode
42    /// pair) intact: a self-contained behavioral check.
43    RoundTrip,
44    /// The element recovers from lost / reordered / duplicated input (e.g. a
45    /// depacketizer through dropped packets, a -7 seamless merge).
46    LossResilience,
47    /// The pixels / samples themselves were measured: decoded output matches a
48    /// committed golden digest, or clears a PSNR floor against a reference. A
49    /// structural round-trip says data survived; this says it is still correct.
50    Quality,
51    /// A graph built around the element is proven zero-copy by the copy plan
52    /// (`crate::copyplan`): no host round-trip of a raw frame.
53    ZeroCopy,
54    /// A measured latency / throughput figure (informational; does not raise the
55    /// maturity level on its own).
56    Latency,
57    /// Validated against an external reference implementation (ffmpeg, GStreamer, a
58    /// hardware peer). Only counts toward maturity when it names the `peer`.
59    Oracle,
60    /// Exercised on real hardware / a real device. Only counts toward maturity when
61    /// it names the `platform`.
62    Hardware,
63}
64
65impl ConformanceDimension {
66    /// Every dimension, in reporting order.
67    pub const ALL: [ConformanceDimension; 9] = [
68        ConformanceDimension::Instantiate,
69        ConformanceDimension::Properties,
70        ConformanceDimension::RoundTrip,
71        ConformanceDimension::LossResilience,
72        ConformanceDimension::Quality,
73        ConformanceDimension::ZeroCopy,
74        ConformanceDimension::Latency,
75        ConformanceDimension::Oracle,
76        ConformanceDimension::Hardware,
77    ];
78
79    /// A short kebab-case label.
80    pub fn label(self) -> &'static str {
81        match self {
82            ConformanceDimension::Instantiate => "instantiate",
83            ConformanceDimension::Properties => "properties",
84            ConformanceDimension::RoundTrip => "round-trip",
85            ConformanceDimension::LossResilience => "loss-resilience",
86            ConformanceDimension::Quality => "quality",
87            ConformanceDimension::ZeroCopy => "zero-copy",
88            ConformanceDimension::Latency => "latency",
89            ConformanceDimension::Oracle => "oracle",
90            ConformanceDimension::Hardware => "hardware",
91        }
92    }
93
94    /// Parse a [`label`](Self::label) back (for the persisted evidence log). `None`
95    /// for an unknown token, so a malformed log line is skipped, not trusted.
96    pub fn from_label(s: &str) -> Option<Self> {
97        Self::ALL.into_iter().find(|d| d.label() == s)
98    }
99}
100
101/// One passed conformance check: the dimension it verified, plus the context it was
102/// verified in. Build with [`Evidence::new`] and the context setters; construct one
103/// only when the check actually passed.
104#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct Evidence {
106    /// What was verified.
107    pub dimension: ConformanceDimension,
108    /// The platform it ran on (e.g. `"linux"`, `"pixel-10a"`). Required for
109    /// [`Hardware`](ConformanceDimension::Hardware) to count toward maturity.
110    pub platform: Option<String>,
111    /// The codec / format the check covered (e.g. `"h264"`, `"rgba8"`).
112    pub codec: Option<String>,
113    /// The external implementation it was validated against (e.g. `"ffmpeg"`).
114    /// Required for [`Oracle`](ConformanceDimension::Oracle) to count.
115    pub peer: Option<String>,
116    /// A free-text note (fixture name, measured figure, caveat).
117    pub detail: Option<String>,
118}
119
120impl Evidence {
121    /// Evidence for `dimension` with no context yet.
122    pub fn new(dimension: ConformanceDimension) -> Self {
123        Self {
124            dimension,
125            platform: None,
126            codec: None,
127            peer: None,
128            detail: None,
129        }
130    }
131
132    /// Tag the platform this ran on.
133    pub fn platform(mut self, p: impl Into<String>) -> Self {
134        self.platform = Some(p.into());
135        self
136    }
137
138    /// Tag the codec / format covered.
139    pub fn codec(mut self, c: impl Into<String>) -> Self {
140        self.codec = Some(c.into());
141        self
142    }
143
144    /// Tag the external peer validated against.
145    pub fn peer(mut self, p: impl Into<String>) -> Self {
146        self.peer = Some(p.into());
147        self
148    }
149
150    /// Attach a free-text note.
151    pub fn detail(mut self, d: impl Into<String>) -> Self {
152        self.detail = Some(d.into());
153        self
154    }
155}
156
157/// The conservative headline maturity of an element, derived from its evidence.
158/// Ordered: a higher level strictly implies more validation.
159#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
160pub enum MaturityLevel {
161    /// No conformance evidence.
162    Unverified,
163    /// Constructs and advertises its interface (caps / properties).
164    Instantiated,
165    /// Passes a self-contained behavioral check (round-trip, loss resilience, or a
166    /// zero-copy graph), but has not been validated against an external peer.
167    UnitTested,
168    /// Validated against an external reference implementation (a named peer).
169    InteropTested,
170    /// Validated on real hardware (a named platform).
171    HardwareValidated,
172}
173
174impl MaturityLevel {
175    /// A short label.
176    pub fn label(self) -> &'static str {
177        match self {
178            MaturityLevel::Unverified => "unverified",
179            MaturityLevel::Instantiated => "instantiated",
180            MaturityLevel::UnitTested => "unit-tested",
181            MaturityLevel::InteropTested => "interop-tested",
182            MaturityLevel::HardwareValidated => "hardware-validated",
183        }
184    }
185}
186
187/// One element's conformance evidence, from which its [`MaturityLevel`] is derived.
188/// There is deliberately no way to set the level directly.
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub struct MaturityRecord {
191    /// The element's name (its registry / log category).
192    pub element: String,
193    /// Every passed check.
194    pub evidence: Vec<Evidence>,
195}
196
197impl MaturityRecord {
198    /// A record for `element` with no evidence yet (maturity [`Unverified`]).
199    ///
200    /// [`Unverified`]: MaturityLevel::Unverified
201    pub fn new(element: impl Into<String>) -> Self {
202        Self {
203            element: element.into(),
204            evidence: Vec::new(),
205        }
206    }
207
208    /// Add one piece of evidence (builder style).
209    pub fn with(mut self, e: Evidence) -> Self {
210        self.evidence.push(e);
211        self
212    }
213
214    /// Add one piece of evidence.
215    pub fn add(&mut self, e: Evidence) {
216        self.evidence.push(e);
217    }
218
219    /// Whether any evidence covers `dimension`.
220    pub fn has(&self, dimension: ConformanceDimension) -> bool {
221        self.evidence.iter().any(|e| e.dimension == dimension)
222    }
223
224    /// The distinct dimensions with evidence, in reporting order.
225    pub fn dimensions(&self) -> Vec<ConformanceDimension> {
226        ConformanceDimension::ALL
227            .into_iter()
228            .filter(|&d| self.has(d))
229            .collect()
230    }
231
232    /// The distinct external peers this element was validated against.
233    pub fn peers(&self) -> Vec<&str> {
234        let mut v: Vec<&str> = self
235            .evidence
236            .iter()
237            .filter_map(|e| e.peer.as_deref())
238            .collect();
239        v.sort_unstable();
240        v.dedup();
241        v
242    }
243
244    /// The distinct platforms this element was validated on.
245    pub fn platforms(&self) -> Vec<&str> {
246        let mut v: Vec<&str> = self
247            .evidence
248            .iter()
249            .filter_map(|e| e.platform.as_deref())
250            .collect();
251        v.sort_unstable();
252        v.dedup();
253        v
254    }
255
256    /// The derived headline maturity. `Oracle` counts only with a named peer and
257    /// `Hardware` only with a named platform, so the level never overstates what the
258    /// evidence supports.
259    pub fn level(&self) -> MaturityLevel {
260        use ConformanceDimension as D;
261        let has_hardware = self
262            .evidence
263            .iter()
264            .any(|e| e.dimension == D::Hardware && e.platform.is_some());
265        let has_interop = self
266            .evidence
267            .iter()
268            .any(|e| e.dimension == D::Oracle && e.peer.is_some());
269        let behavioral = self.has(D::RoundTrip)
270            || self.has(D::LossResilience)
271            || self.has(D::Quality)
272            || self.has(D::ZeroCopy);
273        let advertised = self.has(D::Instantiate) || self.has(D::Properties);
274        if has_hardware {
275            MaturityLevel::HardwareValidated
276        } else if has_interop {
277            MaturityLevel::InteropTested
278        } else if behavioral {
279            MaturityLevel::UnitTested
280        } else if advertised {
281            MaturityLevel::Instantiated
282        } else {
283            MaturityLevel::Unverified
284        }
285    }
286}
287
288/// A collection of [`MaturityRecord`]s, rendered as a matrix table.
289#[derive(Debug, Clone, Default)]
290pub struct ConformanceReport {
291    /// Per-element records.
292    pub records: Vec<MaturityRecord>,
293}
294
295impl ConformanceReport {
296    /// An empty report.
297    pub fn new() -> Self {
298        Self::default()
299    }
300
301    /// Add a record.
302    pub fn push(&mut self, record: MaturityRecord) {
303        self.records.push(record);
304    }
305
306    /// The record for `element`, inserting an empty one if absent.
307    pub fn record_mut(&mut self, element: &str) -> &mut MaturityRecord {
308        if let Some(i) = self.records.iter().position(|r| r.element == element) {
309            &mut self.records[i]
310        } else {
311            self.records.push(MaturityRecord::new(element));
312            self.records.last_mut().expect("just pushed")
313        }
314    }
315
316    /// Merge another report into this one: each record's evidence is unioned into the
317    /// matching element (deduplicating identical evidence). Used to fold persisted
318    /// `Oracle` / `Hardware` evidence (from the resource-owning tests) into the
319    /// in-process battery report, so the derived level rises to reflect it.
320    pub fn absorb(&mut self, other: ConformanceReport) {
321        for record in other.records {
322            let dst = self.record_mut(&record.element);
323            for ev in record.evidence {
324                if !dst.evidence.contains(&ev) {
325                    dst.evidence.push(ev);
326                }
327            }
328        }
329    }
330
331    /// The lowest maturity level across all records (the weakest link), or
332    /// [`Unverified`](MaturityLevel::Unverified) for an empty report.
333    pub fn min_level(&self) -> MaturityLevel {
334        self.records
335            .iter()
336            .map(MaturityRecord::level)
337            .min()
338            .unwrap_or(MaturityLevel::Unverified)
339    }
340
341    /// Render the report as an aligned text table: element, derived level, the
342    /// dimensions with evidence, and any peers / platforms.
343    pub fn to_table(&self) -> String {
344        let rows: Vec<(String, String, String, String)> = self
345            .records
346            .iter()
347            .map(|r| {
348                let dims = r
349                    .dimensions()
350                    .iter()
351                    .map(|d| d.label())
352                    .collect::<Vec<_>>()
353                    .join(", ");
354                let mut context = Vec::new();
355                let peers = r.peers();
356                if !peers.is_empty() {
357                    context.push(format!("peers: {}", peers.join(", ")));
358                }
359                let plats = r.platforms();
360                if !plats.is_empty() {
361                    context.push(format!("platforms: {}", plats.join(", ")));
362                }
363                (
364                    r.element.clone(),
365                    r.level().label().to_string(),
366                    dims,
367                    context.join("; "),
368                )
369            })
370            .collect();
371
372        let w_el = rows.iter().map(|r| r.0.len()).chain([7]).max().unwrap_or(7);
373        let w_lv = rows.iter().map(|r| r.1.len()).chain([5]).max().unwrap_or(5);
374        let mut s = String::new();
375        s.push_str(&format!(
376            "{:<w_el$}  {:<w_lv$}  dimensions\n",
377            "element", "maturity"
378        ));
379        for (el, lv, dims, ctx) in &rows {
380            s.push_str(&format!("{el:<w_el$}  {lv:<w_lv$}  {dims}\n"));
381            if !ctx.is_empty() {
382                s.push_str(&format!("{:<w_el$}  {:<w_lv$}  ({ctx})\n", "", ""));
383            }
384        }
385        s
386    }
387}
388
389#[cfg(test)]
390mod tests {
391    use super::*;
392
393    #[test]
394    fn empty_record_is_unverified() {
395        assert_eq!(MaturityRecord::new("x").level(), MaturityLevel::Unverified);
396    }
397
398    #[test]
399    fn instantiate_alone_is_instantiated() {
400        let r = MaturityRecord::new("capsfilter")
401            .with(Evidence::new(ConformanceDimension::Instantiate))
402            .with(Evidence::new(ConformanceDimension::Properties));
403        assert_eq!(r.level(), MaturityLevel::Instantiated);
404    }
405
406    #[test]
407    fn a_round_trip_reaches_unit_tested_but_not_interop() {
408        // The honesty case: a loopback round-trip proves behavior but is NOT interop
409        // validation, so with no peer-tagged oracle the element stays UnitTested.
410        let r = MaturityRecord::new("st2110video")
411            .with(Evidence::new(ConformanceDimension::Instantiate))
412            .with(Evidence::new(ConformanceDimension::RoundTrip).codec("rgba8"));
413        assert_eq!(r.level(), MaturityLevel::UnitTested);
414        assert!(!r.has(ConformanceDimension::Oracle), "no interop claim");
415    }
416
417    #[test]
418    fn a_golden_quality_check_reaches_unit_tested_but_not_interop() {
419        // A committed golden digest proves the decoder still produces the same
420        // pixels, which is behavioral evidence, but nothing external looked at it.
421        let r = MaturityRecord::new("rav1ddec")
422            .with(Evidence::new(ConformanceDimension::Quality).codec("av1"));
423        assert_eq!(r.level(), MaturityLevel::UnitTested);
424        assert!(!r.has(ConformanceDimension::Oracle));
425    }
426
427    #[test]
428    fn oracle_without_a_peer_does_not_reach_interop() {
429        // A bare Oracle evidence with no named peer is a hollow claim and must not
430        // raise the level past UnitTested.
431        let r = MaturityRecord::new("h264enc")
432            .with(Evidence::new(ConformanceDimension::RoundTrip))
433            .with(Evidence::new(ConformanceDimension::Oracle));
434        assert_eq!(r.level(), MaturityLevel::UnitTested);
435    }
436
437    #[test]
438    fn oracle_with_a_peer_reaches_interop() {
439        let r = MaturityRecord::new("h264enc")
440            .with(Evidence::new(ConformanceDimension::RoundTrip))
441            .with(
442                Evidence::new(ConformanceDimension::Oracle)
443                    .peer("ffmpeg")
444                    .codec("h264"),
445            );
446        assert_eq!(r.level(), MaturityLevel::InteropTested);
447        assert_eq!(r.peers(), alloc::vec!["ffmpeg"]);
448    }
449
450    #[test]
451    fn hardware_with_a_platform_is_the_top_level() {
452        let r = MaturityRecord::new("nvh264dec")
453            .with(Evidence::new(ConformanceDimension::Oracle).peer("ffmpeg"))
454            .with(Evidence::new(ConformanceDimension::Hardware).platform("rtx-3060"));
455        assert_eq!(r.level(), MaturityLevel::HardwareValidated);
456        assert_eq!(r.platforms(), alloc::vec!["rtx-3060"]);
457    }
458
459    #[test]
460    fn levels_are_ordered() {
461        assert!(MaturityLevel::Unverified < MaturityLevel::Instantiated);
462        assert!(MaturityLevel::UnitTested < MaturityLevel::InteropTested);
463        assert!(MaturityLevel::InteropTested < MaturityLevel::HardwareValidated);
464    }
465
466    #[test]
467    fn dimension_labels_round_trip() {
468        for d in ConformanceDimension::ALL {
469            assert_eq!(ConformanceDimension::from_label(d.label()), Some(d));
470        }
471        assert_eq!(ConformanceDimension::from_label("bogus"), None);
472    }
473
474    #[test]
475    fn absorb_merges_persisted_evidence_and_raises_the_level() {
476        // The in-process battery derives UnitTested; a persisted Oracle (with a peer)
477        // folded in via absorb raises the same element to InteropTested.
478        let mut base = ConformanceReport::new();
479        base.push(
480            MaturityRecord::new("mp4mux")
481                .with(Evidence::new(ConformanceDimension::Instantiate))
482                .with(Evidence::new(ConformanceDimension::RoundTrip)),
483        );
484        assert_eq!(base.record_mut("mp4mux").level(), MaturityLevel::UnitTested);
485
486        let mut persisted = ConformanceReport::new();
487        persisted.push(
488            MaturityRecord::new("mp4mux").with(
489                Evidence::new(ConformanceDimension::Oracle)
490                    .peer("ffmpeg")
491                    .codec("h264"),
492            ),
493        );
494        base.absorb(persisted);
495        assert_eq!(
496            base.record_mut("mp4mux").level(),
497            MaturityLevel::InteropTested
498        );
499        assert_eq!(
500            base.records.len(),
501            1,
502            "merged into the existing element, not duplicated"
503        );
504    }
505
506    #[test]
507    fn absorb_deduplicates_identical_evidence() {
508        let mut a = ConformanceReport::new();
509        a.push(MaturityRecord::new("x").with(Evidence::new(ConformanceDimension::RoundTrip)));
510        let mut b = ConformanceReport::new();
511        b.push(MaturityRecord::new("x").with(Evidence::new(ConformanceDimension::RoundTrip)));
512        a.absorb(b);
513        assert_eq!(
514            a.record_mut("x").evidence.len(),
515            1,
516            "identical evidence is not doubled"
517        );
518    }
519
520    #[test]
521    fn report_table_lists_rows_and_min_level() {
522        let mut report = ConformanceReport::new();
523        report.push(
524            MaturityRecord::new("st2110video")
525                .with(Evidence::new(ConformanceDimension::Instantiate))
526                .with(Evidence::new(ConformanceDimension::RoundTrip)),
527        );
528        report.push(MaturityRecord::new("unchecked"));
529        let table = report.to_table();
530        assert!(table.contains("st2110video"), "row present:\n{table}");
531        assert!(
532            table.contains("unit-tested"),
533            "derived level shown:\n{table}"
534        );
535        assert!(table.contains("round-trip"), "dimension shown:\n{table}");
536        assert_eq!(
537            report.min_level(),
538            MaturityLevel::Unverified,
539            "the unchecked element drags the min down"
540        );
541    }
542}