Skip to main content

datasynth_eval/coherence/
mod.rs

1//! Semantic coherence evaluation module.
2//!
3//! Validates that generated data maintains accounting coherence including
4//! balance sheet equations, subledger reconciliation, and document chain integrity.
5
6mod 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/// Combined coherence evaluation results.
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct CoherenceEvaluation {
39    /// Balance sheet validation results.
40    pub balance: Option<BalanceSheetEvaluation>,
41    /// Subledger reconciliation results.
42    pub subledger: Option<SubledgerReconciliationEvaluation>,
43    /// Document chain completeness results.
44    pub document_chain: Option<DocumentChainEvaluation>,
45    /// Intercompany matching results.
46    pub intercompany: Option<ICMatchingEvaluation>,
47    /// Referential integrity results.
48    pub referential: Option<ReferentialIntegrityEvaluation>,
49    /// Multi-table consistency results.
50    pub multi_table: Option<MultiTableEvaluation>,
51    /// Accounting and audit standards compliance results.
52    pub standards: Option<StandardsComplianceEvaluation>,
53    /// Overall pass/fail status.
54    pub passes: bool,
55    /// Summary of failed checks.
56    pub failures: Vec<String>,
57}
58
59impl CoherenceEvaluation {
60    /// Create a new empty evaluation.
61    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    /// Check all results against thresholds and update pass status.
76    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            // Check multi-table consistency (use referential_integrity_min as default threshold)
133            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            // Add any issues from the multi-table evaluation
140            self.failures.extend(multi_table.issues.clone());
141        }
142
143        if let Some(ref mut standards_eval) = self.standards.clone() {
144            // Use default standards thresholds
145            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}