1use super::experiment::ExperimentSpec;
25use super::model_card::EquationModelCard;
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct EddViolation {
30 pub code: String,
32 pub message: String,
34 pub severity: ViolationSeverity,
36 pub context: Option<String>,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
42pub enum ViolationSeverity {
43 Info,
45 Warning,
47 Error,
49 Critical,
51}
52
53impl EddViolation {
54 #[must_use]
56 pub fn new(code: &str, message: &str, severity: ViolationSeverity) -> Self {
57 Self {
58 code: code.to_string(),
59 message: message.to_string(),
60 severity,
61 context: None,
62 }
63 }
64
65 #[must_use]
67 pub fn with_context(mut self, context: &str) -> Self {
68 self.context = Some(context.to_string());
69 self
70 }
71}
72
73pub type EddResult<T> = Result<T, EddViolation>;
75
76#[derive(Debug, Default)]
78pub struct EddValidator {
79 violations: Vec<EddViolation>,
81 #[allow(dead_code)]
83 jidoka_mode: bool,
84}
85
86impl EddValidator {
87 #[must_use]
89 pub fn new() -> Self {
90 Self {
91 violations: Vec::new(),
92 jidoka_mode: true,
93 }
94 }
95
96 #[must_use]
98 pub fn lenient() -> Self {
99 Self {
100 violations: Vec::new(),
101 jidoka_mode: false,
102 }
103 }
104
105 pub fn clear(&mut self) {
107 self.violations.clear();
108 }
109
110 #[must_use]
112 pub fn violations(&self) -> &[EddViolation] {
113 &self.violations
114 }
115
116 #[must_use]
118 pub fn has_critical_violations(&self) -> bool {
119 self.violations
120 .iter()
121 .any(|v| v.severity == ViolationSeverity::Critical)
122 }
123
124 #[must_use]
126 pub fn has_errors(&self) -> bool {
127 self.violations
128 .iter()
129 .any(|v| v.severity >= ViolationSeverity::Error)
130 }
131
132 pub fn validate_simulation_has_emc(&self, emc: Option<&EquationModelCard>) -> EddResult<()> {
143 match emc {
144 Some(_) => Ok(()),
145 None => Err(EddViolation::new(
146 "EDD-01",
147 "Simulation must have an Equation Model Card (Pillar 1: Prove It)",
148 ViolationSeverity::Critical,
149 )),
150 }
151 }
152
153 pub fn validate_emc_has_equation(&self, emc: &EquationModelCard) -> EddResult<()> {
160 if emc.equation.is_empty() {
161 Err(EddViolation::new(
162 "EDD-02",
163 "EMC must have a governing equation in LaTeX format",
164 ViolationSeverity::Critical,
165 ))
166 } else {
167 Ok(())
168 }
169 }
170
171 pub fn validate_emc_has_citation(&self, emc: &EquationModelCard) -> EddResult<()> {
178 if emc.citation.authors.is_empty() {
179 Err(EddViolation::new(
180 "EDD-03",
181 "EMC must have a peer-reviewed citation",
182 ViolationSeverity::Critical,
183 ))
184 } else {
185 Ok(())
186 }
187 }
188
189 pub fn validate_emc_has_tests(&self, emc: &EquationModelCard) -> EddResult<()> {
196 if emc.verification_tests.is_empty() {
197 Err(EddViolation::new(
198 "EDD-04",
199 "EMC must have at least one verification test (Pillar 2: Fail It)",
200 ViolationSeverity::Critical,
201 ))
202 } else {
203 Ok(())
204 }
205 }
206
207 pub fn validate_emc(&mut self, emc: &EquationModelCard) -> Result<(), Vec<EddViolation>> {
212 let mut violations = Vec::new();
213
214 if let Err(v) = self.validate_emc_has_equation(emc) {
215 violations.push(v);
216 }
217
218 if let Err(v) = self.validate_emc_has_citation(emc) {
219 violations.push(v);
220 }
221
222 if let Err(v) = self.validate_emc_has_tests(emc) {
223 violations.push(v);
224 }
225
226 if violations.is_empty() {
227 Ok(())
228 } else {
229 self.violations.extend(violations.clone());
230 Err(violations)
231 }
232 }
233
234 pub fn validate_seed_specified(&self, seed: Option<u64>) -> EddResult<()> {
245 match seed {
246 Some(_) => Ok(()),
247 None => Err(EddViolation::new(
248 "EDD-05",
249 "Experiment must have an explicit seed (Pillar 3: Seed It)",
250 ViolationSeverity::Critical,
251 )),
252 }
253 }
254
255 pub fn validate_has_falsification_criteria(&self, spec: &ExperimentSpec) -> EddResult<()> {
266 if spec.falsification_criteria().is_empty() {
267 Err(EddViolation::new(
269 "EDD-06",
270 "Experiment should have falsification criteria (Pillar 4: Falsify It)",
271 ViolationSeverity::Warning,
272 ))
273 } else {
274 Ok(())
275 }
276 }
277
278 pub fn validate_experiment(&mut self, spec: &ExperimentSpec) -> Result<(), Vec<EddViolation>> {
287 let mut violations = Vec::new();
288
289 if let Err(v) = self.validate_seed_specified(Some(spec.seed())) {
291 violations.push(v);
292 }
293
294 if let Err(v) = self.validate_has_falsification_criteria(spec) {
296 violations.push(v);
297 }
298
299 if let Err(errs) = spec.validate() {
301 for err in errs {
302 violations.push(EddViolation::new("EDD-00", &err, ViolationSeverity::Error));
303 }
304 }
305
306 if violations
307 .iter()
308 .any(|v| v.severity >= ViolationSeverity::Error)
309 {
310 self.violations.extend(violations.clone());
311 Err(violations)
312 } else {
313 self.violations.extend(violations);
315 Ok(())
316 }
317 }
318
319 pub fn validate_verification_tests<F>(
330 &mut self,
331 emc: &EquationModelCard,
332 evaluator: F,
333 ) -> Result<(), Vec<EddViolation>>
334 where
335 F: Fn(&std::collections::HashMap<String, f64>) -> f64,
336 {
337 let results = emc.run_verification_tests(evaluator);
338 let failures: Vec<EddViolation> = results
339 .into_iter()
340 .filter(|(_, passed, _)| !passed)
341 .map(|(name, _, msg)| {
342 EddViolation::new(
343 "EDD-07",
344 &format!("Verification test failed: {name}"),
345 ViolationSeverity::Critical,
346 )
347 .with_context(&msg)
348 })
349 .collect();
350
351 if failures.is_empty() {
352 Ok(())
353 } else {
354 self.violations.extend(failures.clone());
355 Err(failures)
356 }
357 }
358
359 pub fn validate_conservation_law(
381 &self,
382 quantity_name: &str,
383 initial_value: f64,
384 current_value: f64,
385 tolerance: f64,
386 ) -> EddResult<()> {
387 let relative_drift = if initial_value.abs() > f64::EPSILON {
388 (current_value - initial_value).abs() / initial_value.abs()
389 } else {
390 (current_value - initial_value).abs()
391 };
392
393 if relative_drift > tolerance {
394 Err(EddViolation::new(
395 "EDD-08",
396 &format!("Conservation law violated: {quantity_name} drifted beyond tolerance"),
397 ViolationSeverity::Critical,
398 ).with_context(&format!(
399 "initial={initial_value:.6e}, current={current_value:.6e}, drift={relative_drift:.6e}, tolerance={tolerance:.6e}"
400 )))
401 } else {
402 Ok(())
403 }
404 }
405
406 pub fn validate_cross_platform_reproducibility(
429 &self,
430 platform_a: &str,
431 platform_b: &str,
432 result_a: f64,
433 result_b: f64,
434 tolerance: f64,
435 ) -> EddResult<()> {
436 let diff = (result_a - result_b).abs();
437
438 if diff > tolerance {
439 Err(EddViolation::new(
440 "EDD-09",
441 &format!("Cross-platform reproducibility failed: {platform_a} vs {platform_b}"),
442 ViolationSeverity::Error,
443 )
444 .with_context(&format!(
445 "{platform_a}={result_a:.15e}, {platform_b}={result_b:.15e}, diff={diff:.15e}"
446 )))
447 } else {
448 Ok(())
449 }
450 }
451
452 pub fn validate_tdd_compliance(
474 &self,
475 implementation_name: &str,
476 has_test_file: bool,
477 test_count: usize,
478 ) -> EddResult<()> {
479 if !has_test_file {
480 return Err(EddViolation::new(
481 "EDD-10",
482 &format!("Implementation '{implementation_name}' has no test file"),
483 ViolationSeverity::Critical,
484 )
485 .with_context("EDD requires TDD: write failing tests BEFORE implementation"));
486 }
487
488 if test_count == 0 {
489 return Err(EddViolation::new(
490 "EDD-10",
491 &format!("Implementation '{implementation_name}' has no tests"),
492 ViolationSeverity::Critical,
493 )
494 .with_context("Every implementation must have at least one test"));
495 }
496
497 Ok(())
498 }
499
500 pub fn validate_yaml_only_config(
520 has_yaml_config: bool,
521 hardcoded_params: &[String],
522 ) -> Result<(), EddViolation> {
523 if !has_yaml_config {
524 return Err(EddViolation::new(
525 "EDD-13",
526 "Simulation requires YAML configuration",
527 ViolationSeverity::Critical,
528 )
529 .with_context("Three Pillars: Pillar 2 requires YAML-only configuration"));
530 }
531
532 if !hardcoded_params.is_empty() {
533 return Err(EddViolation::new(
534 "EDD-13",
535 &format!(
536 "Hardcoded parameters detected: {}",
537 hardcoded_params.join(", ")
538 ),
539 ViolationSeverity::Critical,
540 )
541 .with_context("All parameters must come from YAML configuration"));
542 }
543
544 Ok(())
545 }
546
547 pub fn validate_probar_tui(
562 probar_tests_passed: bool,
563 test_count: usize,
564 ) -> Result<(), EddViolation> {
565 if test_count == 0 {
566 return Err(EddViolation::new(
567 "EDD-14",
568 "No Probar TUI tests found",
569 ViolationSeverity::Critical,
570 )
571 .with_context("Three Pillars: Pillar 3 requires Probar TUI verification"));
572 }
573
574 if !probar_tests_passed {
575 return Err(EddViolation::new(
576 "EDD-14",
577 "Probar TUI tests failed",
578 ViolationSeverity::Critical,
579 )
580 .with_context("All Probar TUI tests must pass before release"));
581 }
582
583 Ok(())
584 }
585
586 pub fn validate_probar_wasm(
601 probar_wasm_passed: bool,
602 test_count: usize,
603 ) -> Result<(), EddViolation> {
604 if test_count == 0 {
605 return Err(EddViolation::new(
606 "EDD-15",
607 "No Probar WASM tests found",
608 ViolationSeverity::Critical,
609 )
610 .with_context("Three Pillars: Pillar 3 requires Probar WASM verification"));
611 }
612
613 if !probar_wasm_passed {
614 return Err(EddViolation::new(
615 "EDD-15",
616 "Probar WASM tests failed",
617 ViolationSeverity::Critical,
618 )
619 .with_context("All Probar WASM tests must pass before release"));
620 }
621
622 Ok(())
623 }
624
625 #[must_use]
644 #[allow(clippy::fn_params_excessive_bools)]
645 pub fn validate_three_pillars(
646 z3_proofs_passed: bool,
647 has_yaml_config: bool,
648 seed_specified: bool,
649 probar_tui_passed: bool,
650 probar_tui_test_count: usize,
651 probar_wasm_passed: bool,
652 probar_wasm_test_count: usize,
653 ) -> Vec<EddViolation> {
654 let mut violations = Vec::new();
655
656 if !z3_proofs_passed {
658 violations.push(
659 EddViolation::new(
660 "EDD-11",
661 "Z3 equation proofs did not pass",
662 ViolationSeverity::Critical,
663 )
664 .with_context("Pillar 1: All equations must be provable with Z3"),
665 );
666 }
667
668 if !has_yaml_config {
670 violations.push(
671 EddViolation::new(
672 "EDD-13",
673 "No YAML configuration provided",
674 ViolationSeverity::Critical,
675 )
676 .with_context("Pillar 2: All configuration must be YAML-based"),
677 );
678 }
679
680 if !seed_specified {
681 violations.push(
682 EddViolation::new(
683 "EDD-05",
684 "No seed specified in configuration",
685 ViolationSeverity::Critical,
686 )
687 .with_context("Pillar 2: Seed must be explicitly specified in YAML"),
688 );
689 }
690
691 if let Err(e) = Self::validate_probar_tui(probar_tui_passed, probar_tui_test_count) {
693 violations.push(e);
694 }
695
696 if let Err(e) = Self::validate_probar_wasm(probar_wasm_passed, probar_wasm_test_count) {
697 violations.push(e);
698 }
699
700 violations
701 }
702}
703
704#[derive(Debug)]
706pub struct EddComplianceSummary {
707 pub total_violations: usize,
709 pub critical_count: usize,
711 pub error_count: usize,
713 pub warning_count: usize,
715 pub info_count: usize,
717 pub compliant: bool,
719}
720
721#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
727pub enum TpsGrade {
728 ToyotaStandard,
730 KaizenRequired,
732 AndonWarning,
734 StopTheLine,
736}
737
738impl TpsGrade {
739 #[must_use]
741 pub fn from_score(score: f64) -> Self {
742 if score >= 0.95 {
743 Self::ToyotaStandard
744 } else if score >= 0.85 {
745 Self::KaizenRequired
746 } else if score >= 0.70 {
747 Self::AndonWarning
748 } else {
749 Self::StopTheLine
750 }
751 }
752
753 #[must_use]
757 pub fn from_violations(violations: &[EddViolation], total_checks: usize) -> Self {
758 if violations
760 .iter()
761 .any(|v| v.severity == ViolationSeverity::Critical)
762 {
763 return Self::StopTheLine;
764 }
765
766 let error_count = violations
768 .iter()
769 .filter(|v| v.severity >= ViolationSeverity::Error)
770 .count();
771
772 if total_checks == 0 {
773 return Self::ToyotaStandard;
774 }
775
776 let score = 1.0 - (error_count as f64 / total_checks as f64);
777 Self::from_score(score)
778 }
779
780 #[must_use]
782 pub const fn decision(&self) -> &'static str {
783 match self {
784 Self::ToyotaStandard => "Release OK",
785 Self::KaizenRequired => "Beta with documented limitations",
786 Self::AndonWarning => "Significant revision required",
787 Self::StopTheLine => "Block release",
788 }
789 }
790
791 #[must_use]
793 pub const fn score_range(&self) -> &'static str {
794 match self {
795 Self::ToyotaStandard => "95-100%",
796 Self::KaizenRequired => "85-94%",
797 Self::AndonWarning => "70-84%",
798 Self::StopTheLine => "<70% or Critical",
799 }
800 }
801}
802
803impl std::fmt::Display for TpsGrade {
804 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
805 let name = match self {
806 Self::ToyotaStandard => "Toyota Standard",
807 Self::KaizenRequired => "Kaizen Required",
808 Self::AndonWarning => "Andon Warning",
809 Self::StopTheLine => "STOP THE LINE",
810 };
811 write!(f, "{name}")
812 }
813}
814
815#[derive(Debug, Clone)]
821pub struct ConvergenceAnalysis {
822 pub order: f64,
824 pub expected_order: f64,
826 pub order_matches: bool,
828 pub tolerance: f64,
830 pub extrapolated_value: f64,
832 pub error_estimates: Vec<f64>,
834}
835
836#[must_use]
856pub fn richardson_extrapolation(
857 values: &[f64],
858 refinement_ratio: f64,
859 expected_order: f64,
860 tolerance: f64,
861) -> ConvergenceAnalysis {
862 assert!(
863 values.len() >= 3,
864 "Richardson extrapolation requires at least 3 values"
865 );
866
867 let n = values.len();
868 let r = refinement_ratio;
869
870 let mut error_estimates = Vec::with_capacity(n - 1);
872 for i in 0..n - 1 {
873 error_estimates.push((values[i] - values[i + 1]).abs());
874 }
875
876 let e1 = (values[n - 3] - values[n - 2]).abs();
879 let e2 = (values[n - 2] - values[n - 1]).abs();
880
881 let order = if e2 > f64::EPSILON && e1 > f64::EPSILON {
882 (e1 / e2).ln() / r.ln()
883 } else {
884 expected_order };
886
887 let extrapolated_value = if (r.powf(order) - 1.0).abs() > f64::EPSILON {
890 values[n - 1] + (values[n - 1] - values[n - 2]) / (r.powf(order) - 1.0)
891 } else {
892 values[n - 1]
893 };
894
895 let order_matches = (order - expected_order).abs() <= tolerance;
896
897 ConvergenceAnalysis {
898 order,
899 expected_order,
900 order_matches,
901 tolerance,
902 extrapolated_value,
903 error_estimates,
904 }
905}
906
907impl EddComplianceSummary {
908 #[must_use]
910 pub fn from_violations(violations: &[EddViolation]) -> Self {
911 let critical_count = violations
912 .iter()
913 .filter(|v| v.severity == ViolationSeverity::Critical)
914 .count();
915 let error_count = violations
916 .iter()
917 .filter(|v| v.severity == ViolationSeverity::Error)
918 .count();
919 let warning_count = violations
920 .iter()
921 .filter(|v| v.severity == ViolationSeverity::Warning)
922 .count();
923 let info_count = violations
924 .iter()
925 .filter(|v| v.severity == ViolationSeverity::Info)
926 .count();
927
928 Self {
929 total_violations: violations.len(),
930 critical_count,
931 error_count,
932 warning_count,
933 info_count,
934 compliant: critical_count == 0 && error_count == 0,
935 }
936 }
937}
938
939#[cfg(test)]
940mod tests {
941 use super::*;
942 use crate::edd::equation::Citation;
943 use crate::edd::model_card::EmcBuilder;
944
945 #[test]
946 fn test_validator_new() {
947 let validator = EddValidator::new();
948 assert!(validator.violations().is_empty());
949 }
950
951 #[test]
952 fn test_validate_simulation_has_emc_fails() {
953 let validator = EddValidator::new();
954 let result = validator.validate_simulation_has_emc(None);
955 assert!(result.is_err());
956 let err = result.err().unwrap();
957 assert_eq!(err.code, "EDD-01");
958 assert_eq!(err.severity, ViolationSeverity::Critical);
959 }
960
961 #[test]
962 fn test_validate_simulation_has_emc_passes() {
963 let validator = EddValidator::new();
964 let emc = EmcBuilder::new()
965 .name("Test")
966 .equation("x = y")
967 .citation(Citation::new(&["Test"], "Test", 2024))
968 .add_verification_test("test", 1.0, 0.1)
969 .build()
970 .ok()
971 .unwrap();
972
973 let result = validator.validate_simulation_has_emc(Some(&emc));
974 assert!(result.is_ok());
975 }
976
977 #[test]
978 fn test_validate_seed_specified_fails() {
979 let validator = EddValidator::new();
980 let result = validator.validate_seed_specified(None);
981 assert!(result.is_err());
982 let err = result.err().unwrap();
983 assert_eq!(err.code, "EDD-05");
984 }
985
986 #[test]
987 fn test_validate_seed_specified_passes() {
988 let validator = EddValidator::new();
989 let result = validator.validate_seed_specified(Some(42));
990 assert!(result.is_ok());
991 }
992
993 #[test]
994 fn test_compliance_summary() {
995 let violations = vec![
996 EddViolation::new("EDD-01", "test", ViolationSeverity::Critical),
997 EddViolation::new("EDD-05", "test", ViolationSeverity::Error),
998 EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
999 ];
1000
1001 let summary = EddComplianceSummary::from_violations(&violations);
1002 assert_eq!(summary.total_violations, 3);
1003 assert_eq!(summary.critical_count, 1);
1004 assert_eq!(summary.error_count, 1);
1005 assert_eq!(summary.warning_count, 1);
1006 assert!(!summary.compliant);
1007 }
1008
1009 #[test]
1010 fn test_compliance_summary_compliant() {
1011 let violations = vec![
1012 EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
1013 EddViolation::new("EDD-00", "test", ViolationSeverity::Info),
1014 ];
1015
1016 let summary = EddComplianceSummary::from_violations(&violations);
1017 assert!(summary.compliant);
1018 }
1019
1020 #[test]
1021 fn test_violation_with_context() {
1022 let violation = EddViolation::new("EDD-07", "Test failed", ViolationSeverity::Critical)
1023 .with_context("Expected 10, got 15");
1024
1025 assert!(violation.context.is_some());
1026 assert!(violation.context.unwrap().contains("Expected 10"));
1027 }
1028
1029 #[test]
1030 fn test_validator_collects_violations() {
1031 let mut validator = EddValidator::lenient();
1032
1033 let emc = EquationModelCard {
1035 name: "Test".to_string(),
1036 version: "1.0".to_string(),
1037 equation: String::new(), class: crate::edd::equation::EquationClass::Queueing,
1039 citation: Citation::new(&[], "Test", 2024), references: vec![],
1041 variables: vec![],
1042 verification_tests: vec![], domain_constraints: vec![],
1044 falsification_criteria: vec![],
1045 implementation_notes: vec![],
1046 description: String::new(),
1047 lineage: vec![],
1048 };
1049
1050 let result = validator.validate_emc(&emc);
1051 assert!(result.is_err());
1052
1053 assert!(validator.violations().len() >= 3);
1055 }
1056
1057 #[test]
1058 fn test_has_critical_violations() {
1059 let mut validator = EddValidator::new();
1060 validator.violations.push(EddViolation::new(
1061 "EDD-01",
1062 "test",
1063 ViolationSeverity::Critical,
1064 ));
1065
1066 assert!(validator.has_critical_violations());
1067 assert!(validator.has_errors());
1068 }
1069
1070 #[test]
1071 fn test_clear_violations() {
1072 let mut validator = EddValidator::new();
1073 validator.violations.push(EddViolation::new(
1074 "EDD-01",
1075 "test",
1076 ViolationSeverity::Critical,
1077 ));
1078
1079 validator.clear();
1080 assert!(validator.violations().is_empty());
1081 }
1082
1083 #[test]
1088 fn test_validate_conservation_law_passes() {
1089 let validator = EddValidator::new();
1090 let result = validator.validate_conservation_law("energy", 100.0, 100.001, 1e-4);
1092 assert!(result.is_ok());
1093 }
1094
1095 #[test]
1096 fn test_validate_conservation_law_fails() {
1097 let validator = EddValidator::new();
1098 let result = validator.validate_conservation_law("energy", 100.0, 110.0, 1e-4);
1100 assert!(result.is_err());
1101 let err = result.err().unwrap();
1102 assert_eq!(err.code, "EDD-08");
1103 assert_eq!(err.severity, ViolationSeverity::Critical);
1104 assert!(err.message.contains("energy"));
1105 }
1106
1107 #[test]
1108 fn test_validate_conservation_law_zero_initial() {
1109 let validator = EddValidator::new();
1110 let result = validator.validate_conservation_law("momentum", 0.0, 0.0001, 1e-4);
1112 assert!(result.is_ok());
1113
1114 let result_fail = validator.validate_conservation_law("momentum", 0.0, 1.0, 1e-4);
1115 assert!(result_fail.is_err());
1116 }
1117
1118 #[test]
1123 fn test_validate_cross_platform_reproducibility_passes() {
1124 let validator = EddValidator::new();
1125 let result = validator.validate_cross_platform_reproducibility(
1126 "x86_64-linux",
1127 "aarch64-darwin",
1128 1.234567890123456,
1129 1.234567890123456,
1130 0.0,
1131 );
1132 assert!(result.is_ok());
1133 }
1134
1135 #[test]
1136 fn test_validate_cross_platform_reproducibility_fails() {
1137 let validator = EddValidator::new();
1138 let result = validator.validate_cross_platform_reproducibility(
1139 "x86_64-linux",
1140 "aarch64-darwin",
1141 1.234567890123456,
1142 1.234567890123999,
1143 1e-15,
1144 );
1145 assert!(result.is_err());
1146 let err = result.err().unwrap();
1147 assert_eq!(err.code, "EDD-09");
1148 assert_eq!(err.severity, ViolationSeverity::Error);
1149 assert!(err.context.is_some());
1150 }
1151
1152 #[test]
1153 fn test_validate_cross_platform_with_tolerance() {
1154 let validator = EddValidator::new();
1155 let result = validator.validate_cross_platform_reproducibility(
1157 "x86_64-linux",
1158 "wasm32",
1159 1.0000000001,
1160 1.0000000002,
1161 1e-9,
1162 );
1163 assert!(result.is_ok());
1164 }
1165
1166 #[test]
1171 fn test_validate_tdd_compliance_passes() {
1172 let validator = EddValidator::new();
1173 let result = validator.validate_tdd_compliance("harmonic_oscillator", true, 5);
1174 assert!(result.is_ok());
1175 }
1176
1177 #[test]
1178 fn test_validate_tdd_compliance_no_test_file() {
1179 let validator = EddValidator::new();
1180 let result = validator.validate_tdd_compliance("new_simulation", false, 0);
1181 assert!(result.is_err());
1182 let err = result.err().unwrap();
1183 assert_eq!(err.code, "EDD-10");
1184 assert!(err.message.contains("no test file"));
1185 }
1186
1187 #[test]
1188 fn test_validate_tdd_compliance_no_tests() {
1189 let validator = EddValidator::new();
1190 let result = validator.validate_tdd_compliance("empty_simulation", true, 0);
1191 assert!(result.is_err());
1192 let err = result.err().unwrap();
1193 assert_eq!(err.code, "EDD-10");
1194 assert!(err.message.contains("no tests"));
1195 }
1196
1197 #[test]
1202 fn test_tps_grade_from_score_toyota_standard() {
1203 assert_eq!(TpsGrade::from_score(1.0), TpsGrade::ToyotaStandard);
1204 assert_eq!(TpsGrade::from_score(0.95), TpsGrade::ToyotaStandard);
1205 assert_eq!(TpsGrade::from_score(0.99), TpsGrade::ToyotaStandard);
1206 }
1207
1208 #[test]
1209 fn test_tps_grade_from_score_kaizen_required() {
1210 assert_eq!(TpsGrade::from_score(0.94), TpsGrade::KaizenRequired);
1211 assert_eq!(TpsGrade::from_score(0.85), TpsGrade::KaizenRequired);
1212 assert_eq!(TpsGrade::from_score(0.90), TpsGrade::KaizenRequired);
1213 }
1214
1215 #[test]
1216 fn test_tps_grade_from_score_andon_warning() {
1217 assert_eq!(TpsGrade::from_score(0.84), TpsGrade::AndonWarning);
1218 assert_eq!(TpsGrade::from_score(0.70), TpsGrade::AndonWarning);
1219 assert_eq!(TpsGrade::from_score(0.75), TpsGrade::AndonWarning);
1220 }
1221
1222 #[test]
1223 fn test_tps_grade_from_score_stop_the_line() {
1224 assert_eq!(TpsGrade::from_score(0.69), TpsGrade::StopTheLine);
1225 assert_eq!(TpsGrade::from_score(0.0), TpsGrade::StopTheLine);
1226 assert_eq!(TpsGrade::from_score(0.50), TpsGrade::StopTheLine);
1227 }
1228
1229 #[test]
1230 fn test_tps_grade_from_violations_critical_always_stops() {
1231 let violations = vec![EddViolation::new(
1232 "EDD-01",
1233 "test",
1234 ViolationSeverity::Critical,
1235 )];
1236 assert_eq!(
1238 TpsGrade::from_violations(&violations, 100),
1239 TpsGrade::StopTheLine
1240 );
1241 }
1242
1243 #[test]
1244 fn test_tps_grade_from_violations_no_violations() {
1245 let violations: Vec<EddViolation> = vec![];
1246 assert_eq!(
1247 TpsGrade::from_violations(&violations, 10),
1248 TpsGrade::ToyotaStandard
1249 );
1250 }
1251
1252 #[test]
1253 fn test_tps_grade_from_violations_warnings_ignored() {
1254 let violations = vec![
1255 EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
1256 EddViolation::new("EDD-06", "test", ViolationSeverity::Warning),
1257 ];
1258 assert_eq!(
1260 TpsGrade::from_violations(&violations, 10),
1261 TpsGrade::ToyotaStandard
1262 );
1263 }
1264
1265 #[test]
1266 fn test_tps_grade_decision_text() {
1267 assert_eq!(TpsGrade::ToyotaStandard.decision(), "Release OK");
1268 assert_eq!(
1269 TpsGrade::KaizenRequired.decision(),
1270 "Beta with documented limitations"
1271 );
1272 assert_eq!(
1273 TpsGrade::AndonWarning.decision(),
1274 "Significant revision required"
1275 );
1276 assert_eq!(TpsGrade::StopTheLine.decision(), "Block release");
1277 }
1278
1279 #[test]
1280 fn test_tps_grade_display() {
1281 assert_eq!(format!("{}", TpsGrade::ToyotaStandard), "Toyota Standard");
1282 assert_eq!(format!("{}", TpsGrade::StopTheLine), "STOP THE LINE");
1283 }
1284
1285 #[test]
1290 fn test_validate_yaml_only_config_passes() {
1291 let result = EddValidator::validate_yaml_only_config(true, &[]);
1292 assert!(result.is_ok());
1293 }
1294
1295 #[test]
1296 fn test_validate_yaml_only_config_no_yaml() {
1297 let result = EddValidator::validate_yaml_only_config(false, &[]);
1298 assert!(result.is_err());
1299 let err = result.err().unwrap();
1300 assert_eq!(err.code, "EDD-13");
1301 assert_eq!(err.severity, ViolationSeverity::Critical);
1302 }
1303
1304 #[test]
1305 fn test_validate_yaml_only_config_hardcoded_params() {
1306 let hardcoded = vec!["omega".to_string(), "amplitude".to_string()];
1307 let result = EddValidator::validate_yaml_only_config(true, &hardcoded);
1308 assert!(result.is_err());
1309 let err = result.err().unwrap();
1310 assert_eq!(err.code, "EDD-13");
1311 assert!(err.message.contains("omega"));
1312 assert!(err.message.contains("amplitude"));
1313 }
1314
1315 #[test]
1320 fn test_validate_probar_tui_passes() {
1321 let result = EddValidator::validate_probar_tui(true, 5);
1322 assert!(result.is_ok());
1323 }
1324
1325 #[test]
1326 fn test_validate_probar_tui_no_tests() {
1327 let result = EddValidator::validate_probar_tui(true, 0);
1328 assert!(result.is_err());
1329 let err = result.err().unwrap();
1330 assert_eq!(err.code, "EDD-14");
1331 assert_eq!(err.severity, ViolationSeverity::Critical);
1332 }
1333
1334 #[test]
1335 fn test_validate_probar_tui_failed() {
1336 let result = EddValidator::validate_probar_tui(false, 5);
1337 assert!(result.is_err());
1338 let err = result.err().unwrap();
1339 assert_eq!(err.code, "EDD-14");
1340 assert!(err.message.contains("failed"));
1341 }
1342
1343 #[test]
1348 fn test_validate_probar_wasm_passes() {
1349 let result = EddValidator::validate_probar_wasm(true, 3);
1350 assert!(result.is_ok());
1351 }
1352
1353 #[test]
1354 fn test_validate_probar_wasm_no_tests() {
1355 let result = EddValidator::validate_probar_wasm(true, 0);
1356 assert!(result.is_err());
1357 let err = result.err().unwrap();
1358 assert_eq!(err.code, "EDD-15");
1359 assert_eq!(err.severity, ViolationSeverity::Critical);
1360 }
1361
1362 #[test]
1363 fn test_validate_probar_wasm_failed() {
1364 let result = EddValidator::validate_probar_wasm(false, 3);
1365 assert!(result.is_err());
1366 let err = result.err().unwrap();
1367 assert_eq!(err.code, "EDD-15");
1368 assert!(err.message.contains("failed"));
1369 }
1370
1371 #[test]
1376 fn test_validate_three_pillars_all_pass() {
1377 let violations = EddValidator::validate_three_pillars(
1378 true, true, true, true, 5, true, 3, );
1386 assert!(violations.is_empty(), "All pillars should pass");
1387 }
1388
1389 #[test]
1390 fn test_validate_three_pillars_z3_fails() {
1391 let violations = EddValidator::validate_three_pillars(
1392 false, true, true, true, 5, true, 3,
1394 );
1395 assert_eq!(violations.len(), 1);
1396 assert_eq!(violations[0].code, "EDD-11");
1397 }
1398
1399 #[test]
1400 fn test_validate_three_pillars_yaml_fails() {
1401 let violations = EddValidator::validate_three_pillars(
1402 true, false, true, true, 5, true, 3,
1404 );
1405 assert_eq!(violations.len(), 1);
1406 assert_eq!(violations[0].code, "EDD-13");
1407 }
1408
1409 #[test]
1410 fn test_validate_three_pillars_seed_missing() {
1411 let violations = EddValidator::validate_three_pillars(
1412 true, true, false, true, 5, true, 3,
1414 );
1415 assert_eq!(violations.len(), 1);
1416 assert_eq!(violations[0].code, "EDD-05");
1417 }
1418
1419 #[test]
1420 fn test_validate_three_pillars_probar_fails() {
1421 let violations = EddValidator::validate_three_pillars(
1422 true, true, true, false, 5, false, 3,
1425 );
1426 assert_eq!(violations.len(), 2);
1427 assert!(violations.iter().any(|v| v.code == "EDD-14"));
1428 assert!(violations.iter().any(|v| v.code == "EDD-15"));
1429 }
1430
1431 #[test]
1432 fn test_validate_three_pillars_multiple_failures() {
1433 let violations = EddValidator::validate_three_pillars(
1434 false, false, false, false, 0, false, 0, );
1442 assert!(
1444 violations.len() >= 4,
1445 "Expected multiple violations: {:?}",
1446 violations
1447 );
1448 }
1449
1450 #[test]
1455 fn test_richardson_extrapolation_second_order() {
1456 let values = vec![
1460 2.0, 1.25, 1.0625, ];
1464
1465 let result = richardson_extrapolation(&values, 2.0, 2.0, 0.1);
1466
1467 assert!(
1469 (result.order - 2.0).abs() < 0.1,
1470 "Expected order ~2.0, got {}",
1471 result.order
1472 );
1473 assert!(result.order_matches);
1474
1475 assert!(
1477 (result.extrapolated_value - 1.0).abs() < 0.1,
1478 "Expected extrapolated ~1.0, got {}",
1479 result.extrapolated_value
1480 );
1481 }
1482
1483 #[test]
1484 fn test_richardson_extrapolation_first_order() {
1485 let values = vec![
1489 1.0, 0.5, 0.25, 0.125, ];
1494
1495 let result = richardson_extrapolation(&values, 2.0, 1.0, 0.1);
1496
1497 assert!(
1499 (result.order - 1.0).abs() < 0.1,
1500 "Expected order ~1.0, got {}",
1501 result.order
1502 );
1503 assert!(result.order_matches);
1504 }
1505
1506 #[test]
1507 fn test_richardson_extrapolation_fourth_order() {
1508 let values = vec![
1511 1.0 + 1.0, 1.0 + 0.0625, 1.0 + 0.00390625, 1.0 + 0.000244140625, ];
1516
1517 let result = richardson_extrapolation(&values, 2.0, 4.0, 0.2);
1518
1519 assert!(
1521 (result.order - 4.0).abs() < 0.3,
1522 "Expected order ~4.0, got {}",
1523 result.order
1524 );
1525 }
1526
1527 #[test]
1528 fn test_richardson_extrapolation_error_estimates() {
1529 let values = vec![2.0, 1.25, 1.0625];
1530 let result = richardson_extrapolation(&values, 2.0, 2.0, 0.1);
1531
1532 assert_eq!(result.error_estimates.len(), 2);
1534
1535 assert!(
1537 result.error_estimates[0] > result.error_estimates[1],
1538 "Errors should decrease: {:?}",
1539 result.error_estimates
1540 );
1541 }
1542
1543 #[test]
1544 #[should_panic(expected = "requires at least 3 values")]
1545 fn test_richardson_extrapolation_requires_minimum_values() {
1546 let values = vec![1.0, 0.5];
1547 let _ = richardson_extrapolation(&values, 2.0, 2.0, 0.1);
1548 }
1549
1550 #[test]
1551 fn test_richardson_extrapolation_tolerance() {
1552 let values = vec![2.0, 1.25, 1.0625];
1553
1554 let result_tight = richardson_extrapolation(&values, 2.0, 2.5, 0.01);
1556 assert!(!result_tight.order_matches);
1557
1558 let result_loose = richardson_extrapolation(&values, 2.0, 2.5, 1.0);
1560 assert!(result_loose.order_matches);
1561 }
1562}