entrenar/citl/trainer/
correlation.rs1use super::{DecisionTrace, SourceSpan};
4use crate::citl::FixSuggestion;
5
6#[derive(Debug, Clone)]
8pub struct ErrorCorrelation {
9 pub error_code: String,
11 pub error_span: SourceSpan,
13 pub suspicious_decisions: Vec<SuspiciousDecision>,
15 pub fix_suggestions: Vec<FixSuggestion>,
17}
18
19#[derive(Debug, Clone)]
21pub struct SuspiciousDecision {
22 pub decision: DecisionTrace,
24 pub suspiciousness: f32,
26 pub reason: String,
28}
29
30impl SuspiciousDecision {
31 #[must_use]
33 pub fn new(decision: DecisionTrace, suspiciousness: f32, reason: impl Into<String>) -> Self {
34 Self { decision, suspiciousness: suspiciousness.clamp(0.0, 1.0), reason: reason.into() }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn test_suspicious_decision_new() {
44 let trace = DecisionTrace::new("d1", "type", "desc");
45 let suspicious = SuspiciousDecision::new(trace, 0.8, "high suspicion");
46 assert_eq!(suspicious.suspiciousness, 0.8);
47 }
48
49 #[test]
50 fn test_suspicious_decision_clamped() {
51 let trace = DecisionTrace::new("d1", "type", "desc");
52 let suspicious = SuspiciousDecision::new(trace, 1.5, "over max");
53 assert_eq!(suspicious.suspiciousness, 1.0);
54 }
55}
56
57#[cfg(test)]
58mod prop_tests {
59 use super::*;
60 use proptest::prelude::*;
61
62 proptest! {
63 #[test]
64 fn prop_suspiciousness_clamped(score in -10.0f32..10.0) {
65 let trace = DecisionTrace::new("d", "type", "desc");
66 let suspicious = SuspiciousDecision::new(trace, score, "reason");
67 prop_assert!(suspicious.suspiciousness >= 0.0);
68 prop_assert!(suspicious.suspiciousness <= 1.0);
69 }
70 }
71}