1use super::engine::{GateProfile, QualityGate, QualityMetric};
6
7pub fn strict_profile() -> GateProfile {
18 GateProfile::new(
19 "strict",
20 vec![
21 QualityGate::lte("benford_compliance", QualityMetric::BenfordMad, 0.01),
22 QualityGate::gte("balance_coherence", QualityMetric::BalanceCoherence, 0.999),
23 QualityGate::gte(
24 "document_chain_integrity",
25 QualityMetric::DocumentChainIntegrity,
26 0.95,
27 ),
28 QualityGate::gte(
29 "temporal_consistency",
30 QualityMetric::TemporalConsistency,
31 0.90,
32 ),
33 QualityGate::gte("completion_rate", QualityMetric::CompletionRate, 0.99),
34 QualityGate::lte("duplicate_rate", QualityMetric::DuplicateRate, 0.001),
35 QualityGate::gte(
36 "referential_integrity",
37 QualityMetric::ReferentialIntegrity,
38 0.999,
39 ),
40 QualityGate::gte("ic_match_rate", QualityMetric::IcMatchRate, 0.99),
41 QualityGate::lte("privacy_mia_auc", QualityMetric::PrivacyMiaAuc, 0.55),
42 ],
43 )
44}
45
46pub fn default_profile() -> GateProfile {
57 GateProfile::new(
58 "default",
59 vec![
60 QualityGate::lte("benford_compliance", QualityMetric::BenfordMad, 0.015),
61 QualityGate::gte("balance_coherence", QualityMetric::BalanceCoherence, 0.99),
62 QualityGate::gte(
63 "document_chain_integrity",
64 QualityMetric::DocumentChainIntegrity,
65 0.90,
66 ),
67 QualityGate::gte(
68 "temporal_consistency",
69 QualityMetric::TemporalConsistency,
70 0.80,
71 ),
72 QualityGate::gte("completion_rate", QualityMetric::CompletionRate, 0.95),
73 QualityGate::lte("duplicate_rate", QualityMetric::DuplicateRate, 0.01),
74 QualityGate::gte(
75 "referential_integrity",
76 QualityMetric::ReferentialIntegrity,
77 0.99,
78 ),
79 QualityGate::gte("ic_match_rate", QualityMetric::IcMatchRate, 0.95),
80 QualityGate::lte("privacy_mia_auc", QualityMetric::PrivacyMiaAuc, 0.60),
81 ],
82 )
83}
84
85pub fn lenient_profile() -> GateProfile {
96 GateProfile::new(
97 "lenient",
98 vec![
99 QualityGate::lte("benford_compliance", QualityMetric::BenfordMad, 0.03),
100 QualityGate::gte("balance_coherence", QualityMetric::BalanceCoherence, 0.95),
101 QualityGate::gte(
102 "document_chain_integrity",
103 QualityMetric::DocumentChainIntegrity,
104 0.80,
105 ),
106 QualityGate::gte(
107 "temporal_consistency",
108 QualityMetric::TemporalConsistency,
109 0.60,
110 ),
111 QualityGate::gte("completion_rate", QualityMetric::CompletionRate, 0.90),
112 QualityGate::lte("duplicate_rate", QualityMetric::DuplicateRate, 0.05),
113 QualityGate::gte(
114 "referential_integrity",
115 QualityMetric::ReferentialIntegrity,
116 0.95,
117 ),
118 QualityGate::gte("ic_match_rate", QualityMetric::IcMatchRate, 0.85),
119 QualityGate::lte("privacy_mia_auc", QualityMetric::PrivacyMiaAuc, 0.70),
120 ],
121 )
122}
123
124pub fn get_profile(name: &str) -> Option<GateProfile> {
128 match name {
129 "strict" => Some(strict_profile()),
130 "default" => Some(default_profile()),
131 "lenient" => Some(lenient_profile()),
132 _ => None,
133 }
134}
135
136#[cfg(test)]
137#[allow(clippy::unwrap_used)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_strict_profile_has_gates() {
143 let profile = strict_profile();
144 assert_eq!(profile.name, "strict");
145 assert!(!profile.gates.is_empty());
146 assert!(profile.gates.len() >= 5);
147 }
148
149 #[test]
150 fn test_default_profile_has_gates() {
151 let profile = default_profile();
152 assert_eq!(profile.name, "default");
153 assert!(!profile.gates.is_empty());
154 }
155
156 #[test]
157 fn test_lenient_profile_has_gates() {
158 let profile = lenient_profile();
159 assert_eq!(profile.name, "lenient");
160 assert!(!profile.gates.is_empty());
161 }
162
163 #[test]
164 fn test_strict_thresholds_tighter_than_lenient() {
165 let strict = strict_profile();
166 let lenient = lenient_profile();
167
168 let strict_benford = strict
170 .gates
171 .iter()
172 .find(|g| g.metric == QualityMetric::BenfordMad);
173 let lenient_benford = lenient
174 .gates
175 .iter()
176 .find(|g| g.metric == QualityMetric::BenfordMad);
177
178 if let (Some(s), Some(l)) = (strict_benford, lenient_benford) {
179 assert!(
181 s.threshold < l.threshold,
182 "strict MAD ({}) should be < lenient MAD ({})",
183 s.threshold,
184 l.threshold
185 );
186 }
187 }
188
189 #[test]
190 fn test_get_profile_by_name() {
191 assert!(get_profile("strict").is_some());
192 assert!(get_profile("default").is_some());
193 assert!(get_profile("lenient").is_some());
194 assert!(get_profile("nonexistent").is_none());
195 }
196
197 #[test]
198 fn test_profile_serialization_roundtrip() {
199 for name in &["strict", "default", "lenient"] {
200 let profile = get_profile(name).expect("profile should exist");
201 let json = serde_json::to_string(&profile).expect("should serialize");
202 let deser: GateProfile = serde_json::from_str(&json).expect("should deserialize");
203 assert_eq!(deser.name, *name);
204 assert_eq!(deser.gates.len(), profile.gates.len());
205 }
206 }
207}