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}