sklears_compose/
enhanced_compile_time_validation.rs

1//! Enhanced compile-time validation for pipeline configurations
2//!
3//! This module provides comprehensive compile-time validation capabilities for ML pipelines including:
4//! - Type-level validation using Rust's type system to catch errors at compile time
5//! - Constraint validation for parameter ranges and dependencies
6//! - Schema validation for configuration structure and format
7//! - Cross-reference validation for relationships between configuration sections
8//! - Custom validation rules and user-defined validation logic
9//! - Comprehensive validation reporting with detailed error messages and suggestions
10
11use crate::error::{Result, SklearsComposeError};
12use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, HashSet};
14use std::marker::PhantomData;
15use std::sync::{Arc, RwLock};
16use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
17
18/// Enhanced compile-time validation system for ML pipeline configurations
19#[derive(Debug)]
20pub struct CompileTimeValidator<State = Unvalidated> {
21    /// Validation state marker
22    state: PhantomData<State>,
23
24    /// Schema validators for different configuration types
25    schema_validators: Arc<RwLock<HashMap<String, Box<dyn SchemaValidator>>>>,
26
27    /// Constraint validators for parameter validation
28    constraint_validators: Arc<RwLock<Vec<Box<dyn ConstraintValidator>>>>,
29
30    /// Dependency validators for checking relationships
31    dependency_validators: Arc<RwLock<Vec<Box<dyn DependencyValidator>>>>,
32
33    /// Cross-reference validators for inter-section validation
34    cross_reference_validators: Arc<RwLock<Vec<Box<dyn CrossReferenceValidator>>>>,
35
36    /// Custom validation rules
37    custom_validators: Arc<RwLock<Vec<Box<dyn CustomValidator>>>>,
38
39    /// Validation configuration
40    config: ValidationConfig,
41
42    /// Validation cache for performance
43    validation_cache: Arc<RwLock<HashMap<String, ValidationResult>>>,
44}
45
46/// Validation state markers
47#[derive(Debug, Clone)]
48pub struct Unvalidated;
49
50#[derive(Debug, Clone)]
51pub struct Validated;
52
53#[derive(Debug, Clone)]
54pub struct PartiallyValidated;
55
56/// Configuration for validation behavior
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct ValidationConfig {
59    /// Enable strict type checking
60    pub strict_type_checking: bool,
61
62    /// Enable constraint validation
63    pub enable_constraint_validation: bool,
64
65    /// Enable dependency validation
66    pub enable_dependency_validation: bool,
67
68    /// Enable cross-reference validation
69    pub enable_cross_reference_validation: bool,
70
71    /// Enable custom validation rules
72    pub enable_custom_validation: bool,
73
74    /// Maximum validation depth for nested configurations
75    pub max_validation_depth: usize,
76
77    /// Validation timeout
78    pub validation_timeout: Duration,
79
80    /// Enable validation caching
81    pub enable_caching: bool,
82
83    /// Fail fast on first error or collect all errors
84    pub fail_fast: bool,
85
86    /// Enable detailed validation reports
87    pub detailed_reports: bool,
88}
89
90/// Comprehensive validation result
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct ValidationResult {
93    /// Overall validation status
94    pub status: ValidationStatus,
95
96    /// Validation errors found
97    pub errors: Vec<ValidationError>,
98
99    /// Validation warnings
100    pub warnings: Vec<ValidationWarning>,
101
102    /// Validation suggestions
103    pub suggestions: Vec<ValidationSuggestion>,
104
105    /// Validation metrics
106    pub metrics: ValidationMetrics,
107
108    /// Validation timestamp
109    pub timestamp: SystemTime,
110}
111
112/// Validation status
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub enum ValidationStatus {
115    /// Valid
116    Valid,
117    /// Invalid
118    Invalid,
119    /// Warning
120    Warning,
121    /// Partial
122    Partial,
123    /// Unknown
124    Unknown,
125}
126
127/// Validation error with detailed information
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct ValidationError {
130    /// Error identifier
131    pub error_id: String,
132
133    /// Error category
134    pub category: ValidationErrorCategory,
135
136    /// Error message
137    pub message: String,
138
139    /// Error location in configuration
140    pub location: ConfigurationLocation,
141
142    /// Error severity
143    pub severity: ValidationSeverity,
144
145    /// Expected value or format
146    pub expected: Option<String>,
147
148    /// Actual value found
149    pub actual: Option<String>,
150
151    /// Suggested fix
152    pub suggestion: Option<String>,
153
154    /// Related errors
155    pub related_errors: Vec<String>,
156}
157
158/// Categories of validation errors
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub enum ValidationErrorCategory {
161    /// TypeMismatch
162    TypeMismatch,
163    /// ConstraintViolation
164    ConstraintViolation,
165    /// MissingRequired
166    MissingRequired,
167    /// InvalidFormat
168    InvalidFormat,
169    /// DependencyMissing
170    DependencyMissing,
171    /// CrossReferenceError
172    CrossReferenceError,
173    /// CustomValidationFailure
174    CustomValidationFailure,
175    /// SchemaViolation
176    SchemaViolation,
177    /// RangeError
178    RangeError,
179    /// CompatibilityError
180    CompatibilityError,
181}
182
183/// Validation error severity levels
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub enum ValidationSeverity {
186    /// Critical
187    Critical,
188    /// High
189    High,
190    /// Medium
191    Medium,
192    /// Low
193    Low,
194    /// Info
195    Info,
196}
197
198/// Location within configuration
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct ConfigurationLocation {
201    /// Configuration section
202    pub section: String,
203
204    /// Field path (e.g., "`model.parameters.learning_rate`")
205    pub field_path: String,
206
207    /// Line number (if applicable)
208    pub line_number: Option<usize>,
209
210    /// Column number (if applicable)
211    pub column_number: Option<usize>,
212}
213
214/// Validation warning
215#[derive(Debug, Clone, Serialize, Deserialize)]
216pub struct ValidationWarning {
217    /// Warning identifier
218    pub warning_id: String,
219
220    /// Warning message
221    pub message: String,
222
223    /// Warning location
224    pub location: ConfigurationLocation,
225
226    /// Warning category
227    pub category: WarningCategory,
228
229    /// Recommendation
230    pub recommendation: Option<String>,
231}
232
233/// Warning categories
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub enum WarningCategory {
236    /// Performance
237    Performance,
238    /// Compatibility
239    Compatibility,
240    /// Deprecated
241    Deprecated,
242    /// Suboptimal
243    Suboptimal,
244    /// Experimental
245    Experimental,
246}
247
248/// Validation suggestion
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct ValidationSuggestion {
251    /// Suggestion identifier
252    pub suggestion_id: String,
253
254    /// Suggestion message
255    pub message: String,
256
257    /// Suggested action
258    pub action: SuggestionAction,
259
260    /// Confidence level
261    pub confidence: f64,
262
263    /// Priority level
264    pub priority: SuggestionPriority,
265}
266
267/// Types of suggestion actions
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub enum SuggestionAction {
270    /// AddField
271    AddField { field: String, value: String },
272    /// RemoveField
273    RemoveField { field: String },
274    /// ModifyField
275    ModifyField { field: String, new_value: String },
276    /// RestructureSection
277    RestructureSection {
278        section: String,
279        new_structure: String,
280    },
281    /// AddDependency
282    AddDependency { dependency: String },
283    /// UpgradeVersion
284    UpgradeVersion { component: String, version: String },
285}
286
287/// Suggestion priority levels
288#[derive(Debug, Clone, Serialize, Deserialize)]
289pub enum SuggestionPriority {
290    /// Critical
291    Critical,
292    /// High
293    High,
294    /// Medium
295    Medium,
296    /// Low
297    Low,
298}
299
300/// Validation performance metrics
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub struct ValidationMetrics {
303    /// Total validation time
304    pub validation_time: Duration,
305
306    /// Number of rules checked
307    pub rules_checked: usize,
308
309    /// Number of fields validated
310    pub fields_validated: usize,
311
312    /// Cache hit rate
313    pub cache_hit_rate: f64,
314
315    /// Memory usage during validation
316    pub memory_usage: u64,
317}
318
319/// Type-safe configuration builder with compile-time validation
320#[derive(Debug)]
321pub struct TypeSafeConfigBuilder<State = Unbuilt> {
322    /// Builder state marker
323    state: PhantomData<State>,
324
325    /// Configuration data
326    config_data: HashMap<String, ConfigValue>,
327
328    /// Type constraints
329    type_constraints: HashMap<String, TypeConstraint>,
330
331    /// Validation rules
332    validation_rules: Vec<Box<dyn ValidationRule>>,
333
334    /// Builder configuration
335    builder_config: BuilderConfig,
336}
337
338/// Builder state markers
339#[derive(Debug, Clone)]
340pub struct Unbuilt;
341
342#[derive(Debug, Clone)]
343pub struct Built;
344
345/// Configuration value with type information
346#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
347pub enum ConfigValue {
348    /// String
349    String(String),
350    /// Integer
351    Integer(i64),
352    /// Float
353    Float(f64),
354    /// Boolean
355    Boolean(bool),
356    /// Array
357    Array(Vec<ConfigValue>),
358    /// Object
359    Object(HashMap<String, ConfigValue>),
360    /// Null
361    Null,
362}
363
364/// Type constraint for configuration fields
365pub struct TypeConstraint {
366    /// Expected type
367    pub expected_type: ConfigType,
368
369    /// Whether field is required
370    pub required: bool,
371
372    /// Default value if not provided
373    pub default_value: Option<ConfigValue>,
374
375    /// Value constraints
376    pub constraints: Vec<ValueConstraint>,
377
378    /// Custom validation function
379    pub custom_validator: Option<Box<dyn Fn(&ConfigValue) -> Result<()> + Send + Sync>>,
380}
381
382impl std::fmt::Debug for TypeConstraint {
383    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384        f.debug_struct("TypeConstraint")
385            .field("expected_type", &self.expected_type)
386            .field("required", &self.required)
387            .field("default_value", &self.default_value)
388            .field("constraints", &self.constraints)
389            .field(
390                "custom_validator",
391                &format!(
392                    "<{} validator>",
393                    if self.custom_validator.is_some() {
394                        "some"
395                    } else {
396                        "none"
397                    }
398                ),
399            )
400            .finish()
401    }
402}
403
404impl Clone for TypeConstraint {
405    fn clone(&self) -> Self {
406        Self {
407            expected_type: self.expected_type.clone(),
408            required: self.required,
409            default_value: self.default_value.clone(),
410            constraints: self.constraints.clone(),
411            custom_validator: None, // Can't clone function pointers
412        }
413    }
414}
415
416/// Configuration value types
417#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
418pub enum ConfigType {
419    /// String
420    String,
421    /// Integer
422    Integer,
423    /// Float
424    Float,
425    /// Boolean
426    Boolean,
427    /// Array
428    Array(Box<ConfigType>),
429    /// Object
430    Object(HashMap<String, ConfigType>),
431    /// Union
432    Union(Vec<ConfigType>),
433    /// Optional
434    Optional(Box<ConfigType>),
435}
436
437/// Value constraints for configuration fields
438#[derive(Debug, Clone, Serialize, Deserialize)]
439pub enum ValueConstraint {
440    /// Range
441    Range { min: f64, max: f64 },
442    /// Length
443    Length { min: usize, max: Option<usize> },
444    /// Pattern
445    Pattern(String),
446    /// OneOf
447    OneOf(Vec<ConfigValue>),
448    /// Custom
449    Custom(String), // Custom constraint description
450}
451
452/// Builder configuration
453#[derive(Debug, Clone)]
454pub struct BuilderConfig {
455    /// Enable strict validation
456    pub strict_validation: bool,
457
458    /// Allow unknown fields
459    pub allow_unknown_fields: bool,
460
461    /// Maximum nesting depth
462    pub max_nesting_depth: usize,
463}
464
465/// Schema validator trait
466pub trait SchemaValidator: std::fmt::Debug + Send + Sync {
467    /// Validate configuration against schema
468    fn validate_schema(
469        &self,
470        config: &HashMap<String, ConfigValue>,
471    ) -> Result<Vec<ValidationError>>;
472
473    /// Get schema name
474    fn schema_name(&self) -> &str;
475
476    /// Get schema version
477    fn schema_version(&self) -> &str;
478}
479
480/// Constraint validator trait
481pub trait ConstraintValidator: std::fmt::Debug + Send + Sync {
482    /// Validate configuration constraints
483    fn validate_constraints(
484        &self,
485        config: &HashMap<String, ConfigValue>,
486    ) -> Result<Vec<ValidationError>>;
487
488    /// Get validator name
489    fn validator_name(&self) -> &str;
490}
491
492/// Dependency validator trait
493pub trait DependencyValidator: std::fmt::Debug + Send + Sync {
494    /// Validate configuration dependencies
495    fn validate_dependencies(
496        &self,
497        config: &HashMap<String, ConfigValue>,
498    ) -> Result<Vec<ValidationError>>;
499
500    /// Get dependency validator name
501    fn validator_name(&self) -> &str;
502}
503
504/// Cross-reference validator trait
505pub trait CrossReferenceValidator: std::fmt::Debug + Send + Sync {
506    /// Validate cross-references in configuration
507    fn validate_cross_references(
508        &self,
509        config: &HashMap<String, ConfigValue>,
510    ) -> Result<Vec<ValidationError>>;
511
512    /// Get validator name
513    fn validator_name(&self) -> &str;
514}
515
516/// Custom validator trait
517pub trait CustomValidator: std::fmt::Debug + Send + Sync {
518    /// Perform custom validation
519    fn validate(&self, config: &HashMap<String, ConfigValue>) -> Result<Vec<ValidationError>>;
520
521    /// Get validator name
522    fn validator_name(&self) -> &str;
523
524    /// Get validator description
525    fn description(&self) -> &str;
526}
527
528/// Validation rule trait
529pub trait ValidationRule: std::fmt::Debug + Send + Sync {
530    /// Apply validation rule
531    fn apply(&self, field: &str, value: &ConfigValue) -> Result<()>;
532
533    /// Get rule name
534    fn rule_name(&self) -> &str;
535}
536
537/// Pipeline configuration schema
538#[derive(Debug, Clone, Serialize, Deserialize)]
539pub struct PipelineConfigurationSchema {
540    /// Schema version
541    pub version: String,
542
543    /// Required fields
544    pub required_fields: HashSet<String>,
545
546    /// Field definitions
547    pub field_definitions: HashMap<String, FieldDefinition>,
548
549    /// Schema constraints
550    pub constraints: Vec<SchemaConstraint>,
551
552    /// Cross-reference rules
553    pub cross_reference_rules: Vec<CrossReferenceRule>,
554}
555
556/// Field definition in schema
557#[derive(Debug, Clone, Serialize, Deserialize)]
558pub struct FieldDefinition {
559    /// Field type
560    pub field_type: ConfigType,
561
562    /// Field description
563    pub description: String,
564
565    /// Default value
566    pub default: Option<ConfigValue>,
567
568    /// Field constraints
569    pub constraints: Vec<ValueConstraint>,
570
571    /// Whether field is deprecated
572    pub deprecated: bool,
573
574    /// Deprecation message
575    pub deprecation_message: Option<String>,
576}
577
578/// Schema-level constraint
579#[derive(Debug, Clone, Serialize, Deserialize)]
580pub struct SchemaConstraint {
581    /// Constraint name
582    pub name: String,
583
584    /// Constraint description
585    pub description: String,
586
587    /// Fields involved in constraint
588    pub fields: Vec<String>,
589
590    /// Constraint type
591    pub constraint_type: SchemaConstraintType,
592}
593
594/// Types of schema constraints
595#[derive(Debug, Clone, Serialize, Deserialize)]
596pub enum SchemaConstraintType {
597    /// MutualExclusion
598    MutualExclusion,
599    /// RequiredTogether
600    RequiredTogether,
601    /// ConditionalRequired
602    ConditionalRequired {
603        condition: String,
604        required: Vec<String>,
605    },
606    /// ValueDependency
607    ValueDependency {
608        field: String,
609        dependent_field: String,
610        values: Vec<ConfigValue>,
611    },
612}
613
614/// Cross-reference rule
615#[derive(Debug, Clone, Serialize, Deserialize)]
616pub struct CrossReferenceRule {
617    /// Rule name
618    pub name: String,
619
620    /// Source field
621    pub source_field: String,
622
623    /// Target field
624    pub target_field: String,
625
626    /// Reference type
627    pub reference_type: ReferenceType,
628
629    /// Validation rule
630    pub validation_rule: String,
631}
632
633/// Types of cross-references
634#[derive(Debug, Clone, Serialize, Deserialize)]
635pub enum ReferenceType {
636    /// ForeignKey
637    ForeignKey,
638    /// WeakReference
639    WeakReference,
640    /// StrongReference
641    StrongReference,
642    /// Computed
643    Computed,
644}
645
646/// Compile-time validated pipeline configuration
647#[derive(Debug)]
648pub struct ValidatedPipelineConfig<T> {
649    /// Configuration data
650    config: T,
651
652    /// Validation proof
653    validation_proof: ValidationProof,
654
655    /// Schema version used for validation
656    schema_version: String,
657}
658
659/// Proof that configuration has been validated
660#[derive(Debug, Clone)]
661pub struct ValidationProof {
662    /// Proof identifier
663    proof_id: String,
664
665    /// Validation timestamp
666    validation_time: SystemTime,
667
668    /// Validator version
669    validator_version: String,
670
671    /// Validation checksum
672    checksum: String,
673}
674
675/// Type-level proof that configuration is valid
676pub struct ValidConfigMarker<T>(PhantomData<T>);
677
678impl Default for ValidationConfig {
679    fn default() -> Self {
680        Self {
681            strict_type_checking: true,
682            enable_constraint_validation: true,
683            enable_dependency_validation: true,
684            enable_cross_reference_validation: true,
685            enable_custom_validation: true,
686            max_validation_depth: 10,
687            validation_timeout: Duration::from_secs(30),
688            enable_caching: true,
689            fail_fast: false,
690            detailed_reports: true,
691        }
692    }
693}
694
695impl<State> CompileTimeValidator<State> {
696    /// Create a new compile-time validator
697    #[must_use]
698    pub fn new() -> CompileTimeValidator<Unvalidated> {
699        Self::with_config(ValidationConfig::default())
700    }
701
702    /// Create a new compile-time validator with custom configuration
703    #[must_use]
704    pub fn with_config(config: ValidationConfig) -> CompileTimeValidator<Unvalidated> {
705        /// CompileTimeValidator
706        CompileTimeValidator {
707            state: PhantomData,
708            schema_validators: Arc::new(RwLock::new(HashMap::new())),
709            constraint_validators: Arc::new(RwLock::new(Vec::new())),
710            dependency_validators: Arc::new(RwLock::new(Vec::new())),
711            cross_reference_validators: Arc::new(RwLock::new(Vec::new())),
712            custom_validators: Arc::new(RwLock::new(Vec::new())),
713            config,
714            validation_cache: Arc::new(RwLock::new(HashMap::new())),
715        }
716    }
717}
718
719impl CompileTimeValidator<Unvalidated> {
720    /// Add a schema validator
721    #[must_use]
722    pub fn add_schema_validator(self, validator: Box<dyn SchemaValidator>) -> Self {
723        let schema_name = validator.schema_name().to_string();
724        self.schema_validators
725            .write()
726            .unwrap()
727            .insert(schema_name, validator);
728        self
729    }
730
731    /// Add a constraint validator
732    #[must_use]
733    pub fn add_constraint_validator(self, validator: Box<dyn ConstraintValidator>) -> Self {
734        self.constraint_validators.write().unwrap().push(validator);
735        self
736    }
737
738    /// Add a dependency validator
739    #[must_use]
740    pub fn add_dependency_validator(self, validator: Box<dyn DependencyValidator>) -> Self {
741        self.dependency_validators.write().unwrap().push(validator);
742        self
743    }
744
745    /// Add a cross-reference validator
746    #[must_use]
747    pub fn add_cross_reference_validator(
748        self,
749        validator: Box<dyn CrossReferenceValidator>,
750    ) -> Self {
751        self.cross_reference_validators
752            .write()
753            .unwrap()
754            .push(validator);
755        self
756    }
757
758    /// Add a custom validator
759    #[must_use]
760    pub fn add_custom_validator(self, validator: Box<dyn CustomValidator>) -> Self {
761        self.custom_validators.write().unwrap().push(validator);
762        self
763    }
764
765    /// Validate configuration and transition to validated state
766    pub fn validate(
767        self,
768        config: &HashMap<String, ConfigValue>,
769    ) -> Result<(CompileTimeValidator<Validated>, ValidationResult)> {
770        let start_time = Instant::now();
771        let mut errors = Vec::new();
772        let warnings = Vec::new();
773        let mut suggestions = Vec::new();
774        let mut rules_checked = 0;
775
776        // Check validation cache
777        let config_hash = self.compute_config_hash(config);
778        if self.config.enable_caching {
779            if let Some(cached_result) = self.validation_cache.read().unwrap().get(&config_hash) {
780                let validation_cache_clone = Arc::clone(&self.validation_cache);
781                return Ok((
782                    /// CompileTimeValidator
783                    CompileTimeValidator {
784                        state: PhantomData,
785                        schema_validators: self.schema_validators,
786                        constraint_validators: self.constraint_validators,
787                        dependency_validators: self.dependency_validators,
788                        cross_reference_validators: self.cross_reference_validators,
789                        custom_validators: self.custom_validators,
790                        config: self.config,
791                        validation_cache: validation_cache_clone,
792                    },
793                    cached_result.clone(),
794                ));
795            }
796        }
797
798        // Schema validation
799        if !self.schema_validators.read().unwrap().is_empty() {
800            for validator in self.schema_validators.read().unwrap().values() {
801                match validator.validate_schema(config) {
802                    Ok(mut schema_errors) => {
803                        errors.append(&mut schema_errors);
804                        rules_checked += 1;
805                    }
806                    Err(e) => {
807                        errors.push(ValidationError {
808                            error_id: format!("schema_error_{rules_checked}"),
809                            category: ValidationErrorCategory::SchemaViolation,
810                            message: e.to_string(),
811                            location: ConfigurationLocation {
812                                section: "schema".to_string(),
813                                field_path: "root".to_string(),
814                                line_number: None,
815                                column_number: None,
816                            },
817                            severity: ValidationSeverity::Critical,
818                            expected: None,
819                            actual: None,
820                            suggestion: Some(
821                                "Check schema definition and configuration format".to_string(),
822                            ),
823                            related_errors: Vec::new(),
824                        });
825                    }
826                }
827
828                if self.config.fail_fast && !errors.is_empty() {
829                    break;
830                }
831            }
832        }
833
834        // Constraint validation
835        if self.config.enable_constraint_validation && (errors.is_empty() || !self.config.fail_fast)
836        {
837            for validator in self.constraint_validators.read().unwrap().iter() {
838                match validator.validate_constraints(config) {
839                    Ok(mut constraint_errors) => {
840                        errors.append(&mut constraint_errors);
841                        rules_checked += 1;
842                    }
843                    Err(e) => {
844                        errors.push(ValidationError {
845                            error_id: format!("constraint_error_{rules_checked}"),
846                            category: ValidationErrorCategory::ConstraintViolation,
847                            message: e.to_string(),
848                            location: ConfigurationLocation {
849                                section: "constraints".to_string(),
850                                field_path: "unknown".to_string(),
851                                line_number: None,
852                                column_number: None,
853                            },
854                            severity: ValidationSeverity::High,
855                            expected: None,
856                            actual: None,
857                            suggestion: Some(
858                                "Review parameter constraints and valid ranges".to_string(),
859                            ),
860                            related_errors: Vec::new(),
861                        });
862                    }
863                }
864
865                if self.config.fail_fast && !errors.is_empty() {
866                    break;
867                }
868            }
869        }
870
871        // Dependency validation
872        if self.config.enable_dependency_validation && (errors.is_empty() || !self.config.fail_fast)
873        {
874            for validator in self.dependency_validators.read().unwrap().iter() {
875                match validator.validate_dependencies(config) {
876                    Ok(mut dependency_errors) => {
877                        errors.append(&mut dependency_errors);
878                        rules_checked += 1;
879                    }
880                    Err(e) => {
881                        errors.push(ValidationError {
882                            error_id: format!("dependency_error_{rules_checked}"),
883                            category: ValidationErrorCategory::DependencyMissing,
884                            message: e.to_string(),
885                            location: ConfigurationLocation {
886                                section: "dependencies".to_string(),
887                                field_path: "unknown".to_string(),
888                                line_number: None,
889                                column_number: None,
890                            },
891                            severity: ValidationSeverity::High,
892                            expected: None,
893                            actual: None,
894                            suggestion: Some(
895                                "Check that all required dependencies are configured".to_string(),
896                            ),
897                            related_errors: Vec::new(),
898                        });
899                    }
900                }
901
902                if self.config.fail_fast && !errors.is_empty() {
903                    break;
904                }
905            }
906        }
907
908        // Cross-reference validation
909        if self.config.enable_cross_reference_validation
910            && (errors.is_empty() || !self.config.fail_fast)
911        {
912            for validator in self.cross_reference_validators.read().unwrap().iter() {
913                match validator.validate_cross_references(config) {
914                    Ok(mut cross_ref_errors) => {
915                        errors.append(&mut cross_ref_errors);
916                        rules_checked += 1;
917                    }
918                    Err(e) => {
919                        errors.push(ValidationError {
920                            error_id: format!("cross_ref_error_{rules_checked}"),
921                            category: ValidationErrorCategory::CrossReferenceError,
922                            message: e.to_string(),
923                            location: ConfigurationLocation {
924                                section: "cross_references".to_string(),
925                                field_path: "unknown".to_string(),
926                                line_number: None,
927                                column_number: None,
928                            },
929                            severity: ValidationSeverity::Medium,
930                            expected: None,
931                            actual: None,
932                            suggestion: Some(
933                                "Check cross-references between configuration sections".to_string(),
934                            ),
935                            related_errors: Vec::new(),
936                        });
937                    }
938                }
939
940                if self.config.fail_fast && !errors.is_empty() {
941                    break;
942                }
943            }
944        }
945
946        // Custom validation
947        if self.config.enable_custom_validation && (errors.is_empty() || !self.config.fail_fast) {
948            for validator in self.custom_validators.read().unwrap().iter() {
949                match validator.validate(config) {
950                    Ok(mut custom_errors) => {
951                        errors.append(&mut custom_errors);
952                        rules_checked += 1;
953                    }
954                    Err(e) => {
955                        errors.push(ValidationError {
956                            error_id: format!("custom_error_{rules_checked}"),
957                            category: ValidationErrorCategory::CustomValidationFailure,
958                            message: e.to_string(),
959                            location: ConfigurationLocation {
960                                section: "custom".to_string(),
961                                field_path: "unknown".to_string(),
962                                line_number: None,
963                                column_number: None,
964                            },
965                            severity: ValidationSeverity::Medium,
966                            expected: None,
967                            actual: None,
968                            suggestion: Some("Review custom validation rules".to_string()),
969                            related_errors: Vec::new(),
970                        });
971                    }
972                }
973
974                if self.config.fail_fast && !errors.is_empty() {
975                    break;
976                }
977            }
978        }
979
980        // Generate suggestions based on errors
981        suggestions.extend(self.generate_suggestions(&errors, config));
982
983        // Determine validation status
984        let status = if !errors.is_empty() {
985            ValidationStatus::Invalid
986        } else if !warnings.is_empty() {
987            ValidationStatus::Warning
988        } else {
989            ValidationStatus::Valid
990        };
991
992        // Create validation result
993        let validation_time = start_time.elapsed();
994        let result = ValidationResult {
995            status,
996            errors,
997            warnings,
998            suggestions,
999            metrics: ValidationMetrics {
1000                validation_time,
1001                rules_checked,
1002                fields_validated: config.len(),
1003                cache_hit_rate: 0.0, // Would be calculated based on cache usage
1004                memory_usage: 0,     // Would be measured
1005            },
1006            timestamp: SystemTime::now(),
1007        };
1008
1009        // Cache result
1010        if self.config.enable_caching {
1011            self.validation_cache
1012                .write()
1013                .unwrap()
1014                .insert(config_hash, result.clone());
1015        }
1016
1017        // Transition to validated state
1018        let validated_validator = CompileTimeValidator {
1019            state: PhantomData,
1020            schema_validators: self.schema_validators,
1021            constraint_validators: self.constraint_validators,
1022            dependency_validators: self.dependency_validators,
1023            cross_reference_validators: self.cross_reference_validators,
1024            custom_validators: self.custom_validators,
1025            config: self.config,
1026            validation_cache: self.validation_cache,
1027        };
1028
1029        Ok((validated_validator, result))
1030    }
1031
1032    // Private helper methods
1033    fn compute_config_hash(&self, config: &HashMap<String, ConfigValue>) -> String {
1034        // Simple hash computation - would use a proper hash function in practice
1035        format!("hash_{}", config.len())
1036    }
1037
1038    fn generate_suggestions(
1039        &self,
1040        errors: &[ValidationError],
1041        config: &HashMap<String, ConfigValue>,
1042    ) -> Vec<ValidationSuggestion> {
1043        let mut suggestions = Vec::new();
1044
1045        for error in errors {
1046            match &error.category {
1047                ValidationErrorCategory::MissingRequired => {
1048                    suggestions.push(ValidationSuggestion {
1049                        suggestion_id: format!("add_required_{}", error.error_id),
1050                        message: format!("Add required field '{}'", error.location.field_path),
1051                        action: SuggestionAction::AddField {
1052                            field: error.location.field_path.clone(),
1053                            value: error
1054                                .expected
1055                                .clone()
1056                                .unwrap_or_else(|| "default_value".to_string()),
1057                        },
1058                        confidence: 0.9,
1059                        priority: SuggestionPriority::Critical,
1060                    });
1061                }
1062                ValidationErrorCategory::TypeMismatch => {
1063                    if let Some(expected) = &error.expected {
1064                        suggestions.push(ValidationSuggestion {
1065                            suggestion_id: format!("fix_type_{}", error.error_id),
1066                            message: format!(
1067                                "Convert field '{}' to type '{}'",
1068                                error.location.field_path, expected
1069                            ),
1070                            action: SuggestionAction::ModifyField {
1071                                field: error.location.field_path.clone(),
1072                                new_value: format!("convert_to_{expected}"),
1073                            },
1074                            confidence: 0.8,
1075                            priority: SuggestionPriority::High,
1076                        });
1077                    }
1078                }
1079                _ => {}
1080            }
1081        }
1082
1083        suggestions
1084    }
1085}
1086
1087impl CompileTimeValidator<Validated> {
1088    /// Create a validated configuration from raw config data
1089    pub fn create_validated_config<T>(&self, config: T) -> ValidatedPipelineConfig<T> {
1090        let validation_proof = ValidationProof {
1091            proof_id: format!(
1092                "proof_{}",
1093                SystemTime::now()
1094                    .duration_since(UNIX_EPOCH)
1095                    .unwrap()
1096                    .as_millis()
1097            ),
1098            validation_time: SystemTime::now(),
1099            validator_version: "1.0.0".to_string(),
1100            checksum: "validated".to_string(),
1101        };
1102
1103        /// ValidatedPipelineConfig
1104        ValidatedPipelineConfig {
1105            config,
1106            validation_proof,
1107            schema_version: "1.0.0".to_string(),
1108        }
1109    }
1110
1111    /// Get validation metrics
1112    #[must_use]
1113    pub fn get_validation_metrics(&self) -> ValidationMetrics {
1114        /// ValidationMetrics
1115        ValidationMetrics {
1116            validation_time: Duration::from_millis(0),
1117            rules_checked: 0,
1118            fields_validated: 0,
1119            cache_hit_rate: 0.0,
1120            memory_usage: 0,
1121        }
1122    }
1123}
1124
1125impl<T> ValidatedPipelineConfig<T> {
1126    /// Get the validated configuration
1127    pub fn config(&self) -> &T {
1128        &self.config
1129    }
1130
1131    /// Get the validation proof
1132    pub fn validation_proof(&self) -> &ValidationProof {
1133        &self.validation_proof
1134    }
1135
1136    /// Convert to another type while preserving validation
1137    pub fn map<U, F>(self, f: F) -> ValidatedPipelineConfig<U>
1138    where
1139        F: FnOnce(T) -> U,
1140    {
1141        /// ValidatedPipelineConfig
1142        ValidatedPipelineConfig {
1143            config: f(self.config),
1144            validation_proof: self.validation_proof,
1145            schema_version: self.schema_version,
1146        }
1147    }
1148}
1149
1150// Type-safe configuration builder implementation
1151
1152impl Default for TypeSafeConfigBuilder<Unbuilt> {
1153    fn default() -> Self {
1154        Self::new()
1155    }
1156}
1157
1158impl TypeSafeConfigBuilder<Unbuilt> {
1159    /// Create a new type-safe configuration builder
1160    #[must_use]
1161    pub fn new() -> Self {
1162        Self {
1163            state: PhantomData,
1164            config_data: HashMap::new(),
1165            type_constraints: HashMap::new(),
1166            validation_rules: Vec::new(),
1167            builder_config: BuilderConfig {
1168                strict_validation: true,
1169                allow_unknown_fields: false,
1170                max_nesting_depth: 5,
1171            },
1172        }
1173    }
1174
1175    /// Add a string field with validation
1176    pub fn string_field<T: Into<String>>(mut self, name: &str, value: T) -> Self {
1177        self.config_data
1178            .insert(name.to_string(), ConfigValue::String(value.into()));
1179        self.type_constraints.insert(
1180            name.to_string(),
1181            /// TypeConstraint
1182            TypeConstraint {
1183                expected_type: ConfigType::String,
1184                required: true,
1185                default_value: None,
1186                constraints: Vec::new(),
1187                custom_validator: None,
1188            },
1189        );
1190        self
1191    }
1192
1193    /// Add an integer field with validation
1194    #[must_use]
1195    pub fn integer_field(mut self, name: &str, value: i64) -> Self {
1196        self.config_data
1197            .insert(name.to_string(), ConfigValue::Integer(value));
1198        self.type_constraints.insert(
1199            name.to_string(),
1200            /// TypeConstraint
1201            TypeConstraint {
1202                expected_type: ConfigType::Integer,
1203                required: true,
1204                default_value: None,
1205                constraints: Vec::new(),
1206                custom_validator: None,
1207            },
1208        );
1209        self
1210    }
1211
1212    /// Add a float field with validation
1213    #[must_use]
1214    pub fn float_field(mut self, name: &str, value: f64) -> Self {
1215        self.config_data
1216            .insert(name.to_string(), ConfigValue::Float(value));
1217        self.type_constraints.insert(
1218            name.to_string(),
1219            /// TypeConstraint
1220            TypeConstraint {
1221                expected_type: ConfigType::Float,
1222                required: true,
1223                default_value: None,
1224                constraints: Vec::new(),
1225                custom_validator: None,
1226            },
1227        );
1228        self
1229    }
1230
1231    /// Add a boolean field with validation
1232    #[must_use]
1233    pub fn boolean_field(mut self, name: &str, value: bool) -> Self {
1234        self.config_data
1235            .insert(name.to_string(), ConfigValue::Boolean(value));
1236        self.type_constraints.insert(
1237            name.to_string(),
1238            /// TypeConstraint
1239            TypeConstraint {
1240                expected_type: ConfigType::Boolean,
1241                required: true,
1242                default_value: None,
1243                constraints: Vec::new(),
1244                custom_validator: None,
1245            },
1246        );
1247        self
1248    }
1249
1250    /// Add a constraint to a field
1251    #[must_use]
1252    pub fn with_constraint(mut self, field: &str, constraint: ValueConstraint) -> Self {
1253        if let Some(type_constraint) = self.type_constraints.get_mut(field) {
1254            type_constraint.constraints.push(constraint);
1255        }
1256        self
1257    }
1258
1259    /// Add a validation rule
1260    #[must_use]
1261    pub fn with_rule(mut self, rule: Box<dyn ValidationRule>) -> Self {
1262        self.validation_rules.push(rule);
1263        self
1264    }
1265
1266    /// Build the configuration with validation
1267    pub fn build(self) -> Result<TypeSafeConfigBuilder<Built>> {
1268        // Validate configuration
1269        for (field, constraint) in &self.type_constraints {
1270            if let Some(value) = self.config_data.get(field) {
1271                // Check type compatibility
1272                if !self.is_type_compatible(value, &constraint.expected_type) {
1273                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1274                        "Type mismatch for field '{}': expected {:?}, got {:?}",
1275                        field, constraint.expected_type, value
1276                    )));
1277                }
1278
1279                // Check constraints
1280                for value_constraint in &constraint.constraints {
1281                    self.validate_constraint(field, value, value_constraint)?;
1282                }
1283
1284                // Apply custom validator if present
1285                if let Some(ref validator) = constraint.custom_validator {
1286                    validator(value)
1287                        .map_err(|e| SklearsComposeError::InvalidConfiguration(e.to_string()))?;
1288                }
1289            } else if constraint.required {
1290                return Err(SklearsComposeError::InvalidConfiguration(format!(
1291                    "Required field '{field}' is missing"
1292                )));
1293            }
1294        }
1295
1296        // Apply validation rules
1297        for rule in &self.validation_rules {
1298            for (field, value) in &self.config_data {
1299                rule.apply(field, value)
1300                    .map_err(|e| SklearsComposeError::InvalidConfiguration(e.to_string()))?;
1301            }
1302        }
1303
1304        Ok(TypeSafeConfigBuilder {
1305            state: PhantomData,
1306            config_data: self.config_data,
1307            type_constraints: self.type_constraints,
1308            validation_rules: self.validation_rules,
1309            builder_config: self.builder_config,
1310        })
1311    }
1312
1313    // Helper methods
1314    fn is_type_compatible(&self, value: &ConfigValue, expected_type: &ConfigType) -> bool {
1315        match (value, expected_type) {
1316            (ConfigValue::String(_), ConfigType::String) => true,
1317            (ConfigValue::Integer(_), ConfigType::Integer) => true,
1318            (ConfigValue::Float(_), ConfigType::Float) => true,
1319            (ConfigValue::Boolean(_), ConfigType::Boolean) => true,
1320            (ConfigValue::Array(arr), ConfigType::Array(element_type)) => arr
1321                .iter()
1322                .all(|item| self.is_type_compatible(item, element_type)),
1323            (ConfigValue::Object(_), ConfigType::Object(_)) => true,
1324            (ConfigValue::Null, ConfigType::Optional(_)) => true,
1325            _ => false,
1326        }
1327    }
1328
1329    fn validate_constraint(
1330        &self,
1331        field: &str,
1332        value: &ConfigValue,
1333        constraint: &ValueConstraint,
1334    ) -> Result<()> {
1335        match constraint {
1336            ValueConstraint::Range { min, max } => {
1337                let numeric_value = match value {
1338                    ConfigValue::Integer(i) => *i as f64,
1339                    ConfigValue::Float(f) => *f,
1340                    _ => {
1341                        return Err(SklearsComposeError::InvalidConfiguration(format!(
1342                            "Range constraint can only be applied to numeric values in field '{field}'"
1343                        )));
1344                    }
1345                };
1346
1347                if numeric_value < *min || numeric_value > *max {
1348                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1349                        "Value {numeric_value} in field '{field}' is outside range [{min}, {max}]"
1350                    )));
1351                }
1352            }
1353            ValueConstraint::Length { min, max } => {
1354                let length = match value {
1355                    ConfigValue::String(s) => s.len(),
1356                    ConfigValue::Array(arr) => arr.len(),
1357                    _ => {
1358                        return Err(SklearsComposeError::InvalidConfiguration(
1359                            format!("Length constraint can only be applied to strings or arrays in field '{field}'")
1360                        ));
1361                    }
1362                };
1363
1364                if length < *min {
1365                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1366                        "Length {length} in field '{field}' is less than minimum {min}"
1367                    )));
1368                }
1369
1370                if let Some(max_len) = max {
1371                    if length > *max_len {
1372                        return Err(SklearsComposeError::InvalidConfiguration(format!(
1373                            "Length {length} in field '{field}' is greater than maximum {max_len}"
1374                        )));
1375                    }
1376                }
1377            }
1378            ValueConstraint::OneOf(allowed_values) => {
1379                if !allowed_values.contains(value) {
1380                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1381                        "Value in field '{field}' is not one of the allowed values"
1382                    )));
1383                }
1384            }
1385            ValueConstraint::Pattern(pattern) => {
1386                if let ConfigValue::String(s) = value {
1387                    // Simple pattern matching - would use regex in practice
1388                    if !s.contains(pattern) {
1389                        return Err(SklearsComposeError::InvalidConfiguration(format!(
1390                            "String in field '{field}' does not match pattern '{pattern}'"
1391                        )));
1392                    }
1393                } else {
1394                    return Err(SklearsComposeError::InvalidConfiguration(format!(
1395                        "Pattern constraint can only be applied to strings in field '{field}'"
1396                    )));
1397                }
1398            }
1399            ValueConstraint::Custom(description) => {
1400                // Custom constraints would be implemented with proper validation logic
1401                // For now, just a placeholder
1402                println!("Custom constraint '{description}' applied to field '{field}'");
1403            }
1404        }
1405
1406        Ok(())
1407    }
1408}
1409
1410impl TypeSafeConfigBuilder<Built> {
1411    /// Get the validated configuration data
1412    #[must_use]
1413    pub fn config_data(&self) -> &HashMap<String, ConfigValue> {
1414        &self.config_data
1415    }
1416
1417    /// Extract configuration data
1418    #[must_use]
1419    pub fn into_config_data(self) -> HashMap<String, ConfigValue> {
1420        self.config_data
1421    }
1422}
1423
1424// Example schema and constraint validators
1425
1426/// Example schema validator for pipeline configurations
1427#[derive(Debug)]
1428pub struct PipelineSchemaValidator {
1429    schema: PipelineConfigurationSchema,
1430}
1431
1432impl Default for PipelineSchemaValidator {
1433    fn default() -> Self {
1434        Self::new()
1435    }
1436}
1437
1438impl PipelineSchemaValidator {
1439    #[must_use]
1440    pub fn new() -> Self {
1441        let mut required_fields = HashSet::new();
1442        required_fields.insert("model".to_string());
1443        required_fields.insert("pipeline".to_string());
1444
1445        let mut field_definitions = HashMap::new();
1446        field_definitions.insert(
1447            "model".to_string(),
1448            /// FieldDefinition
1449            FieldDefinition {
1450                field_type: ConfigType::Object(HashMap::new()),
1451                description: "Model configuration".to_string(),
1452                default: None,
1453                constraints: Vec::new(),
1454                deprecated: false,
1455                deprecation_message: None,
1456            },
1457        );
1458
1459        let schema = PipelineConfigurationSchema {
1460            version: "1.0.0".to_string(),
1461            required_fields,
1462            field_definitions,
1463            constraints: Vec::new(),
1464            cross_reference_rules: Vec::new(),
1465        };
1466
1467        Self { schema }
1468    }
1469}
1470
1471impl SchemaValidator for PipelineSchemaValidator {
1472    fn validate_schema(
1473        &self,
1474        config: &HashMap<String, ConfigValue>,
1475    ) -> Result<Vec<ValidationError>> {
1476        let mut errors = Vec::new();
1477
1478        // Check required fields
1479        for required_field in &self.schema.required_fields {
1480            if !config.contains_key(required_field) {
1481                errors.push(ValidationError {
1482                    error_id: format!("missing_required_{required_field}"),
1483                    category: ValidationErrorCategory::MissingRequired,
1484                    message: format!("Required field '{required_field}' is missing"),
1485                    location: ConfigurationLocation {
1486                        section: "root".to_string(),
1487                        field_path: required_field.clone(),
1488                        line_number: None,
1489                        column_number: None,
1490                    },
1491                    severity: ValidationSeverity::Critical,
1492                    expected: Some("required field".to_string()),
1493                    actual: Some("missing".to_string()),
1494                    suggestion: Some(format!("Add required field '{required_field}'")),
1495                    related_errors: Vec::new(),
1496                });
1497            }
1498        }
1499
1500        Ok(errors)
1501    }
1502
1503    fn schema_name(&self) -> &'static str {
1504        "PipelineSchema"
1505    }
1506
1507    fn schema_version(&self) -> &str {
1508        &self.schema.version
1509    }
1510}
1511
1512/// Example parameter constraint validator
1513#[derive(Debug)]
1514pub struct ParameterConstraintValidator;
1515
1516impl ConstraintValidator for ParameterConstraintValidator {
1517    fn validate_constraints(
1518        &self,
1519        config: &HashMap<String, ConfigValue>,
1520    ) -> Result<Vec<ValidationError>> {
1521        let mut errors = Vec::new();
1522
1523        // Example: validate learning rate is in valid range
1524        if let Some(ConfigValue::Object(model_config)) = config.get("model") {
1525            if let Some(ConfigValue::Float(learning_rate)) = model_config.get("learning_rate") {
1526                if *learning_rate <= 0.0 || *learning_rate > 1.0 {
1527                    errors.push(ValidationError {
1528                        error_id: "invalid_learning_rate".to_string(),
1529                        category: ValidationErrorCategory::RangeError,
1530                        message: "Learning rate must be between 0.0 and 1.0".to_string(),
1531                        location: ConfigurationLocation {
1532                            section: "model".to_string(),
1533                            field_path: "learning_rate".to_string(),
1534                            line_number: None,
1535                            column_number: None,
1536                        },
1537                        severity: ValidationSeverity::High,
1538                        expected: Some("0.0 < learning_rate <= 1.0".to_string()),
1539                        actual: Some(learning_rate.to_string()),
1540                        suggestion: Some(
1541                            "Set learning rate to a value between 0.001 and 0.1".to_string(),
1542                        ),
1543                        related_errors: Vec::new(),
1544                    });
1545                }
1546            }
1547        }
1548
1549        Ok(errors)
1550    }
1551
1552    fn validator_name(&self) -> &'static str {
1553        "ParameterConstraintValidator"
1554    }
1555}
1556
1557/// Example validation rule
1558#[derive(Debug)]
1559pub struct NonEmptyStringRule;
1560
1561impl ValidationRule for NonEmptyStringRule {
1562    fn apply(&self, field: &str, value: &ConfigValue) -> Result<()> {
1563        if let ConfigValue::String(s) = value {
1564            if s.is_empty() {
1565                return Err(format!("String field '{field}' cannot be empty").into());
1566            }
1567        }
1568        Ok(())
1569    }
1570
1571    fn rule_name(&self) -> &'static str {
1572        "NonEmptyStringRule"
1573    }
1574}
1575
1576// Convenience macros for compile-time validation
1577
1578/// Macro for creating enhanced validated configurations
1579#[macro_export]
1580macro_rules! enhanced_validated_config {
1581    ($($key:expr => $value:expr),*) => {{
1582        let mut config = std::collections::HashMap::new();
1583        $(
1584            config.insert($key.to_string(), $value);
1585        )*
1586        config
1587    }};
1588}
1589
1590/// Macro for type-safe configuration building
1591#[macro_export]
1592macro_rules! type_safe_config {
1593    (
1594        $($field:ident: $type:ident = $value:expr),*
1595    ) => {{
1596        let builder = TypeSafeConfigBuilder::new();
1597        $(
1598            let builder = match stringify!($type) {
1599                "String" => builder.string_field(stringify!($field), $value),
1600                "Integer" => builder.integer_field(stringify!($field), $value),
1601                "Float" => builder.float_field(stringify!($field), $value),
1602                "Boolean" => builder.boolean_field(stringify!($field), $value),
1603                _ => panic!("Unsupported type: {}", stringify!($type)),
1604            };
1605        )*
1606        builder.build()
1607    }};
1608}
1609
1610#[allow(non_snake_case)]
1611#[cfg(test)]
1612mod tests {
1613    use super::*;
1614
1615    #[test]
1616    fn test_validator_creation() {
1617        let validator = CompileTimeValidator::<Unvalidated>::new();
1618        assert!(validator.config.strict_type_checking);
1619    }
1620
1621    #[test]
1622    fn test_schema_validation() {
1623        let validator = CompileTimeValidator::<Unvalidated>::new()
1624            .add_schema_validator(Box::new(PipelineSchemaValidator::new()));
1625
1626        let mut config = HashMap::new();
1627        config.insert("model".to_string(), ConfigValue::Object(HashMap::new()));
1628        config.insert("pipeline".to_string(), ConfigValue::Object(HashMap::new()));
1629
1630        let result = validator.validate(&config);
1631        assert!(result.is_ok());
1632
1633        let (_, validation_result) = result.unwrap();
1634        assert!(matches!(validation_result.status, ValidationStatus::Valid));
1635    }
1636
1637    #[test]
1638    fn test_constraint_validation() {
1639        let validator = CompileTimeValidator::<Unvalidated>::new()
1640            .add_constraint_validator(Box::new(ParameterConstraintValidator));
1641
1642        let mut model_config = HashMap::new();
1643        model_config.insert("learning_rate".to_string(), ConfigValue::Float(2.0)); // Invalid
1644
1645        let mut config = HashMap::new();
1646        config.insert("model".to_string(), ConfigValue::Object(model_config));
1647
1648        let result = validator.validate(&config);
1649        assert!(result.is_ok());
1650
1651        let (_, validation_result) = result.unwrap();
1652        assert!(matches!(
1653            validation_result.status,
1654            ValidationStatus::Invalid
1655        ));
1656        assert!(!validation_result.errors.is_empty());
1657    }
1658
1659    #[test]
1660    fn test_type_safe_builder() {
1661        let builder = TypeSafeConfigBuilder::new()
1662            .string_field("name", "test_pipeline")
1663            .float_field("learning_rate", 0.01)
1664            .integer_field("epochs", 100)
1665            .boolean_field("verbose", true)
1666            .with_constraint(
1667                "learning_rate",
1668                ValueConstraint::Range { min: 0.0, max: 1.0 },
1669            )
1670            .with_rule(Box::new(NonEmptyStringRule));
1671
1672        let result = builder.build();
1673        assert!(result.is_ok());
1674
1675        let built_config = result.unwrap();
1676        assert_eq!(built_config.config_data().len(), 4);
1677    }
1678
1679    #[test]
1680    fn test_validated_config_creation() {
1681        let validator = CompileTimeValidator::<Unvalidated>::new();
1682        let config = HashMap::new();
1683
1684        let (validated_validator, _) = validator.validate(&config).unwrap();
1685        let validated_config = validated_validator.create_validated_config(config);
1686
1687        assert!(validated_config
1688            .validation_proof()
1689            .proof_id
1690            .starts_with("proof_"));
1691    }
1692
1693    #[test]
1694    fn test_validation_errors() {
1695        let validator = CompileTimeValidator::<Unvalidated>::new()
1696            .add_schema_validator(Box::new(PipelineSchemaValidator::new()));
1697
1698        let config = HashMap::new(); // Missing required fields
1699
1700        let result = validator.validate(&config);
1701        assert!(result.is_ok());
1702
1703        let (_, validation_result) = result.unwrap();
1704        assert!(matches!(
1705            validation_result.status,
1706            ValidationStatus::Invalid
1707        ));
1708        assert!(validation_result.errors.len() >= 2); // Missing "model" and "pipeline"
1709    }
1710
1711    #[test]
1712    fn test_config_value_types() {
1713        assert!(matches!(
1714            ConfigValue::String("test".to_string()),
1715            ConfigValue::String(_)
1716        ));
1717        assert!(matches!(ConfigValue::Integer(42), ConfigValue::Integer(_)));
1718        assert!(matches!(ConfigValue::Float(3.14), ConfigValue::Float(_)));
1719        assert!(matches!(
1720            ConfigValue::Boolean(true),
1721            ConfigValue::Boolean(_)
1722        ));
1723    }
1724
1725    #[test]
1726    fn test_validation_suggestions() {
1727        let validator = CompileTimeValidator::<Unvalidated>::new()
1728            .add_schema_validator(Box::new(PipelineSchemaValidator::new()));
1729
1730        let config = HashMap::new();
1731
1732        let (_, validation_result) = validator.validate(&config).unwrap();
1733        assert!(!validation_result.suggestions.is_empty());
1734
1735        let suggestion = &validation_result.suggestions[0];
1736        assert!(matches!(suggestion.priority, SuggestionPriority::Critical));
1737    }
1738
1739    #[test]
1740    fn test_constraint_range() {
1741        let builder = TypeSafeConfigBuilder::new()
1742            .float_field("value", 150.0)
1743            .with_constraint(
1744                "value",
1745                ValueConstraint::Range {
1746                    min: 0.0,
1747                    max: 100.0,
1748                },
1749            );
1750
1751        let result = builder.build();
1752        assert!(result.is_err());
1753    }
1754
1755    #[test]
1756    fn test_constraint_length() {
1757        let builder = TypeSafeConfigBuilder::new()
1758            .string_field("name", "a") // Too short
1759            .with_constraint(
1760                "name",
1761                ValueConstraint::Length {
1762                    min: 3,
1763                    max: Some(10),
1764                },
1765            );
1766
1767        let result = builder.build();
1768        assert!(result.is_err());
1769    }
1770}