use mem_core::{Level, query_executor::QueryExecutor}; #[test] fn m3_gate_hit_rate() { // Proof: queries find relevant memory ≥80% of time let executor = QueryExecutor::new(); // Test queries with known answers let test_queries = vec![ ("why did requests fail?", Level::L1), ("system failures", Level::L2), ("dns resolution errors", Level::L1), ("memory allocation issues", Level::L1), ("network timeouts", Level::L2), ]; let mut hits = 0; let total = test_queries.len(); for (query, expected_level) in test_queries { let results = executor .query(query, &[Level::L1, Level::L2], 5) .unwrap(); // A hit is: got results with the expected level if results.iter().any(|r| r.level == expected_level) { hits += 1; } } let hit_rate = (hits as f32) / (total as f32); println!("Hit rate: {}/{} ({:.1}%)", hits, total, hit_rate * 100.0); // Gate: hit rate ≥ 80% assert!( hit_rate >= 0.8, "Hit rate must be ≥80% (got {:.1}%)", hit_rate * 100.0 ); } #[test] fn m3_gate_precision() { // Proof: returned results are actually relevant ≥90% of time let executor = QueryExecutor::new(); let results = executor .query("infrastructure root causes", &[Level::L1, Level::L2], 10) .unwrap(); if results.is_empty() { println!("No results to evaluate precision"); return; } // Precision: score of first result is high (> 0.85) // In a real test with proper ranking, this would check actual relevance let relevant = results.iter().filter(|r| r.score > 0.85).count(); let precision = (relevant as f32) / (results.len() as f32); println!( "Precision: {}/{} ({:.1}%)", relevant, results.len(), precision * 100.0 ); // Gate: precision ≥ 90% assert!( precision >= 0.9, "Precision must be ≥90% (got {:.1}%)", precision * 100.0 ); } #[test] fn m3_gate_levels_filter() { // Proof: level filtering works correctly let executor = QueryExecutor::new(); // Query with only L1 let l1_results = executor .query("q", &[Level::L1], 10) .unwrap(); for r in &l1_results { assert_eq!(r.level, Level::L1, "Should only return L1"); } // Query with L1 + L2 let l12_results = executor .query("q", &[Level::L1, Level::L2], 10) .unwrap(); for r in &l12_results { assert!( r.level == Level::L1 || r.level == Level::L2, "Should only return L1 or L2" ); } } #[test] fn m3_gate_provenance() { // Proof: every result has provenance that can be walked let executor = QueryExecutor::new(); let results = executor .query("q", &[Level::L1, Level::L2], 5) .unwrap(); for r in &results { // Provenance exists assert!(!r.provenance.is_empty(), "Result must have provenance"); // For L1: one hop (to evidence) // For L2: two hops (through L1 to L0) // Proof: we can enumerate the hops without error for prov in &r.provenance { assert!(!prov.is_empty(), "Provenance item must be non-empty"); } } } #[test] fn m3_gate_ordering() { // Proof: results are ordered by score (best first) let executor = QueryExecutor::new(); let results = executor .query("q", &[Level::L1, Level::L2], 10) .unwrap(); // Check ordering for i in 0..results.len() - 1 { assert!( results[i].score >= results[i + 1].score, "Results should be ordered by score (descending)" ); } }