metrale_bench/gate/
record_summary.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-26: The one-line summary a gate record carries, and the clock it
4//! is stamped with.
5//!
6//! Owner: bench gate (records).
7//! Invariants: none beyond the types.
8
9use std::time::{SystemTime, UNIX_EPOCH};
10
11use crate::history::RunRecord;
12
13/// 2026-09-26: `<model> · <metric=value, …> · <verdict kind>: <reason>`, with
14/// `no metrics` / `no verdict` for absent parts, plus the first Warn or Error
15/// log line when there is one.
16pub(super) fn summarize(record: &RunRecord) -> String {
17    let frame = &record.frame;
18    let numbers: Vec<String> = frame
19        .metrics
20        .iter()
21        .map(|(k, v)| format!("{k}={v:.2}"))
22        .collect();
23    let numbers = if numbers.is_empty() {
24        "no metrics".to_string()
25    } else {
26        numbers.join(", ")
27    };
28    let warning = frame
29        .log
30        .iter()
31        .find(|l| {
32            matches!(
33                l.level,
34                crate::result::LogLevel::Warn | crate::result::LogLevel::Error
35            )
36        })
37        .map(|l| format!(" · warning: {}", l.text));
38    let verdict = frame
39        .verdict
40        .as_ref()
41        .map(|v| format!("{:?}: {}", v.kind, v.reason))
42        .unwrap_or_else(|| "no verdict".into());
43    format!(
44        "{} · {} · {}{}",
45        record.target_model,
46        numbers,
47        verdict,
48        warning.unwrap_or_default()
49    )
50}
51
52/// 2026-09-26: Unix seconds now; 0 when the clock reads before the epoch.
53pub fn now_secs() -> u64 {
54    SystemTime::now()
55        .duration_since(UNIX_EPOCH)
56        .map(|d| d.as_secs())
57        .unwrap_or_default()
58}