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