datasynth_eval/coherence/
mod.rs1mod balance;
7mod document_chain;
8mod intercompany;
9mod multi_table;
10mod network;
11mod referential;
12mod standards;
13mod subledger;
14
15pub use balance::{BalanceSheetEvaluation, BalanceSheetEvaluator};
16pub use document_chain::{DocumentChainEvaluation, DocumentChainEvaluator};
17pub use intercompany::{ICMatchingEvaluation, ICMatchingEvaluator};
18pub use multi_table::{
19 get_o2c_flow_relationships, get_p2p_flow_relationships, AnomalyRecord, CascadeAnomalyAnalysis,
20 CascadePath, ConsistencyViolation, MultiTableConsistencyEvaluator, MultiTableData,
21 MultiTableEvaluation, TableConsistencyResult, TableRecord, TableRelationship,
22 TableRelationshipDef, ViolationType,
23};
24pub use network::{
25 ConcentrationMetrics, NetworkEdge, NetworkEvaluation, NetworkEvaluator, NetworkNode,
26 NetworkThresholds, StrengthStats,
27};
28pub use referential::{ReferentialIntegrityEvaluation, ReferentialIntegrityEvaluator};
29pub use standards::{
30 AuditTrailEvaluation, AuditTrailGap, FairValueEvaluation, FrameworkViolation,
31 ImpairmentEvaluation, IsaComplianceEvaluation, LeaseAccountingEvaluation,
32 LeaseAccountingEvaluator, LeaseEvaluation, PcaobComplianceEvaluation, PerformanceObligation,
33 RevenueContract, RevenueRecognitionEvaluation, RevenueRecognitionEvaluator,
34 SoxComplianceEvaluation, StandardsComplianceEvaluation, StandardsThresholds,
35 VariableConsideration, ViolationSeverity,
36};
37pub use subledger::{SubledgerEvaluator, SubledgerReconciliationEvaluation};
38
39use serde::{Deserialize, Serialize};
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct CoherenceEvaluation {
44 pub balance: Option<BalanceSheetEvaluation>,
46 pub subledger: Option<SubledgerReconciliationEvaluation>,
48 pub document_chain: Option<DocumentChainEvaluation>,
50 pub intercompany: Option<ICMatchingEvaluation>,
52 pub referential: Option<ReferentialIntegrityEvaluation>,
54 pub multi_table: Option<MultiTableEvaluation>,
56 pub standards: Option<StandardsComplianceEvaluation>,
58 pub network: Option<NetworkEvaluation>,
60 pub passes: bool,
62 pub failures: Vec<String>,
64}
65
66impl CoherenceEvaluation {
67 pub fn new() -> Self {
69 Self {
70 balance: None,
71 subledger: None,
72 document_chain: None,
73 intercompany: None,
74 referential: None,
75 multi_table: None,
76 standards: None,
77 network: None,
78 passes: true,
79 failures: Vec::new(),
80 }
81 }
82
83 pub fn check_thresholds(&mut self, thresholds: &crate::config::EvaluationThresholds) {
85 self.failures.clear();
86
87 if let Some(ref balance) = self.balance {
88 if !balance.equation_balanced {
89 self.failures.push(format!(
90 "Balance sheet equation not balanced (max imbalance: {})",
91 balance.max_imbalance
92 ));
93 }
94 }
95
96 if let Some(ref subledger) = self.subledger {
97 if subledger.completeness_score < thresholds.subledger_reconciliation_rate_min {
98 self.failures.push(format!(
99 "Subledger reconciliation {} < {} (threshold)",
100 subledger.completeness_score, thresholds.subledger_reconciliation_rate_min
101 ));
102 }
103 }
104
105 if let Some(ref doc_chain) = self.document_chain {
106 let min_rate = thresholds.document_chain_completion_min;
107 if doc_chain.p2p_completion_rate < min_rate {
108 self.failures.push(format!(
109 "P2P chain completion {} < {} (threshold)",
110 doc_chain.p2p_completion_rate, min_rate
111 ));
112 }
113 if doc_chain.o2c_completion_rate < min_rate {
114 self.failures.push(format!(
115 "O2C chain completion {} < {} (threshold)",
116 doc_chain.o2c_completion_rate, min_rate
117 ));
118 }
119 }
120
121 if let Some(ref ic) = self.intercompany {
122 if ic.match_rate < thresholds.ic_match_rate_min {
123 self.failures.push(format!(
124 "IC match rate {} < {} (threshold)",
125 ic.match_rate, thresholds.ic_match_rate_min
126 ));
127 }
128 }
129
130 if let Some(ref referential) = self.referential {
131 if referential.overall_integrity_score < thresholds.referential_integrity_min {
132 self.failures.push(format!(
133 "Referential integrity {} < {} (threshold)",
134 referential.overall_integrity_score, thresholds.referential_integrity_min
135 ));
136 }
137 }
138
139 if let Some(ref multi_table) = self.multi_table {
140 if multi_table.overall_consistency_score < thresholds.referential_integrity_min {
142 self.failures.push(format!(
143 "Multi-table consistency {} < {} (threshold)",
144 multi_table.overall_consistency_score, thresholds.referential_integrity_min
145 ));
146 }
147 self.failures.extend(multi_table.issues.clone());
149 }
150
151 if let Some(ref mut standards_eval) = self.standards.clone() {
152 let standards_thresholds = StandardsThresholds::default();
154 standards_eval.check_thresholds(&standards_thresholds);
155 self.failures.extend(standards_eval.failures.clone());
156 }
157
158 if let Some(ref network_eval) = self.network {
159 if !network_eval.passes {
161 self.failures.extend(network_eval.issues.clone());
162 }
163 }
164
165 self.passes = self.failures.is_empty();
166 }
167}
168
169impl Default for CoherenceEvaluation {
170 fn default() -> Self {
171 Self::new()
172 }
173}