Skip to main content

remem/eval/governance/
types.rs

1use serde::Serialize;
2
3#[derive(Debug, Clone, Copy)]
4pub struct GovernanceEvalOptions {
5    pub k: usize,
6}
7
8impl Default for GovernanceEvalOptions {
9    fn default() -> Self {
10        Self { k: 5 }
11    }
12}
13
14#[derive(Debug, Serialize)]
15pub struct GovernanceEvalReport {
16    pub metadata: GovernanceEvalMetadata,
17    pub metrics: GovernanceMetricSummary,
18    pub lifecycle_counts: LifecycleCounts,
19    pub summary_candidates: CandidateSummary,
20    pub owner_checks: Vec<OwnerCheckReport>,
21    pub queries: Vec<QueryReport>,
22    pub context: ContextReport,
23    pub failing_examples: Vec<String>,
24}
25
26#[derive(Debug, Serialize)]
27pub struct GovernanceEvalMetadata {
28    pub corpus: String,
29    pub storage: String,
30    pub data_dir: String,
31    pub real_db_touched: bool,
32    pub project: String,
33    pub nested_projects: Vec<String>,
34    pub k: usize,
35}
36
37#[derive(Debug, Serialize)]
38pub struct GovernanceMetricSummary {
39    pub owner_routing_accuracy: RateMetric,
40    pub evidence_recall_at_k: RateMetric,
41    pub active_current_precision: RateMetric,
42    pub stale_exclusion_rate: RateMetric,
43    pub context_injection_precision: RateMetric,
44    pub all_checks_passed: bool,
45}
46
47#[derive(Debug, Clone, Serialize, PartialEq)]
48pub struct RateMetric {
49    pub passed: usize,
50    pub total: usize,
51    pub rate: f64,
52}
53
54impl RateMetric {
55    pub fn new(passed: usize, total: usize) -> Self {
56        Self {
57            passed,
58            total,
59            rate: if total == 0 {
60                0.0
61            } else {
62                passed as f64 / total as f64
63            },
64        }
65    }
66
67    pub fn is_perfect(&self) -> bool {
68        self.total > 0 && self.passed == self.total
69    }
70}
71
72#[derive(Debug, Default, Clone, Serialize, PartialEq, Eq)]
73pub struct LifecycleCounts {
74    pub add: usize,
75    pub update: usize,
76    pub invalidate: usize,
77    pub noop: usize,
78    pub defer: usize,
79    pub conflict: usize,
80}
81
82#[derive(Debug, Serialize)]
83pub struct CandidateSummary {
84    pub total: usize,
85    pub pending_review: usize,
86    pub auto_promoted: usize,
87    pub active_summary_memories: usize,
88}
89
90#[derive(Debug, Clone, Serialize)]
91pub struct OwnerCheckReport {
92    pub object_ref: String,
93    pub expected_scope: String,
94    pub expected_key: String,
95    pub expected_target_project: Option<String>,
96    pub actual_scope: Option<String>,
97    pub actual_key: Option<String>,
98    pub actual_target_project: Option<String>,
99    pub pass: bool,
100}
101
102#[derive(Debug, Clone, Serialize)]
103pub struct QueryReport {
104    pub id: String,
105    pub category: String,
106    pub query: String,
107    pub project: String,
108    pub memory_type: Option<String>,
109    pub branch: Option<String>,
110    pub expected_topic_keys: Vec<String>,
111    pub result_topic_keys: Vec<String>,
112    pub result_titles: Vec<String>,
113    pub matched_expected: usize,
114    pub forbidden_hits: Vec<String>,
115    pub unexpected_hits: Vec<String>,
116    pub pass: bool,
117}
118
119#[derive(Debug, Serialize)]
120pub struct ContextReport {
121    pub expected_topic_keys: Vec<String>,
122    pub included_topic_keys: Vec<String>,
123    pub included_titles: Vec<String>,
124    pub forbidden_titles: Vec<String>,
125    pub unexpected_topic_keys: Vec<String>,
126    pub unsafe_owner_included: usize,
127    pub excluded_owner_titles: Vec<String>,
128    pub pass: bool,
129}