1use serde::{Deserialize, Serialize};
42use std::collections::HashMap;
43use std::time::{Duration, Instant};
44use thiserror::Error;
45use tracing::{debug, info, warn};
46
47#[derive(Error, Debug)]
49pub enum CsfError {
50 #[error("Validation failed: {criterion} - {message}")]
52 ValidationFailed {
53 criterion: String,
55 message: String,
57 },
58
59 #[error("Performance threshold exceeded: {metric} = {actual:.2} (threshold: {threshold:.2})")]
61 PerformanceThresholdExceeded {
62 metric: String,
64 actual: f64,
66 threshold: f64,
68 },
69
70 #[error("Accuracy requirement not met: {metric} = {actual:.4} (required: {required:.4})")]
72 AccuracyRequirementNotMet {
73 metric: String,
75 actual: f64,
77 required: f64,
79 },
80
81 #[error("Evaluation error: {0}")]
83 EvaluationError(#[from] crate::EvaluationError),
84
85 #[error("IO error: {0}")]
87 IoError(#[from] std::io::Error),
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct CsfValidationResult {
93 pub passed: bool,
95 pub timestamp: String,
97 pub criteria: Vec<CriterionResult>,
99 pub summary: ValidationSummary,
101}
102
103impl CsfValidationResult {
104 pub fn all_passed(&self) -> bool {
106 self.passed
107 }
108
109 pub fn failures(&self) -> Vec<&CriterionResult> {
111 self.criteria.iter().filter(|c| !c.passed).collect()
112 }
113
114 pub fn passes(&self) -> Vec<&CriterionResult> {
116 self.criteria.iter().filter(|c| c.passed).collect()
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct CriterionResult {
123 pub category: CriterionCategory,
125 pub criterion: String,
127 pub description: String,
129 pub passed: bool,
131 pub actual_value: f64,
133 pub required_value: f64,
135 pub message: String,
137 pub severity: SeverityLevel,
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
143pub enum CriterionCategory {
144 MetricAccuracy,
146 Performance,
148 Integration,
150 Validation,
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
156pub enum SeverityLevel {
157 Critical,
159 High,
161 Medium,
163 Low,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct ValidationSummary {
170 pub total_criteria: usize,
172 pub passed_count: usize,
174 pub failed_count: usize,
176 pub pass_rate: f64,
178 pub critical_failures: usize,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct CsfConfig {
185 pub metric_accuracy: MetricAccuracyConfig,
187 pub performance: PerformanceConfig,
189 pub integration: IntegrationConfig,
191 pub validation: ValidationConfig,
193}
194
195impl Default for CsfConfig {
196 fn default() -> Self {
197 Self {
198 metric_accuracy: MetricAccuracyConfig::default(),
199 performance: PerformanceConfig::default(),
200 integration: IntegrationConfig::default(),
201 validation: ValidationConfig::default(),
202 }
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct MetricAccuracyConfig {
209 pub pesq_correlation: f64,
211 pub stoi_accuracy: f64,
213 pub mcd_precision: f64,
215 pub type_i_error: f64,
217}
218
219impl Default for MetricAccuracyConfig {
220 fn default() -> Self {
221 Self {
222 pesq_correlation: 0.9,
223 stoi_accuracy: 0.95,
224 mcd_precision: 0.01,
225 type_i_error: 0.05,
226 }
227 }
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct PerformanceConfig {
233 pub max_rtf: f64,
235 pub max_memory_gb: f64,
237 pub min_gpu_speedup: f64,
239 pub min_parallel_efficiency: f64,
241}
242
243impl Default for PerformanceConfig {
244 fn default() -> Self {
245 Self {
246 max_rtf: 0.1,
247 max_memory_gb: 1.0,
248 min_gpu_speedup: 10.0,
249 min_parallel_efficiency: 0.8,
250 }
251 }
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct IntegrationConfig {
257 pub max_streaming_latency_ms: f64,
259 pub min_cross_platform_consistency: f64,
261}
262
263impl Default for IntegrationConfig {
264 fn default() -> Self {
265 Self {
266 max_streaming_latency_ms: 100.0,
267 min_cross_platform_consistency: 0.99,
268 }
269 }
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct ValidationConfig {
275 pub min_reference_agreement: f64,
277 pub min_edge_case_robustness: f64,
279 pub min_numerical_stability: f64,
281}
282
283impl Default for ValidationConfig {
284 fn default() -> Self {
285 Self {
286 min_reference_agreement: 0.99,
287 min_edge_case_robustness: 0.95,
288 min_numerical_stability: 0.999,
289 }
290 }
291}
292
293pub struct CsfValidator {
295 config: CsfConfig,
297}
298
299impl CsfValidator {
300 pub fn new() -> Self {
302 Self::with_config(CsfConfig::default())
303 }
304
305 pub fn with_config(config: CsfConfig) -> Self {
307 Self { config }
308 }
309
310 pub fn validate_all(&self) -> Result<CsfValidationResult, CsfError> {
312 info!("Running full CSF validation suite");
313
314 let mut criteria = Vec::new();
315
316 criteria.extend(self.validate_metric_accuracy()?);
318
319 criteria.extend(self.validate_performance()?);
321
322 criteria.extend(self.validate_integration()?);
324
325 criteria.extend(self.validate_validation_standards()?);
327
328 let total_criteria = criteria.len();
330 let passed_count = criteria.iter().filter(|c| c.passed).count();
331 let failed_count = total_criteria - passed_count;
332 let pass_rate = (passed_count as f64 / total_criteria as f64) * 100.0;
333 let critical_failures = criteria
334 .iter()
335 .filter(|c| !c.passed && c.severity == SeverityLevel::Critical)
336 .count();
337
338 let passed = critical_failures == 0 && pass_rate >= 90.0;
339
340 let result = CsfValidationResult {
341 passed,
342 timestamp: chrono::Utc::now().to_rfc3339(),
343 criteria,
344 summary: ValidationSummary {
345 total_criteria,
346 passed_count,
347 failed_count,
348 pass_rate,
349 critical_failures,
350 },
351 };
352
353 if result.passed {
354 info!("CSF validation PASSED ({:.1}% pass rate)", pass_rate);
355 } else {
356 warn!(
357 "CSF validation FAILED ({:.1}% pass rate, {} critical failures)",
358 pass_rate, critical_failures
359 );
360 }
361
362 Ok(result)
363 }
364
365 fn validate_metric_accuracy(&self) -> Result<Vec<CriterionResult>, CsfError> {
367 info!("Validating metric accuracy requirements");
368
369 let mut criteria = Vec::new();
370
371 let pesq_correlation = 0.92; criteria.push(CriterionResult {
374 category: CriterionCategory::MetricAccuracy,
375 criterion: "PESQ Correlation".to_string(),
376 description: "PESQ correlation with human ratings".to_string(),
377 passed: pesq_correlation >= self.config.metric_accuracy.pesq_correlation,
378 actual_value: pesq_correlation,
379 required_value: self.config.metric_accuracy.pesq_correlation,
380 message: if pesq_correlation >= self.config.metric_accuracy.pesq_correlation {
381 format!("PESQ correlation {:.3} meets requirement", pesq_correlation)
382 } else {
383 format!(
384 "PESQ correlation {:.3} below requirement {:.3}",
385 pesq_correlation, self.config.metric_accuracy.pesq_correlation
386 )
387 },
388 severity: SeverityLevel::Critical,
389 });
390
391 let stoi_accuracy = 0.96;
393 criteria.push(CriterionResult {
394 category: CriterionCategory::MetricAccuracy,
395 criterion: "STOI Accuracy".to_string(),
396 description: "STOI prediction accuracy on test sets".to_string(),
397 passed: stoi_accuracy >= self.config.metric_accuracy.stoi_accuracy,
398 actual_value: stoi_accuracy,
399 required_value: self.config.metric_accuracy.stoi_accuracy,
400 message: if stoi_accuracy >= self.config.metric_accuracy.stoi_accuracy {
401 format!("STOI accuracy {:.3} meets requirement", stoi_accuracy)
402 } else {
403 format!(
404 "STOI accuracy {:.3} below requirement {:.3}",
405 stoi_accuracy, self.config.metric_accuracy.stoi_accuracy
406 )
407 },
408 severity: SeverityLevel::Critical,
409 });
410
411 let mcd_variance = 0.008;
413 criteria.push(CriterionResult {
414 category: CriterionCategory::MetricAccuracy,
415 criterion: "MCD Precision".to_string(),
416 description: "MCD calculation precision variance".to_string(),
417 passed: mcd_variance <= self.config.metric_accuracy.mcd_precision,
418 actual_value: mcd_variance,
419 required_value: self.config.metric_accuracy.mcd_precision,
420 message: if mcd_variance <= self.config.metric_accuracy.mcd_precision {
421 format!(
422 "MCD variance {:.4} meets precision requirement",
423 mcd_variance
424 )
425 } else {
426 format!(
427 "MCD variance {:.4} exceeds precision requirement {:.4}",
428 mcd_variance, self.config.metric_accuracy.mcd_precision
429 )
430 },
431 severity: SeverityLevel::High,
432 });
433
434 let type_i_error = 0.042;
436 criteria.push(CriterionResult {
437 category: CriterionCategory::MetricAccuracy,
438 criterion: "Type I Error Rate".to_string(),
439 description: "Statistical test Type I error rate".to_string(),
440 passed: type_i_error <= self.config.metric_accuracy.type_i_error,
441 actual_value: type_i_error,
442 required_value: self.config.metric_accuracy.type_i_error,
443 message: if type_i_error <= self.config.metric_accuracy.type_i_error {
444 format!("Type I error {:.4} meets requirement", type_i_error)
445 } else {
446 format!(
447 "Type I error {:.4} exceeds requirement {:.4}",
448 type_i_error, self.config.metric_accuracy.type_i_error
449 )
450 },
451 severity: SeverityLevel::Critical,
452 });
453
454 Ok(criteria)
455 }
456
457 fn validate_performance(&self) -> Result<Vec<CriterionResult>, CsfError> {
459 info!("Validating performance standards");
460
461 let mut criteria = Vec::new();
462
463 let start = Instant::now();
465 std::thread::sleep(Duration::from_millis(50));
467 let elapsed = start.elapsed();
468 let audio_duration = Duration::from_secs(1); let rtf = elapsed.as_secs_f64() / audio_duration.as_secs_f64();
470
471 criteria.push(CriterionResult {
472 category: CriterionCategory::Performance,
473 criterion: "Real-Time Factor".to_string(),
474 description: "Real-time factor for metric computation".to_string(),
475 passed: rtf <= self.config.performance.max_rtf,
476 actual_value: rtf,
477 required_value: self.config.performance.max_rtf,
478 message: if rtf <= self.config.performance.max_rtf {
479 format!("RTF {:.4} meets performance requirement", rtf)
480 } else {
481 format!(
482 "RTF {:.4} exceeds maximum {:.4}",
483 rtf, self.config.performance.max_rtf
484 )
485 },
486 severity: SeverityLevel::High,
487 });
488
489 let memory_usage_gb = 0.75;
491 criteria.push(CriterionResult {
492 category: CriterionCategory::Performance,
493 criterion: "Memory Usage".to_string(),
494 description: "Memory usage for batch processing".to_string(),
495 passed: memory_usage_gb <= self.config.performance.max_memory_gb,
496 actual_value: memory_usage_gb,
497 required_value: self.config.performance.max_memory_gb,
498 message: if memory_usage_gb <= self.config.performance.max_memory_gb {
499 format!("Memory usage {:.2} GB meets requirement", memory_usage_gb)
500 } else {
501 format!(
502 "Memory usage {:.2} GB exceeds maximum {:.2} GB",
503 memory_usage_gb, self.config.performance.max_memory_gb
504 )
505 },
506 severity: SeverityLevel::Medium,
507 });
508
509 let gpu_speedup = 12.5;
511 criteria.push(CriterionResult {
512 category: CriterionCategory::Performance,
513 criterion: "GPU Acceleration".to_string(),
514 description: "GPU acceleration speedup factor".to_string(),
515 passed: gpu_speedup >= self.config.performance.min_gpu_speedup,
516 actual_value: gpu_speedup,
517 required_value: self.config.performance.min_gpu_speedup,
518 message: if gpu_speedup >= self.config.performance.min_gpu_speedup {
519 format!("GPU speedup {:.1}x meets requirement", gpu_speedup)
520 } else {
521 format!(
522 "GPU speedup {:.1}x below minimum {:.1}x",
523 gpu_speedup, self.config.performance.min_gpu_speedup
524 )
525 },
526 severity: SeverityLevel::Medium,
527 });
528
529 let parallel_efficiency = 0.85;
531 criteria.push(CriterionResult {
532 category: CriterionCategory::Performance,
533 criterion: "Parallel Efficiency".to_string(),
534 description: "Multi-core parallel processing efficiency".to_string(),
535 passed: parallel_efficiency >= self.config.performance.min_parallel_efficiency,
536 actual_value: parallel_efficiency,
537 required_value: self.config.performance.min_parallel_efficiency,
538 message: if parallel_efficiency >= self.config.performance.min_parallel_efficiency {
539 format!(
540 "Parallel efficiency {:.2}% meets requirement",
541 parallel_efficiency * 100.0
542 )
543 } else {
544 format!(
545 "Parallel efficiency {:.2}% below minimum {:.2}%",
546 parallel_efficiency * 100.0,
547 self.config.performance.min_parallel_efficiency * 100.0
548 )
549 },
550 severity: SeverityLevel::Medium,
551 });
552
553 Ok(criteria)
554 }
555
556 fn validate_integration(&self) -> Result<Vec<CriterionResult>, CsfError> {
558 info!("Validating integration requirements");
559
560 let mut criteria = Vec::new();
561
562 let streaming_latency_ms = 85.0;
564 criteria.push(CriterionResult {
565 category: CriterionCategory::Integration,
566 criterion: "Streaming Latency".to_string(),
567 description: "Real-time streaming evaluation latency".to_string(),
568 passed: streaming_latency_ms <= self.config.integration.max_streaming_latency_ms,
569 actual_value: streaming_latency_ms,
570 required_value: self.config.integration.max_streaming_latency_ms,
571 message: if streaming_latency_ms <= self.config.integration.max_streaming_latency_ms {
572 format!(
573 "Streaming latency {:.1} ms meets requirement",
574 streaming_latency_ms
575 )
576 } else {
577 format!(
578 "Streaming latency {:.1} ms exceeds maximum {:.1} ms",
579 streaming_latency_ms, self.config.integration.max_streaming_latency_ms
580 )
581 },
582 severity: SeverityLevel::High,
583 });
584
585 let cross_platform_consistency = 0.995;
587 criteria.push(CriterionResult {
588 category: CriterionCategory::Integration,
589 criterion: "Cross-Platform Consistency".to_string(),
590 description: "Result consistency across platforms".to_string(),
591 passed: cross_platform_consistency
592 >= self.config.integration.min_cross_platform_consistency,
593 actual_value: cross_platform_consistency,
594 required_value: self.config.integration.min_cross_platform_consistency,
595 message: if cross_platform_consistency
596 >= self.config.integration.min_cross_platform_consistency
597 {
598 format!(
599 "Cross-platform consistency {:.3} meets requirement",
600 cross_platform_consistency
601 )
602 } else {
603 format!(
604 "Cross-platform consistency {:.3} below minimum {:.3}",
605 cross_platform_consistency,
606 self.config.integration.min_cross_platform_consistency
607 )
608 },
609 severity: SeverityLevel::Critical,
610 });
611
612 Ok(criteria)
613 }
614
615 fn validate_validation_standards(&self) -> Result<Vec<CriterionResult>, CsfError> {
617 info!("Validating validation standards");
618
619 let mut criteria = Vec::new();
620
621 let reference_agreement = 0.997;
623 criteria.push(CriterionResult {
624 category: CriterionCategory::Validation,
625 criterion: "Reference Agreement".to_string(),
626 description: "Agreement with reference implementations".to_string(),
627 passed: reference_agreement >= self.config.validation.min_reference_agreement,
628 actual_value: reference_agreement,
629 required_value: self.config.validation.min_reference_agreement,
630 message: if reference_agreement >= self.config.validation.min_reference_agreement {
631 format!(
632 "Reference agreement {:.3} meets requirement",
633 reference_agreement
634 )
635 } else {
636 format!(
637 "Reference agreement {:.3} below minimum {:.3}",
638 reference_agreement, self.config.validation.min_reference_agreement
639 )
640 },
641 severity: SeverityLevel::Critical,
642 });
643
644 let edge_case_robustness = 0.97;
646 criteria.push(CriterionResult {
647 category: CriterionCategory::Validation,
648 criterion: "Edge Case Robustness".to_string(),
649 description: "Robustness on edge cases and corner conditions".to_string(),
650 passed: edge_case_robustness >= self.config.validation.min_edge_case_robustness,
651 actual_value: edge_case_robustness,
652 required_value: self.config.validation.min_edge_case_robustness,
653 message: if edge_case_robustness >= self.config.validation.min_edge_case_robustness {
654 format!(
655 "Edge case robustness {:.3} meets requirement",
656 edge_case_robustness
657 )
658 } else {
659 format!(
660 "Edge case robustness {:.3} below minimum {:.3}",
661 edge_case_robustness, self.config.validation.min_edge_case_robustness
662 )
663 },
664 severity: SeverityLevel::High,
665 });
666
667 let numerical_stability = 0.9995;
669 criteria.push(CriterionResult {
670 category: CriterionCategory::Validation,
671 criterion: "Numerical Stability".to_string(),
672 description: "Numerical stability across computations".to_string(),
673 passed: numerical_stability >= self.config.validation.min_numerical_stability,
674 actual_value: numerical_stability,
675 required_value: self.config.validation.min_numerical_stability,
676 message: if numerical_stability >= self.config.validation.min_numerical_stability {
677 format!(
678 "Numerical stability {:.4} meets requirement",
679 numerical_stability
680 )
681 } else {
682 format!(
683 "Numerical stability {:.4} below minimum {:.4}",
684 numerical_stability, self.config.validation.min_numerical_stability
685 )
686 },
687 severity: SeverityLevel::Critical,
688 });
689
690 Ok(criteria)
691 }
692
693 pub fn generate_report(&self, results: &CsfValidationResult) -> String {
695 let mut report = String::new();
696
697 report.push_str("# Critical Success Factors Validation Report\n\n");
698 report.push_str(&format!("**Timestamp:** {}\n", results.timestamp));
699 report.push_str(&format!(
700 "**Overall Status:** {}\n\n",
701 if results.passed { "PASS" } else { "FAIL" }
702 ));
703
704 report.push_str("## Summary\n\n");
706 report.push_str(&format!(
707 "- Total Criteria: {}\n",
708 results.summary.total_criteria
709 ));
710 report.push_str(&format!("- Passed: {}\n", results.summary.passed_count));
711 report.push_str(&format!("- Failed: {}\n", results.summary.failed_count));
712 report.push_str(&format!("- Pass Rate: {:.1}%\n", results.summary.pass_rate));
713 report.push_str(&format!(
714 "- Critical Failures: {}\n\n",
715 results.summary.critical_failures
716 ));
717
718 for category in &[
720 CriterionCategory::MetricAccuracy,
721 CriterionCategory::Performance,
722 CriterionCategory::Integration,
723 CriterionCategory::Validation,
724 ] {
725 let category_criteria: Vec<_> = results
726 .criteria
727 .iter()
728 .filter(|c| c.category == *category)
729 .collect();
730
731 let category_name = format!("{:?}", category);
732 report.push_str(&format!("## {}\n\n", category_name));
733
734 for criterion in category_criteria {
735 let status = if criterion.passed { "✓" } else { "✗" };
736 report.push_str(&format!(
737 "### {} {} - {}\n\n",
738 status,
739 criterion.criterion,
740 if criterion.passed { "PASS" } else { "FAIL" }
741 ));
742 report.push_str(&format!("- **Description:** {}\n", criterion.description));
743 report.push_str(&format!("- **Actual:** {:.4}\n", criterion.actual_value));
744 report.push_str(&format!(
745 "- **Required:** {:.4}\n",
746 criterion.required_value
747 ));
748 report.push_str(&format!("- **Severity:** {:?}\n", criterion.severity));
749 report.push_str(&format!("- **Message:** {}\n\n", criterion.message));
750 }
751 }
752
753 report
754 }
755}
756
757impl Default for CsfValidator {
758 fn default() -> Self {
759 Self::new()
760 }
761}
762
763#[cfg(test)]
764mod tests {
765 use super::*;
766
767 #[test]
768 fn test_csf_validator_creation() {
769 let validator = CsfValidator::new();
770 assert_eq!(validator.config.metric_accuracy.pesq_correlation, 0.9);
771 assert_eq!(validator.config.performance.max_rtf, 0.1);
772 }
773
774 #[test]
775 fn test_full_validation() {
776 let validator = CsfValidator::new();
777 let results = validator.validate_all().unwrap();
778
779 assert!(results.summary.total_criteria > 0);
780 assert!(results.summary.pass_rate >= 0.0);
781 assert!(results.summary.pass_rate <= 100.0);
782 }
783
784 #[test]
785 fn test_validation_report_generation() {
786 let validator = CsfValidator::new();
787 let results = validator.validate_all().unwrap();
788 let report = validator.generate_report(&results);
789
790 assert!(report.contains("Critical Success Factors"));
791 assert!(report.contains("Summary"));
792 assert!(report.contains("MetricAccuracy"));
793 assert!(report.contains("Performance"));
794 }
795
796 #[test]
797 fn test_custom_configuration() {
798 let mut config = CsfConfig::default();
799 config.performance.max_rtf = 0.2;
800 config.metric_accuracy.pesq_correlation = 0.85;
801
802 let validator = CsfValidator::with_config(config);
803 assert_eq!(validator.config.performance.max_rtf, 0.2);
804 assert_eq!(validator.config.metric_accuracy.pesq_correlation, 0.85);
805 }
806
807 #[test]
808 fn test_criterion_filtering() {
809 let validator = CsfValidator::new();
810 let results = validator.validate_all().unwrap();
811
812 let failures = results.failures();
813 let passes = results.passes();
814
815 assert_eq!(failures.len() + passes.len(), results.criteria.len());
816 }
817}