Skip to main content

mnemo_baseline/
profile.rs

1//! Rolling per-agent profile (v0.4.1 P0-3).
2
3use std::collections::HashMap;
4use std::time::Duration;
5
6use serde::{Deserialize, Serialize};
7
8pub type ToolId = String;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub struct AgentBaseline {
12    pub agent: String,
13    /// Window the rolling rates cover (e.g. 5 minutes).
14    pub window: Duration,
15    pub recall_rate_per_min: f32,
16    pub write_rate_per_min: f32,
17    /// How many distinct namespaces this agent touched per minute.
18    /// Spike → possible cross-tenant scan.
19    pub namespace_fanout: f32,
20    /// Per-tool fraction of total ops. Sums to ~1.0.
21    pub tool_mix: HashMap<ToolId, f32>,
22    /// Fraction of audit rows whose `prev_hash` matched the running
23    /// chain head. 1.0 = perfect; <1.0 = HMAC chain has been
24    /// tampered with or replayed.
25    pub hmac_continuity: f32,
26}
27
28impl AgentBaseline {
29    pub fn new(agent: impl Into<String>, window: Duration) -> Self {
30        Self {
31            agent: agent.into(),
32            window,
33            recall_rate_per_min: 0.0,
34            write_rate_per_min: 0.0,
35            namespace_fanout: 0.0,
36            tool_mix: HashMap::new(),
37            hmac_continuity: 1.0,
38        }
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn new_baseline_starts_at_zero() {
48        let b = AgentBaseline::new("agent-1", Duration::from_secs(300));
49        assert_eq!(b.agent, "agent-1");
50        assert_eq!(b.recall_rate_per_min, 0.0);
51        assert_eq!(b.hmac_continuity, 1.0);
52    }
53}