Skip to main content

datasynth_eval/coherence/
standards.rs

1//! Accounting and Audit Standards Compliance Evaluation.
2//!
3//! This module validates that generated data complies with accounting and
4//! auditing standards including IFRS, US GAAP, ISA, SOX, and PCAOB.
5
6use rust_decimal::Decimal;
7use rust_decimal_macros::dec;
8use serde::{Deserialize, Serialize};
9use std::collections::HashSet;
10
11// ============================================================================
12// Standards Compliance Evaluation
13// ============================================================================
14
15/// Comprehensive standards compliance evaluation.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct StandardsComplianceEvaluation {
18    /// Revenue recognition compliance (ASC 606/IFRS 15).
19    pub revenue_recognition: Option<RevenueRecognitionEvaluation>,
20    /// Lease accounting compliance (ASC 842/IFRS 16).
21    pub lease_accounting: Option<LeaseAccountingEvaluation>,
22    /// Fair value measurement compliance (ASC 820/IFRS 13).
23    pub fair_value: Option<FairValueEvaluation>,
24    /// Impairment testing compliance (ASC 360/IAS 36).
25    pub impairment: Option<ImpairmentEvaluation>,
26    /// ISA compliance.
27    pub isa_compliance: Option<IsaComplianceEvaluation>,
28    /// SOX compliance.
29    pub sox_compliance: Option<SoxComplianceEvaluation>,
30    /// PCAOB compliance.
31    pub pcaob_compliance: Option<PcaobComplianceEvaluation>,
32    /// Audit trail completeness.
33    pub audit_trail: Option<AuditTrailEvaluation>,
34    /// Overall pass/fail status.
35    pub passes: bool,
36    /// Summary of failures.
37    pub failures: Vec<String>,
38    /// Warnings (non-critical issues).
39    pub warnings: Vec<String>,
40}
41
42impl StandardsComplianceEvaluation {
43    /// Create a new empty evaluation.
44    pub fn new() -> Self {
45        Self {
46            revenue_recognition: None,
47            lease_accounting: None,
48            fair_value: None,
49            impairment: None,
50            isa_compliance: None,
51            sox_compliance: None,
52            pcaob_compliance: None,
53            audit_trail: None,
54            passes: true,
55            failures: Vec::new(),
56            warnings: Vec::new(),
57        }
58    }
59
60    /// Check all evaluations against thresholds.
61    pub fn check_thresholds(&mut self, thresholds: &StandardsThresholds) {
62        self.failures.clear();
63        self.warnings.clear();
64
65        // Check revenue recognition
66        if let Some(ref rev) = self.revenue_recognition {
67            if rev.po_allocation_compliance < thresholds.min_po_allocation_compliance {
68                self.failures.push(format!(
69                    "PO allocation compliance {:.2}% < {:.2}% (threshold)",
70                    rev.po_allocation_compliance * 100.0,
71                    thresholds.min_po_allocation_compliance * 100.0
72                ));
73            }
74            if rev.timing_compliance < thresholds.min_revenue_timing_compliance {
75                self.failures.push(format!(
76                    "Revenue timing compliance {:.2}% < {:.2}% (threshold)",
77                    rev.timing_compliance * 100.0,
78                    thresholds.min_revenue_timing_compliance * 100.0
79                ));
80            }
81        }
82
83        // Check lease accounting
84        if let Some(ref lease) = self.lease_accounting {
85            if lease.classification_accuracy < thresholds.min_lease_classification_accuracy {
86                self.failures.push(format!(
87                    "Lease classification accuracy {:.2}% < {:.2}% (threshold)",
88                    lease.classification_accuracy * 100.0,
89                    thresholds.min_lease_classification_accuracy * 100.0
90                ));
91            }
92            if lease.rou_asset_accuracy < thresholds.min_rou_asset_accuracy {
93                self.failures.push(format!(
94                    "ROU asset calculation accuracy {:.2}% < {:.2}% (threshold)",
95                    lease.rou_asset_accuracy * 100.0,
96                    thresholds.min_rou_asset_accuracy * 100.0
97                ));
98            }
99        }
100
101        // Check fair value
102        if let Some(ref fv) = self.fair_value {
103            if fv.hierarchy_compliance < thresholds.min_fair_value_hierarchy_compliance {
104                self.failures.push(format!(
105                    "Fair value hierarchy compliance {:.2}% < {:.2}% (threshold)",
106                    fv.hierarchy_compliance * 100.0,
107                    thresholds.min_fair_value_hierarchy_compliance * 100.0
108                ));
109            }
110        }
111
112        // Check impairment
113        if let Some(ref imp) = self.impairment {
114            if imp.trigger_recognition_rate < thresholds.min_impairment_trigger_rate {
115                self.warnings.push(format!(
116                    "Impairment trigger recognition rate {:.2}% < {:.2}% (warning)",
117                    imp.trigger_recognition_rate * 100.0,
118                    thresholds.min_impairment_trigger_rate * 100.0
119                ));
120            }
121        }
122
123        // Check ISA compliance
124        if let Some(ref isa) = self.isa_compliance {
125            if isa.coverage_rate < thresholds.min_isa_coverage {
126                self.failures.push(format!(
127                    "ISA coverage rate {:.2}% < {:.2}% (threshold)",
128                    isa.coverage_rate * 100.0,
129                    thresholds.min_isa_coverage * 100.0
130                ));
131            }
132        }
133
134        // Check SOX compliance
135        if let Some(ref sox) = self.sox_compliance {
136            if sox.control_coverage < thresholds.min_sox_control_coverage {
137                self.failures.push(format!(
138                    "SOX control coverage {:.2}% < {:.2}% (threshold)",
139                    sox.control_coverage * 100.0,
140                    thresholds.min_sox_control_coverage * 100.0
141                ));
142            }
143        }
144
145        // Check audit trail
146        if let Some(ref trail) = self.audit_trail {
147            if trail.completeness < thresholds.min_audit_trail_completeness {
148                self.failures.push(format!(
149                    "Audit trail completeness {:.2}% < {:.2}% (threshold)",
150                    trail.completeness * 100.0,
151                    thresholds.min_audit_trail_completeness * 100.0
152                ));
153            }
154        }
155
156        self.passes = self.failures.is_empty();
157    }
158}
159
160impl Default for StandardsComplianceEvaluation {
161    fn default() -> Self {
162        Self::new()
163    }
164}
165
166// ============================================================================
167// Revenue Recognition Evaluation (ASC 606 / IFRS 15)
168// ============================================================================
169
170/// Revenue recognition compliance evaluation.
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct RevenueRecognitionEvaluation {
173    /// Total contracts evaluated.
174    pub total_contracts: usize,
175    /// Contracts with valid structure.
176    pub valid_contracts: usize,
177    /// Performance obligation allocation compliance (0.0-1.0).
178    pub po_allocation_compliance: f64,
179    /// Revenue timing compliance (0.0-1.0).
180    pub timing_compliance: f64,
181    /// Variable consideration estimation compliance.
182    pub variable_consideration_compliance: f64,
183    /// Contract modification handling compliance.
184    pub modification_compliance: f64,
185    /// Framework-specific rule violations.
186    pub framework_violations: Vec<FrameworkViolation>,
187    /// Contracts with balanced revenue/deferred revenue.
188    pub balanced_contracts: usize,
189}
190
191impl RevenueRecognitionEvaluation {
192    /// Create a new evaluation.
193    pub fn new() -> Self {
194        Self {
195            total_contracts: 0,
196            valid_contracts: 0,
197            po_allocation_compliance: 1.0,
198            timing_compliance: 1.0,
199            variable_consideration_compliance: 1.0,
200            modification_compliance: 1.0,
201            framework_violations: Vec::new(),
202            balanced_contracts: 0,
203        }
204    }
205}
206
207impl Default for RevenueRecognitionEvaluation {
208    fn default() -> Self {
209        Self::new()
210    }
211}
212
213/// Revenue recognition evaluator.
214pub struct RevenueRecognitionEvaluator;
215
216impl RevenueRecognitionEvaluator {
217    /// Evaluate revenue recognition contracts.
218    pub fn evaluate(contracts: &[RevenueContract]) -> RevenueRecognitionEvaluation {
219        let mut eval = RevenueRecognitionEvaluation::new();
220        eval.total_contracts = contracts.len();
221
222        if contracts.is_empty() {
223            return eval;
224        }
225
226        let mut valid_count = 0;
227        let mut po_compliant = 0;
228        let mut timing_compliant = 0;
229        let mut vc_compliant = 0;
230        let mut balanced = 0;
231
232        for contract in contracts {
233            // Check contract validity
234            if contract.is_valid() {
235                valid_count += 1;
236            }
237
238            // Check PO allocation (must sum to transaction price)
239            if contract.check_po_allocation() {
240                po_compliant += 1;
241            } else {
242                eval.framework_violations.push(FrameworkViolation {
243                    standard: "ASC 606-10-32-28".to_string(),
244                    description: format!(
245                        "Contract {} PO allocation doesn't equal transaction price",
246                        contract.contract_id
247                    ),
248                    severity: ViolationSeverity::Error,
249                });
250            }
251
252            // Check revenue timing
253            if contract.check_revenue_timing() {
254                timing_compliant += 1;
255            }
256
257            // Check variable consideration
258            if contract.variable_consideration.is_none() || contract.check_variable_consideration()
259            {
260                vc_compliant += 1;
261            }
262
263            // Check revenue/deferred balance
264            if contract.check_balance() {
265                balanced += 1;
266            }
267        }
268
269        eval.valid_contracts = valid_count;
270        eval.po_allocation_compliance = po_compliant as f64 / contracts.len() as f64;
271        eval.timing_compliance = timing_compliant as f64 / contracts.len() as f64;
272        eval.variable_consideration_compliance = vc_compliant as f64 / contracts.len() as f64;
273        eval.balanced_contracts = balanced;
274
275        eval
276    }
277}
278
279/// Revenue contract for evaluation.
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct RevenueContract {
282    /// Contract identifier.
283    pub contract_id: String,
284    /// Transaction price.
285    pub transaction_price: Decimal,
286    /// Performance obligations.
287    pub performance_obligations: Vec<PerformanceObligation>,
288    /// Variable consideration.
289    pub variable_consideration: Option<VariableConsideration>,
290    /// Total revenue recognized.
291    pub revenue_recognized: Decimal,
292    /// Total deferred revenue.
293    pub deferred_revenue: Decimal,
294}
295
296impl RevenueContract {
297    /// Check if contract structure is valid.
298    pub fn is_valid(&self) -> bool {
299        !self.performance_obligations.is_empty() && self.transaction_price > dec!(0)
300    }
301
302    /// Check PO allocation sums to transaction price.
303    pub fn check_po_allocation(&self) -> bool {
304        let allocated: Decimal = self
305            .performance_obligations
306            .iter()
307            .map(|po| po.allocated_amount)
308            .sum();
309        (allocated - self.transaction_price).abs() < dec!(0.01)
310    }
311
312    /// Check revenue timing is consistent with satisfaction.
313    pub fn check_revenue_timing(&self) -> bool {
314        for po in &self.performance_obligations {
315            let expected_revenue = po.allocated_amount * po.satisfaction_percent;
316            let tolerance = po.allocated_amount * dec!(0.01); // 1% tolerance
317            if (po.recognized_revenue - expected_revenue).abs() > tolerance {
318                return false;
319            }
320        }
321        true
322    }
323
324    /// Check variable consideration is within constraint.
325    pub fn check_variable_consideration(&self) -> bool {
326        if let Some(ref vc) = self.variable_consideration {
327            // Variable consideration should be constrained (not overly optimistic)
328            vc.constrained_amount <= vc.expected_amount
329        } else {
330            true
331        }
332    }
333
334    /// Check revenue + deferred = transaction price.
335    pub fn check_balance(&self) -> bool {
336        let total = self.revenue_recognized + self.deferred_revenue;
337        (total - self.transaction_price).abs() < dec!(0.01)
338    }
339}
340
341/// Performance obligation for evaluation.
342#[derive(Debug, Clone, Serialize, Deserialize)]
343pub struct PerformanceObligation {
344    /// Obligation ID.
345    pub obligation_id: String,
346    /// Allocated amount.
347    pub allocated_amount: Decimal,
348    /// Satisfaction percentage (0.0-1.0 as Decimal).
349    pub satisfaction_percent: Decimal,
350    /// Revenue recognized.
351    pub recognized_revenue: Decimal,
352    /// Whether satisfaction is over time.
353    pub over_time: bool,
354}
355
356/// Variable consideration for evaluation.
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct VariableConsideration {
359    /// Expected amount.
360    pub expected_amount: Decimal,
361    /// Constrained amount (after applying constraint).
362    pub constrained_amount: Decimal,
363}
364
365// ============================================================================
366// Lease Accounting Evaluation (ASC 842 / IFRS 16)
367// ============================================================================
368
369/// Lease accounting compliance evaluation.
370#[derive(Debug, Clone, Serialize, Deserialize)]
371pub struct LeaseAccountingEvaluation {
372    /// Total leases evaluated.
373    pub total_leases: usize,
374    /// Finance leases count.
375    pub finance_leases: usize,
376    /// Operating leases count.
377    pub operating_leases: usize,
378    /// Classification accuracy.
379    pub classification_accuracy: f64,
380    /// ROU asset calculation accuracy.
381    pub rou_asset_accuracy: f64,
382    /// Lease liability accuracy.
383    pub lease_liability_accuracy: f64,
384    /// Discount rate reasonableness score.
385    pub discount_rate_reasonableness: f64,
386    /// Framework violations.
387    pub framework_violations: Vec<FrameworkViolation>,
388}
389
390impl LeaseAccountingEvaluation {
391    /// Create a new evaluation.
392    pub fn new() -> Self {
393        Self {
394            total_leases: 0,
395            finance_leases: 0,
396            operating_leases: 0,
397            classification_accuracy: 1.0,
398            rou_asset_accuracy: 1.0,
399            lease_liability_accuracy: 1.0,
400            discount_rate_reasonableness: 1.0,
401            framework_violations: Vec::new(),
402        }
403    }
404}
405
406impl Default for LeaseAccountingEvaluation {
407    fn default() -> Self {
408        Self::new()
409    }
410}
411
412/// Lease for evaluation.
413#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct LeaseEvaluation {
415    /// Lease identifier.
416    pub lease_id: String,
417    /// Lease term in months.
418    pub lease_term_months: u32,
419    /// Asset useful life in months.
420    pub asset_useful_life_months: u32,
421    /// Present value ratio (PV / fair value).
422    pub pv_ratio: f64,
423    /// Classified as finance lease.
424    pub is_finance: bool,
425    /// Framework used.
426    pub framework: String,
427    /// ROU asset initial measurement.
428    pub rou_asset_initial: Decimal,
429    /// Lease liability initial measurement.
430    pub lease_liability_initial: Decimal,
431    /// Discount rate used.
432    pub discount_rate: f64,
433}
434
435impl LeaseEvaluation {
436    /// Check US GAAP classification (bright-line tests).
437    pub fn check_us_gaap_classification(&self) -> bool {
438        let term_ratio = self.lease_term_months as f64 / self.asset_useful_life_months as f64;
439
440        // Bright-line tests
441        let should_be_finance = term_ratio >= 0.75 || self.pv_ratio >= 0.90;
442
443        self.is_finance == should_be_finance
444    }
445
446    /// Check IFRS classification (principles-based).
447    pub fn check_ifrs_classification(&self) -> bool {
448        // IFRS doesn't have bright-lines but similar indicators
449        let term_ratio = self.lease_term_months as f64 / self.asset_useful_life_months as f64;
450
451        // For evaluation, we use similar thresholds as indicators
452        let indicators_suggest_finance = term_ratio >= 0.75 || self.pv_ratio >= 0.90;
453
454        // IFRS is principles-based so some deviation is acceptable
455        self.is_finance == indicators_suggest_finance
456    }
457
458    /// Check ROU asset equals lease liability (plus prepayments, less incentives).
459    pub fn check_rou_equals_liability(&self) -> bool {
460        // For simplicity, check they're approximately equal
461        let diff = (self.rou_asset_initial - self.lease_liability_initial).abs();
462        diff < self.lease_liability_initial * dec!(0.05) // 5% tolerance
463    }
464}
465
466/// Lease accounting evaluator.
467pub struct LeaseAccountingEvaluator;
468
469impl LeaseAccountingEvaluator {
470    /// Evaluate lease accounting compliance.
471    pub fn evaluate(leases: &[LeaseEvaluation], framework: &str) -> LeaseAccountingEvaluation {
472        let mut eval = LeaseAccountingEvaluation::new();
473        eval.total_leases = leases.len();
474
475        if leases.is_empty() {
476            return eval;
477        }
478
479        let mut classification_correct = 0;
480        let mut rou_accurate = 0;
481
482        for lease in leases {
483            if lease.is_finance {
484                eval.finance_leases += 1;
485            } else {
486                eval.operating_leases += 1;
487            }
488
489            // Check classification
490            let classification_ok = if framework == "us_gaap" {
491                lease.check_us_gaap_classification()
492            } else {
493                lease.check_ifrs_classification()
494            };
495
496            if classification_ok {
497                classification_correct += 1;
498            } else {
499                eval.framework_violations.push(FrameworkViolation {
500                    standard: if framework == "us_gaap" {
501                        "ASC 842-10-25-2".to_string()
502                    } else {
503                        "IFRS 16.63".to_string()
504                    },
505                    description: format!(
506                        "Lease {} classification may be incorrect",
507                        lease.lease_id
508                    ),
509                    severity: ViolationSeverity::Warning,
510                });
511            }
512
513            // Check ROU/liability matching
514            if lease.check_rou_equals_liability() {
515                rou_accurate += 1;
516            }
517
518            // Check discount rate reasonableness (2-15% typical range)
519            if lease.discount_rate < 0.02 || lease.discount_rate > 0.15 {
520                eval.framework_violations.push(FrameworkViolation {
521                    standard: "ASC 842-20-30-3".to_string(),
522                    description: format!(
523                        "Lease {} discount rate {:.2}% unusual",
524                        lease.lease_id,
525                        lease.discount_rate * 100.0
526                    ),
527                    severity: ViolationSeverity::Warning,
528                });
529            }
530        }
531
532        eval.classification_accuracy = classification_correct as f64 / leases.len() as f64;
533        eval.rou_asset_accuracy = rou_accurate as f64 / leases.len() as f64;
534        eval.lease_liability_accuracy = eval.rou_asset_accuracy; // Same calculation
535
536        eval
537    }
538}
539
540// ============================================================================
541// Fair Value Measurement Evaluation (ASC 820 / IFRS 13)
542// ============================================================================
543
544/// Fair value measurement compliance evaluation.
545#[derive(Debug, Clone, Serialize, Deserialize)]
546pub struct FairValueEvaluation {
547    /// Total measurements evaluated.
548    pub total_measurements: usize,
549    /// Level 1 measurements (quoted prices).
550    pub level_1_count: usize,
551    /// Level 2 measurements (observable inputs).
552    pub level_2_count: usize,
553    /// Level 3 measurements (unobservable inputs).
554    pub level_3_count: usize,
555    /// Hierarchy compliance (0.0-1.0).
556    pub hierarchy_compliance: f64,
557    /// Valuation technique consistency.
558    pub technique_consistency: f64,
559    /// Framework violations.
560    pub framework_violations: Vec<FrameworkViolation>,
561}
562
563impl FairValueEvaluation {
564    /// Create a new evaluation.
565    pub fn new() -> Self {
566        Self {
567            total_measurements: 0,
568            level_1_count: 0,
569            level_2_count: 0,
570            level_3_count: 0,
571            hierarchy_compliance: 1.0,
572            technique_consistency: 1.0,
573            framework_violations: Vec::new(),
574        }
575    }
576}
577
578impl Default for FairValueEvaluation {
579    fn default() -> Self {
580        Self::new()
581    }
582}
583
584// ============================================================================
585// Impairment Testing Evaluation (ASC 360 / IAS 36)
586// ============================================================================
587
588/// Impairment testing compliance evaluation.
589#[derive(Debug, Clone, Serialize, Deserialize)]
590pub struct ImpairmentEvaluation {
591    /// Total tests evaluated.
592    pub total_tests: usize,
593    /// Tests with proper trigger recognition.
594    pub triggered_properly: usize,
595    /// Trigger recognition rate.
596    pub trigger_recognition_rate: f64,
597    /// Tests with valid recoverable amounts.
598    pub valid_recoverable_amounts: usize,
599    /// Impairment losses recognized.
600    pub impairment_losses: usize,
601    /// Reversals (IFRS only, disallowed for goodwill).
602    pub reversals: usize,
603    /// Invalid reversals (GAAP or goodwill).
604    pub invalid_reversals: usize,
605    /// Framework violations.
606    pub framework_violations: Vec<FrameworkViolation>,
607}
608
609impl ImpairmentEvaluation {
610    /// Create a new evaluation.
611    pub fn new() -> Self {
612        Self {
613            total_tests: 0,
614            triggered_properly: 0,
615            trigger_recognition_rate: 1.0,
616            valid_recoverable_amounts: 0,
617            impairment_losses: 0,
618            reversals: 0,
619            invalid_reversals: 0,
620            framework_violations: Vec::new(),
621        }
622    }
623}
624
625impl Default for ImpairmentEvaluation {
626    fn default() -> Self {
627        Self::new()
628    }
629}
630
631// ============================================================================
632// ISA Compliance Evaluation
633// ============================================================================
634
635/// ISA compliance evaluation.
636#[derive(Debug, Clone, Serialize, Deserialize)]
637pub struct IsaComplianceEvaluation {
638    /// Standards covered.
639    pub standards_covered: HashSet<String>,
640    /// Total requirements mapped.
641    pub total_requirements: usize,
642    /// Requirements addressed.
643    pub requirements_addressed: usize,
644    /// Coverage rate.
645    pub coverage_rate: f64,
646    /// Procedures with ISA mapping.
647    pub procedures_mapped: usize,
648    /// Unmapped procedures.
649    pub procedures_unmapped: usize,
650    /// Critical gaps identified.
651    pub critical_gaps: Vec<String>,
652}
653
654impl IsaComplianceEvaluation {
655    /// Create a new evaluation.
656    pub fn new() -> Self {
657        Self {
658            standards_covered: HashSet::new(),
659            total_requirements: 0,
660            requirements_addressed: 0,
661            coverage_rate: 1.0,
662            procedures_mapped: 0,
663            procedures_unmapped: 0,
664            critical_gaps: Vec::new(),
665        }
666    }
667}
668
669impl Default for IsaComplianceEvaluation {
670    fn default() -> Self {
671        Self::new()
672    }
673}
674
675// ============================================================================
676// SOX Compliance Evaluation
677// ============================================================================
678
679/// SOX compliance evaluation.
680#[derive(Debug, Clone, Serialize, Deserialize)]
681pub struct SoxComplianceEvaluation {
682    /// Section 302 certifications present.
683    pub section_302_certifications: usize,
684    /// Section 404 assessments present.
685    pub section_404_assessments: usize,
686    /// Key controls identified.
687    pub key_controls: usize,
688    /// Key controls tested.
689    pub controls_tested: usize,
690    /// Control coverage (tested/total).
691    pub control_coverage: f64,
692    /// Material weaknesses identified.
693    pub material_weaknesses: usize,
694    /// Significant deficiencies identified.
695    pub significant_deficiencies: usize,
696    /// Deficiency classifications valid.
697    pub valid_classifications: usize,
698}
699
700impl SoxComplianceEvaluation {
701    /// Create a new evaluation.
702    pub fn new() -> Self {
703        Self {
704            section_302_certifications: 0,
705            section_404_assessments: 0,
706            key_controls: 0,
707            controls_tested: 0,
708            control_coverage: 1.0,
709            material_weaknesses: 0,
710            significant_deficiencies: 0,
711            valid_classifications: 0,
712        }
713    }
714}
715
716impl Default for SoxComplianceEvaluation {
717    fn default() -> Self {
718        Self::new()
719    }
720}
721
722// ============================================================================
723// PCAOB Compliance Evaluation
724// ============================================================================
725
726/// PCAOB compliance evaluation.
727#[derive(Debug, Clone, Serialize, Deserialize)]
728pub struct PcaobComplianceEvaluation {
729    /// Standards covered.
730    pub standards_covered: HashSet<String>,
731    /// Coverage rate.
732    pub coverage_rate: f64,
733    /// ICFR opinion present.
734    pub icfr_opinion_present: bool,
735    /// Critical audit matters documented.
736    pub critical_audit_matters: usize,
737}
738
739impl PcaobComplianceEvaluation {
740    /// Create a new evaluation.
741    pub fn new() -> Self {
742        Self {
743            standards_covered: HashSet::new(),
744            coverage_rate: 1.0,
745            icfr_opinion_present: false,
746            critical_audit_matters: 0,
747        }
748    }
749}
750
751impl Default for PcaobComplianceEvaluation {
752    fn default() -> Self {
753        Self::new()
754    }
755}
756
757// ============================================================================
758// Audit Trail Evaluation
759// ============================================================================
760
761/// Audit trail completeness evaluation.
762#[derive(Debug, Clone, Serialize, Deserialize)]
763pub struct AuditTrailEvaluation {
764    /// Total trail items.
765    pub total_items: usize,
766    /// Complete trail items.
767    pub complete_items: usize,
768    /// Completeness score.
769    pub completeness: f64,
770    /// Items with risk assessment linkage.
771    pub risk_linked: usize,
772    /// Items with evidence linkage.
773    pub evidence_linked: usize,
774    /// Items with conclusion.
775    pub concluded: usize,
776    /// Gaps identified.
777    pub gaps: Vec<AuditTrailGap>,
778}
779
780impl AuditTrailEvaluation {
781    /// Create a new evaluation.
782    pub fn new() -> Self {
783        Self {
784            total_items: 0,
785            complete_items: 0,
786            completeness: 1.0,
787            risk_linked: 0,
788            evidence_linked: 0,
789            concluded: 0,
790            gaps: Vec::new(),
791        }
792    }
793}
794
795impl Default for AuditTrailEvaluation {
796    fn default() -> Self {
797        Self::new()
798    }
799}
800
801/// Audit trail gap.
802#[derive(Debug, Clone, Serialize, Deserialize)]
803pub struct AuditTrailGap {
804    /// Trail item ID.
805    pub trail_id: String,
806    /// Gap type.
807    pub gap_type: String,
808    /// Description.
809    pub description: String,
810}
811
812// ============================================================================
813// Framework Violation
814// ============================================================================
815
816/// A violation of a specific standard.
817#[derive(Debug, Clone, Serialize, Deserialize)]
818pub struct FrameworkViolation {
819    /// Standard reference (e.g., "ASC 606-10-25-1").
820    pub standard: String,
821    /// Description of the violation.
822    pub description: String,
823    /// Severity level.
824    pub severity: ViolationSeverity,
825}
826
827/// Violation severity.
828#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
829pub enum ViolationSeverity {
830    /// Informational - minor issue.
831    Info,
832    /// Warning - potential issue.
833    Warning,
834    /// Error - definite violation.
835    Error,
836    /// Critical - material violation.
837    Critical,
838}
839
840// ============================================================================
841// Thresholds
842// ============================================================================
843
844/// Thresholds for standards compliance evaluation.
845#[derive(Debug, Clone, Serialize, Deserialize)]
846pub struct StandardsThresholds {
847    /// Minimum PO allocation compliance.
848    pub min_po_allocation_compliance: f64,
849    /// Minimum revenue timing compliance.
850    pub min_revenue_timing_compliance: f64,
851    /// Minimum lease classification accuracy.
852    pub min_lease_classification_accuracy: f64,
853    /// Minimum ROU asset accuracy.
854    pub min_rou_asset_accuracy: f64,
855    /// Minimum fair value hierarchy compliance.
856    pub min_fair_value_hierarchy_compliance: f64,
857    /// Minimum impairment trigger recognition rate.
858    pub min_impairment_trigger_rate: f64,
859    /// Minimum ISA coverage.
860    pub min_isa_coverage: f64,
861    /// Minimum SOX control coverage.
862    pub min_sox_control_coverage: f64,
863    /// Minimum audit trail completeness.
864    pub min_audit_trail_completeness: f64,
865}
866
867impl Default for StandardsThresholds {
868    fn default() -> Self {
869        Self {
870            min_po_allocation_compliance: 0.95,
871            min_revenue_timing_compliance: 0.95,
872            min_lease_classification_accuracy: 0.90,
873            min_rou_asset_accuracy: 0.95,
874            min_fair_value_hierarchy_compliance: 0.95,
875            min_impairment_trigger_rate: 0.80,
876            min_isa_coverage: 0.90,
877            min_sox_control_coverage: 0.95,
878            min_audit_trail_completeness: 0.90,
879        }
880    }
881}
882
883#[cfg(test)]
884mod tests {
885    use super::*;
886
887    #[test]
888    fn test_standards_compliance_evaluation_new() {
889        let eval = StandardsComplianceEvaluation::new();
890        assert!(eval.passes);
891        assert!(eval.failures.is_empty());
892    }
893
894    #[test]
895    fn test_revenue_contract_validation() {
896        let contract = RevenueContract {
897            contract_id: "C001".to_string(),
898            transaction_price: dec!(10000),
899            performance_obligations: vec![
900                PerformanceObligation {
901                    obligation_id: "PO1".to_string(),
902                    allocated_amount: dec!(6000),
903                    satisfaction_percent: dec!(1.0),
904                    recognized_revenue: dec!(6000),
905                    over_time: false,
906                },
907                PerformanceObligation {
908                    obligation_id: "PO2".to_string(),
909                    allocated_amount: dec!(4000),
910                    satisfaction_percent: dec!(0.5),
911                    recognized_revenue: dec!(2000),
912                    over_time: true,
913                },
914            ],
915            variable_consideration: None,
916            revenue_recognized: dec!(8000),
917            deferred_revenue: dec!(2000),
918        };
919
920        assert!(contract.is_valid());
921        assert!(contract.check_po_allocation());
922        assert!(contract.check_revenue_timing());
923        assert!(contract.check_balance());
924    }
925
926    #[test]
927    fn test_revenue_contract_invalid_po_allocation() {
928        let contract = RevenueContract {
929            contract_id: "C002".to_string(),
930            transaction_price: dec!(10000),
931            performance_obligations: vec![PerformanceObligation {
932                obligation_id: "PO1".to_string(),
933                allocated_amount: dec!(5000), // Only half allocated
934                satisfaction_percent: dec!(1.0),
935                recognized_revenue: dec!(5000),
936                over_time: false,
937            }],
938            variable_consideration: None,
939            revenue_recognized: dec!(5000),
940            deferred_revenue: dec!(5000),
941        };
942
943        assert!(!contract.check_po_allocation());
944    }
945
946    #[test]
947    fn test_lease_us_gaap_classification() {
948        // Finance lease (term >= 75% of useful life)
949        let finance_lease = LeaseEvaluation {
950            lease_id: "L001".to_string(),
951            lease_term_months: 48,
952            asset_useful_life_months: 60,
953            pv_ratio: 0.85,
954            is_finance: true,
955            framework: "us_gaap".to_string(),
956            rou_asset_initial: dec!(50000),
957            lease_liability_initial: dec!(50000),
958            discount_rate: 0.05,
959        };
960        assert!(finance_lease.check_us_gaap_classification());
961
962        // Operating lease
963        let operating_lease = LeaseEvaluation {
964            lease_id: "L002".to_string(),
965            lease_term_months: 24,
966            asset_useful_life_months: 120,
967            pv_ratio: 0.50,
968            is_finance: false,
969            framework: "us_gaap".to_string(),
970            rou_asset_initial: dec!(20000),
971            lease_liability_initial: dec!(20000),
972            discount_rate: 0.05,
973        };
974        assert!(operating_lease.check_us_gaap_classification());
975    }
976
977    #[test]
978    fn test_standards_thresholds_check() {
979        let mut eval = StandardsComplianceEvaluation::new();
980        eval.revenue_recognition = Some(RevenueRecognitionEvaluation {
981            po_allocation_compliance: 0.90, // Below 0.95 threshold
982            timing_compliance: 0.98,
983            ..Default::default()
984        });
985
986        let thresholds = StandardsThresholds::default();
987        eval.check_thresholds(&thresholds);
988
989        assert!(!eval.passes);
990        assert_eq!(eval.failures.len(), 1);
991        assert!(eval.failures[0].contains("PO allocation"));
992    }
993
994    #[test]
995    fn test_lease_accounting_evaluator() {
996        let leases = vec![
997            LeaseEvaluation {
998                lease_id: "L001".to_string(),
999                lease_term_months: 48,
1000                asset_useful_life_months: 60,
1001                pv_ratio: 0.85,
1002                is_finance: true,
1003                framework: "us_gaap".to_string(),
1004                rou_asset_initial: dec!(50000),
1005                lease_liability_initial: dec!(50000),
1006                discount_rate: 0.05,
1007            },
1008            LeaseEvaluation {
1009                lease_id: "L002".to_string(),
1010                lease_term_months: 24,
1011                asset_useful_life_months: 120,
1012                pv_ratio: 0.50,
1013                is_finance: false,
1014                framework: "us_gaap".to_string(),
1015                rou_asset_initial: dec!(20000),
1016                lease_liability_initial: dec!(20000),
1017                discount_rate: 0.05,
1018            },
1019        ];
1020
1021        let eval = LeaseAccountingEvaluator::evaluate(&leases, "us_gaap");
1022
1023        assert_eq!(eval.total_leases, 2);
1024        assert_eq!(eval.finance_leases, 1);
1025        assert_eq!(eval.operating_leases, 1);
1026        assert_eq!(eval.classification_accuracy, 1.0);
1027    }
1028
1029    #[test]
1030    fn test_revenue_recognition_evaluator() {
1031        let contracts = vec![RevenueContract {
1032            contract_id: "C001".to_string(),
1033            transaction_price: dec!(10000),
1034            performance_obligations: vec![PerformanceObligation {
1035                obligation_id: "PO1".to_string(),
1036                allocated_amount: dec!(10000),
1037                satisfaction_percent: dec!(1.0),
1038                recognized_revenue: dec!(10000),
1039                over_time: false,
1040            }],
1041            variable_consideration: None,
1042            revenue_recognized: dec!(10000),
1043            deferred_revenue: dec!(0),
1044        }];
1045
1046        let eval = RevenueRecognitionEvaluator::evaluate(&contracts);
1047
1048        assert_eq!(eval.total_contracts, 1);
1049        assert_eq!(eval.valid_contracts, 1);
1050        assert_eq!(eval.po_allocation_compliance, 1.0);
1051        assert_eq!(eval.timing_compliance, 1.0);
1052    }
1053}