reasonkit/thinktool/
validation_executor.rs

1//! DeepSeek Protocol Validation Engine - Protocol Integration
2//!
3//! **Built-in protocol integration for enterprise-grade reasoning chain validation**
4//!
5//! This module extends the existing ProtocolExecutor with DeepSeek-powered
6//! validation capabilities that validate complete reasoning chains with 671B scale expertise.
7
8use crate::error::{Error, Result};
9use serde::{Deserialize, Serialize};
10
11use super::{
12    executor::{ExecutorConfig, ProtocolExecutor, ProtocolInput, ProtocolOutput},
13    protocol::Protocol,
14    validation::{DeepSeekValidationEngine, DeepSeekValidationResult, ValidationVerdict},
15};
16
17/// Enhanced protocol executor with DeepSeek validation
18pub struct ValidatingProtocolExecutor {
19    base_executor: ProtocolExecutor,
20    validation_engine: Option<DeepSeekValidationEngine>,
21    validation_config: ValidationExecutorConfig,
22}
23
24/// Configuration for validation-enhanced execution
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ValidationExecutorConfig {
27    /// Enable DeepSeek validation
28    #[serde(default)]
29    pub enable_validation: bool,
30
31    /// Validation level
32    #[serde(default)]
33    pub validation_level: ValidationLevel,
34
35    /// Minimum chain confidence threshold for validation
36    #[serde(default = "default_min_confidence_threshold")]
37    pub min_confidence_threshold: f64,
38
39    /// Enable validation for specific protocols only
40    #[serde(default)]
41    pub validate_protocols: Vec<String>,
42
43    /// Skip validation for specific protocols
44    #[serde(default)]
45    pub skip_protocols: Vec<String>,
46}
47
48fn default_min_confidence_threshold() -> f64 {
49    0.70
50}
51
52/// Validation levels
53#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub enum ValidationLevel {
56    None,
57    Quick,
58    #[default]
59    Standard,
60    Rigorous,
61    Paranoid,
62}
63
64impl Default for ValidationExecutorConfig {
65    fn default() -> Self {
66        Self {
67            enable_validation: true,
68            validation_level: ValidationLevel::Standard,
69            min_confidence_threshold: default_min_confidence_threshold(),
70            validate_protocols: Vec::new(),
71            skip_protocols: Vec::new(),
72        }
73    }
74}
75
76impl ValidatingProtocolExecutor {
77    /// Create a new validating executor with default configuration
78    pub fn new() -> Result<Self> {
79        Self::with_configs(
80            ExecutorConfig::default(),
81            ValidationExecutorConfig::default(),
82        )
83    }
84
85    /// Create with custom configurations
86    pub fn with_configs(
87        executor_config: ExecutorConfig,
88        validation_config: ValidationExecutorConfig,
89    ) -> Result<Self> {
90        let base_executor = ProtocolExecutor::with_config(executor_config)?;
91
92        let validation_engine = if validation_config.enable_validation {
93            Some(DeepSeekValidationEngine::new()?)
94        } else {
95            None
96        };
97
98        Ok(Self {
99            base_executor,
100            validation_engine,
101            validation_config,
102        })
103    }
104
105    /// Execute protocol with DeepSeek validation
106    pub async fn execute_with_validation(
107        &self,
108        protocol_id: &str,
109        input: ProtocolInput,
110    ) -> Result<ProtocolOutput> {
111        // First, execute the protocol normally
112        let base_result = self
113            .base_executor
114            .execute(protocol_id, input.clone())
115            .await?;
116
117        // Check if validation should be applied
118        if !self.should_validate(protocol_id, &base_result) {
119            return Ok(base_result);
120        }
121
122        // Apply DeepSeek validation
123        let validation_result = self
124            .apply_validation(protocol_id, &input, &base_result)
125            .await?;
126
127        // Integrate validation results
128        self.merge_validation_results(base_result, validation_result)
129    }
130
131    /// Execute profile with DeepSeek validation
132    pub async fn execute_profile_with_validation(
133        &self,
134        profile_id: &str,
135        input: ProtocolInput,
136    ) -> Result<ProtocolOutput> {
137        // Execute profile normally
138        let base_result = self
139            .base_executor
140            .execute_profile(profile_id, input.clone())
141            .await?;
142
143        // Check if validation should be applied
144        if !self.should_validate_profile(profile_id, &base_result) {
145            return Ok(base_result);
146        }
147
148        // Apply DeepSeek validation
149        let validation_result = self
150            .apply_validation(profile_id, &input, &base_result)
151            .await?;
152
153        // Integrate validation results
154        self.merge_validation_results(base_result, validation_result)
155    }
156
157    /// Check if validation should be applied to a protocol
158    fn should_validate(&self, protocol_id: &str, result: &ProtocolOutput) -> bool {
159        if !self.validation_config.enable_validation {
160            return false;
161        }
162
163        if self.validation_config.validation_level == ValidationLevel::None {
164            return false;
165        }
166
167        // Check protocol-specific settings
168        if !self.validation_config.validate_protocols.is_empty()
169            && !self
170                .validation_config
171                .validate_protocols
172                .contains(&protocol_id.to_string())
173        {
174            return false;
175        }
176
177        if self
178            .validation_config
179            .skip_protocols
180            .contains(&protocol_id.to_string())
181        {
182            return false;
183        }
184
185        // Check confidence threshold
186        if result.confidence < self.validation_config.min_confidence_threshold {
187            return false; // Too low confidence - focus on improvement
188        }
189
190        true
191    }
192
193    /// Check if validation should be applied to a profile
194    fn should_validate_profile(&self, profile_id: &str, result: &ProtocolOutput) -> bool {
195        if !self.validation_config.enable_validation {
196            return false;
197        }
198
199        // Profiles might have different validation criteria
200        match profile_id {
201            "paranoid" | "deep" => true, // Always validate high-stakes profiles
202            "quick" => self.validation_config.validation_level != ValidationLevel::None,
203            _ => result.confidence >= self.validation_config.min_confidence_threshold,
204        }
205    }
206
207    /// Apply DeepSeek validation to protocol results
208    async fn apply_validation(
209        &self,
210        _target_id: &str,
211        original_input: &ProtocolInput,
212        protocol_result: &ProtocolOutput,
213    ) -> Result<DeepSeekValidationResult> {
214        let validation_engine = self
215            .validation_engine
216            .as_ref()
217            .ok_or_else(|| Error::Config("Validation engine not available".into()))?;
218
219        match self.validation_config.validation_level {
220            ValidationLevel::Quick => {
221                validation_engine
222                    .validate_quick(protocol_result, original_input)
223                    .await
224            }
225            ValidationLevel::Standard => {
226                // Use default trace (empty for now - could be enhanced)
227                validation_engine
228                    .validate_chain(protocol_result, original_input, &Default::default())
229                    .await
230            }
231            ValidationLevel::Rigorous => {
232                validation_engine
233                    .validate_rigorous(protocol_result, original_input, &Default::default())
234                    .await
235            }
236            ValidationLevel::Paranoid => {
237                // Paranoid level applies all validation techniques
238                validation_engine
239                    .validate_with_statistical_significance(
240                        protocol_result,
241                        original_input,
242                        &Default::default(),
243                    )
244                    .await
245            }
246            ValidationLevel::None => {
247                unreachable!("ValidationLevel::None should be filtered earlier")
248            }
249        }
250    }
251
252    /// Merge validation results into protocol output
253    fn merge_validation_results(
254        &self,
255        mut base_result: ProtocolOutput,
256        validation_result: DeepSeekValidationResult,
257    ) -> Result<ProtocolOutput> {
258        // Add validation metadata to output
259        base_result.data.insert(
260            "deepseek_validation".into(),
261            serde_json::to_value(&validation_result)?,
262        );
263
264        // Adjust overall confidence based on validation results
265        let validation_impact = match validation_result.verdict {
266            ValidationVerdict::Validated => 1.10, // Boost confidence for validated results
267            ValidationVerdict::PartiallyValidated => 1.00, // Neutral
268            ValidationVerdict::NeedsImprovement => 0.85, // Moderate penalty
269            ValidationVerdict::Invalid => 0.60,   // Significant penalty
270            ValidationVerdict::CriticalIssues => 0.30, // Severe penalty
271        };
272
273        base_result.confidence = (base_result.confidence * validation_impact).clamp(0.0, 1.0);
274
275        // Add validation performance metrics
276        let tokens_used = super::step::TokenUsage {
277            input_tokens: validation_result.tokens_used.input_tokens,
278            output_tokens: validation_result.tokens_used.output_tokens,
279            total_tokens: validation_result.tokens_used.total_tokens,
280            cost_usd: validation_result.tokens_used.cost_usd,
281        };
282        base_result.tokens.add(&tokens_used);
283        base_result.duration_ms += validation_result.performance.duration_ms;
284
285        Ok(base_result)
286    }
287
288    /// Delegate to base executor methods
289    pub fn list_protocols(&self) -> Vec<&str> {
290        self.base_executor.list_protocols()
291    }
292
293    pub fn list_profiles(&self) -> Vec<&str> {
294        self.base_executor.list_profiles()
295    }
296
297    pub fn get_protocol(&self, id: &str) -> Option<&Protocol> {
298        self.base_executor.get_protocol(id)
299    }
300
301    pub fn get_profile(&self, id: &str) -> Option<super::profiles::ReasoningProfile> {
302        self.base_executor.get_profile(id).cloned()
303    }
304}
305
306impl Default for ValidatingProtocolExecutor {
307    fn default() -> Self {
308        Self::new().expect("Failed to create default validating executor")
309    }
310}
311
312/// Configuration helpers for common validation scenarios
313impl ValidationExecutorConfig {
314    /// Create configuration for enterprise deployment
315    pub fn enterprise() -> Self {
316        Self {
317            enable_validation: true,
318            validation_level: ValidationLevel::Rigorous,
319            min_confidence_threshold: 0.80,
320            validate_protocols: vec![
321                "proofguard".into(),
322                "brutalhonesty".into(),
323                "laserlogic".into(),
324            ],
325            skip_protocols: Vec::new(),
326        }
327    }
328
329    /// Create configuration for research applications
330    pub fn research() -> Self {
331        Self {
332            enable_validation: true,
333            validation_level: ValidationLevel::Paranoid,
334            min_confidence_threshold: 0.90,
335            validate_protocols: vec!["gigathink".into(), "scientific".into()],
336            skip_protocols: Vec::new(),
337        }
338    }
339
340    /// Create configuration for production applications
341    pub fn production() -> Self {
342        Self {
343            enable_validation: true,
344            validation_level: ValidationLevel::Standard,
345            min_confidence_threshold: 0.70,
346            validate_protocols: Vec::new(),
347            skip_protocols: vec!["quick".into()],
348        }
349    }
350
351    /// Create configuration for compliance applications
352    pub fn compliance() -> Self {
353        Self {
354            enable_validation: true,
355            validation_level: ValidationLevel::Rigorous,
356            min_confidence_threshold: 0.85,
357            validate_protocols: vec!["proofguard".into(), "brutalhonesty".into()],
358            skip_protocols: vec!["gigathink".into(), "quick".into()],
359        }
360    }
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366    use crate::thinktool::step::TokenUsage;
367    use crate::thinktool::validation::{
368        ChainIntegrityResult, DependencyStatus, LogicalFlowStatus, ProgressionStatus,
369        ValidationPerformance,
370    };
371    use std::collections::HashMap;
372
373    // =========================================================================
374    // CONFIGURATION TESTS
375    // =========================================================================
376
377    #[test]
378    fn test_default_validation_executor_config() {
379        let config = ValidationExecutorConfig::default();
380
381        assert!(config.enable_validation);
382        assert_eq!(config.validation_level, ValidationLevel::Standard);
383        assert!((config.min_confidence_threshold - 0.70).abs() < f64::EPSILON);
384        assert!(config.validate_protocols.is_empty());
385        assert!(config.skip_protocols.is_empty());
386    }
387
388    #[test]
389    fn test_enterprise_configuration() {
390        let config = ValidationExecutorConfig::enterprise();
391
392        assert!(config.enable_validation);
393        assert_eq!(config.validation_level, ValidationLevel::Rigorous);
394        assert!((config.min_confidence_threshold - 0.80).abs() < f64::EPSILON);
395        assert!(config
396            .validate_protocols
397            .contains(&"proofguard".to_string()));
398        assert!(config
399            .validate_protocols
400            .contains(&"brutalhonesty".to_string()));
401        assert!(config
402            .validate_protocols
403            .contains(&"laserlogic".to_string()));
404        assert!(config.skip_protocols.is_empty());
405    }
406
407    #[test]
408    fn test_research_configuration() {
409        let config = ValidationExecutorConfig::research();
410
411        assert!(config.enable_validation);
412        assert_eq!(config.validation_level, ValidationLevel::Paranoid);
413        assert!((config.min_confidence_threshold - 0.90).abs() < f64::EPSILON);
414        assert!(config.validate_protocols.contains(&"gigathink".to_string()));
415        assert!(config
416            .validate_protocols
417            .contains(&"scientific".to_string()));
418    }
419
420    #[test]
421    fn test_production_configuration() {
422        let config = ValidationExecutorConfig::production();
423
424        assert!(config.enable_validation);
425        assert_eq!(config.validation_level, ValidationLevel::Standard);
426        assert!((config.min_confidence_threshold - 0.70).abs() < f64::EPSILON);
427        assert!(config.validate_protocols.is_empty());
428        assert!(config.skip_protocols.contains(&"quick".to_string()));
429    }
430
431    #[test]
432    fn test_compliance_configuration() {
433        let config = ValidationExecutorConfig::compliance();
434
435        assert!(config.enable_validation);
436        assert_eq!(config.validation_level, ValidationLevel::Rigorous);
437        assert!((config.min_confidence_threshold - 0.85).abs() < f64::EPSILON);
438        assert!(config
439            .validate_protocols
440            .contains(&"proofguard".to_string()));
441        assert!(config
442            .validate_protocols
443            .contains(&"brutalhonesty".to_string()));
444        assert!(config.skip_protocols.contains(&"gigathink".to_string()));
445        assert!(config.skip_protocols.contains(&"quick".to_string()));
446    }
447
448    #[test]
449    fn test_validation_level_default() {
450        let level = ValidationLevel::default();
451        assert_eq!(level, ValidationLevel::Standard);
452    }
453
454    #[test]
455    fn test_validation_level_equality() {
456        assert_eq!(ValidationLevel::None, ValidationLevel::None);
457        assert_eq!(ValidationLevel::Quick, ValidationLevel::Quick);
458        assert_eq!(ValidationLevel::Standard, ValidationLevel::Standard);
459        assert_eq!(ValidationLevel::Rigorous, ValidationLevel::Rigorous);
460        assert_eq!(ValidationLevel::Paranoid, ValidationLevel::Paranoid);
461
462        assert_ne!(ValidationLevel::None, ValidationLevel::Quick);
463        assert_ne!(ValidationLevel::Quick, ValidationLevel::Standard);
464        assert_ne!(ValidationLevel::Standard, ValidationLevel::Rigorous);
465        assert_ne!(ValidationLevel::Rigorous, ValidationLevel::Paranoid);
466    }
467
468    #[test]
469    fn test_config_serialization() {
470        let config = ValidationExecutorConfig::enterprise();
471        let json = serde_json::to_string(&config).expect("Failed to serialize config");
472
473        assert!(json.contains("enable_validation"));
474        assert!(json.contains("rigorous"));
475        assert!(json.contains("proofguard"));
476
477        let deserialized: ValidationExecutorConfig =
478            serde_json::from_str(&json).expect("Failed to deserialize config");
479
480        assert_eq!(deserialized.validation_level, config.validation_level);
481        assert_eq!(
482            deserialized.min_confidence_threshold,
483            config.min_confidence_threshold
484        );
485    }
486
487    // =========================================================================
488    // EXECUTOR CREATION TESTS
489    // =========================================================================
490
491    #[tokio::test]
492    async fn test_executor_creation_with_default_config() {
493        let executor = ValidatingProtocolExecutor::new().unwrap();
494
495        // Verify executor has protocols loaded
496        let protocols = executor.list_protocols();
497        assert!(protocols.contains(&"gigathink"));
498        assert!(protocols.contains(&"laserlogic"));
499        assert!(protocols.contains(&"bedrock"));
500    }
501
502    #[tokio::test]
503    async fn test_executor_creation_with_mock_config() {
504        let executor_config = ExecutorConfig::mock();
505        let validation_config = ValidationExecutorConfig::default();
506
507        let executor =
508            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
509
510        assert!(!executor.list_protocols().is_empty());
511        assert!(!executor.list_profiles().is_empty());
512    }
513
514    #[tokio::test]
515    async fn test_executor_creation_with_disabled_validation() {
516        let executor_config = ExecutorConfig::mock();
517        let validation_config = ValidationExecutorConfig {
518            enable_validation: false,
519            ..Default::default()
520        };
521
522        let executor =
523            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
524
525        // Executor should still work, just without validation engine
526        assert!(!executor.list_protocols().is_empty());
527    }
528
529    #[test]
530    fn test_executor_list_protocols() {
531        let executor = ValidatingProtocolExecutor::new().unwrap();
532        let protocols = executor.list_protocols();
533
534        // Should contain all built-in protocols
535        assert!(protocols.contains(&"gigathink"));
536        assert!(protocols.contains(&"laserlogic"));
537        assert!(protocols.contains(&"bedrock"));
538        assert!(protocols.contains(&"proofguard"));
539        assert!(protocols.contains(&"brutalhonesty"));
540    }
541
542    #[test]
543    fn test_executor_list_profiles() {
544        let executor = ValidatingProtocolExecutor::new().unwrap();
545        let profiles = executor.list_profiles();
546
547        // Should contain all built-in profiles
548        assert!(profiles.contains(&"quick"));
549        assert!(profiles.contains(&"balanced"));
550        assert!(profiles.contains(&"deep"));
551        assert!(profiles.contains(&"paranoid"));
552    }
553
554    #[test]
555    fn test_executor_get_protocol() {
556        let executor = ValidatingProtocolExecutor::new().unwrap();
557
558        let protocol = executor.get_protocol("gigathink");
559        assert!(protocol.is_some());
560        assert_eq!(protocol.unwrap().id, "gigathink");
561
562        let missing = executor.get_protocol("nonexistent");
563        assert!(missing.is_none());
564    }
565
566    #[test]
567    fn test_executor_get_profile() {
568        let executor = ValidatingProtocolExecutor::new().unwrap();
569
570        let profile = executor.get_profile("balanced");
571        assert!(profile.is_some());
572
573        let missing = executor.get_profile("nonexistent");
574        assert!(missing.is_none());
575    }
576
577    // =========================================================================
578    // VALIDATION RULES TESTS (should_validate)
579    // =========================================================================
580
581    /// Helper function to create a mock ProtocolOutput for testing
582    fn create_mock_output(protocol_id: &str, confidence: f64) -> ProtocolOutput {
583        ProtocolOutput {
584            protocol_id: protocol_id.to_string(),
585            success: true,
586            data: HashMap::new(),
587            confidence,
588            steps: vec![],
589            tokens: TokenUsage::default(),
590            duration_ms: 100,
591            error: None,
592            trace_id: None,
593            budget_summary: None,
594        }
595    }
596
597    #[test]
598    fn test_should_validate_disabled_validation() {
599        let executor_config = ExecutorConfig::mock();
600        let validation_config = ValidationExecutorConfig {
601            enable_validation: false,
602            ..Default::default()
603        };
604
605        let executor =
606            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
607
608        let output = create_mock_output("gigathink", 0.85);
609        assert!(!executor.should_validate("gigathink", &output));
610    }
611
612    #[test]
613    fn test_should_validate_with_none_level() {
614        let executor_config = ExecutorConfig::mock();
615        let validation_config = ValidationExecutorConfig {
616            enable_validation: true,
617            validation_level: ValidationLevel::None,
618            ..Default::default()
619        };
620
621        let executor =
622            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
623
624        let output = create_mock_output("gigathink", 0.85);
625        assert!(!executor.should_validate("gigathink", &output));
626    }
627
628    #[test]
629    fn test_should_validate_with_specific_protocols() {
630        let executor_config = ExecutorConfig::mock();
631        let validation_config = ValidationExecutorConfig {
632            enable_validation: true,
633            validation_level: ValidationLevel::Standard,
634            validate_protocols: vec!["proofguard".to_string(), "laserlogic".to_string()],
635            ..Default::default()
636        };
637
638        let executor =
639            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
640
641        // Should validate protocols in the list
642        let output_proofguard = create_mock_output("proofguard", 0.85);
643        assert!(executor.should_validate("proofguard", &output_proofguard));
644
645        // Should NOT validate protocols not in the list
646        let output_gigathink = create_mock_output("gigathink", 0.85);
647        assert!(!executor.should_validate("gigathink", &output_gigathink));
648    }
649
650    #[test]
651    fn test_should_validate_with_skip_protocols() {
652        let executor_config = ExecutorConfig::mock();
653        let validation_config = ValidationExecutorConfig {
654            enable_validation: true,
655            validation_level: ValidationLevel::Standard,
656            skip_protocols: vec!["quick".to_string()],
657            ..Default::default()
658        };
659
660        let executor =
661            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
662
663        // Should NOT validate skipped protocols
664        let output_quick = create_mock_output("quick", 0.85);
665        assert!(!executor.should_validate("quick", &output_quick));
666
667        // Should validate non-skipped protocols
668        let output_gigathink = create_mock_output("gigathink", 0.85);
669        assert!(executor.should_validate("gigathink", &output_gigathink));
670    }
671
672    #[test]
673    fn test_should_validate_below_confidence_threshold() {
674        let executor_config = ExecutorConfig::mock();
675        let validation_config = ValidationExecutorConfig {
676            enable_validation: true,
677            validation_level: ValidationLevel::Standard,
678            min_confidence_threshold: 0.80,
679            ..Default::default()
680        };
681
682        let executor =
683            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
684
685        // Below threshold - should NOT validate
686        let output_low_confidence = create_mock_output("gigathink", 0.75);
687        assert!(!executor.should_validate("gigathink", &output_low_confidence));
688
689        // At threshold - should validate
690        let output_at_threshold = create_mock_output("gigathink", 0.80);
691        assert!(executor.should_validate("gigathink", &output_at_threshold));
692
693        // Above threshold - should validate
694        let output_high_confidence = create_mock_output("gigathink", 0.90);
695        assert!(executor.should_validate("gigathink", &output_high_confidence));
696    }
697
698    #[test]
699    fn test_should_validate_all_conditions_met() {
700        let executor_config = ExecutorConfig::mock();
701        let validation_config = ValidationExecutorConfig {
702            enable_validation: true,
703            validation_level: ValidationLevel::Standard,
704            min_confidence_threshold: 0.70,
705            validate_protocols: Vec::new(), // Empty = all protocols
706            skip_protocols: Vec::new(),
707        };
708
709        let executor =
710            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
711
712        let output = create_mock_output("gigathink", 0.85);
713        assert!(executor.should_validate("gigathink", &output));
714    }
715
716    // =========================================================================
717    // VALIDATION RULES TESTS (should_validate_profile)
718    // =========================================================================
719
720    #[test]
721    fn test_should_validate_profile_disabled() {
722        let executor_config = ExecutorConfig::mock();
723        let validation_config = ValidationExecutorConfig {
724            enable_validation: false,
725            ..Default::default()
726        };
727
728        let executor =
729            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
730
731        let output = create_mock_output("paranoid", 0.95);
732        assert!(!executor.should_validate_profile("paranoid", &output));
733    }
734
735    #[test]
736    fn test_should_validate_profile_paranoid_always() {
737        let executor_config = ExecutorConfig::mock();
738        let validation_config = ValidationExecutorConfig {
739            enable_validation: true,
740            validation_level: ValidationLevel::Standard,
741            min_confidence_threshold: 0.99, // Very high threshold
742            ..Default::default()
743        };
744
745        let executor =
746            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
747
748        // Paranoid profile should ALWAYS validate regardless of confidence
749        let output = create_mock_output("paranoid", 0.50);
750        assert!(executor.should_validate_profile("paranoid", &output));
751    }
752
753    #[test]
754    fn test_should_validate_profile_deep_always() {
755        let executor_config = ExecutorConfig::mock();
756        let validation_config = ValidationExecutorConfig {
757            enable_validation: true,
758            validation_level: ValidationLevel::Standard,
759            min_confidence_threshold: 0.99,
760            ..Default::default()
761        };
762
763        let executor =
764            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
765
766        // Deep profile should ALWAYS validate regardless of confidence
767        let output = create_mock_output("deep", 0.50);
768        assert!(executor.should_validate_profile("deep", &output));
769    }
770
771    #[test]
772    fn test_should_validate_profile_quick_with_level() {
773        let executor_config = ExecutorConfig::mock();
774        let validation_config = ValidationExecutorConfig {
775            enable_validation: true,
776            validation_level: ValidationLevel::Standard,
777            ..Default::default()
778        };
779
780        let executor =
781            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
782
783        // Quick profile should validate when level is not None
784        let output = create_mock_output("quick", 0.50);
785        assert!(executor.should_validate_profile("quick", &output));
786    }
787
788    #[test]
789    fn test_should_validate_profile_quick_with_none_level() {
790        let executor_config = ExecutorConfig::mock();
791        let validation_config = ValidationExecutorConfig {
792            enable_validation: true,
793            validation_level: ValidationLevel::None,
794            ..Default::default()
795        };
796
797        let executor =
798            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
799
800        // Quick profile should NOT validate when level is None
801        let output = create_mock_output("quick", 0.90);
802        assert!(!executor.should_validate_profile("quick", &output));
803    }
804
805    #[test]
806    fn test_should_validate_profile_other_profiles_use_threshold() {
807        let executor_config = ExecutorConfig::mock();
808        let validation_config = ValidationExecutorConfig {
809            enable_validation: true,
810            validation_level: ValidationLevel::Standard,
811            min_confidence_threshold: 0.80,
812            ..Default::default()
813        };
814
815        let executor =
816            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
817
818        // Other profiles should use confidence threshold
819        let output_low = create_mock_output("balanced", 0.75);
820        assert!(!executor.should_validate_profile("balanced", &output_low));
821
822        let output_high = create_mock_output("balanced", 0.85);
823        assert!(executor.should_validate_profile("balanced", &output_high));
824    }
825
826    // =========================================================================
827    // CONFIDENCE ADJUSTMENT TESTS (merge_validation_results)
828    // =========================================================================
829
830    /// Helper function to create a mock DeepSeekValidationResult
831    fn create_mock_validation_result(verdict: ValidationVerdict) -> DeepSeekValidationResult {
832        use crate::thinktool::validation::TokenUsage as ValidationTokenUsage;
833
834        DeepSeekValidationResult {
835            verdict,
836            chain_integrity: ChainIntegrityResult {
837                logical_flow: LogicalFlowStatus::Good,
838                step_dependencies: DependencyStatus::FullySatisfied,
839                confidence_progression: ProgressionStatus::Monotonic,
840                gaps_detected: vec![],
841                continuity_score: 0.85,
842            },
843            statistical_results: None,
844            compliance_results: None,
845            meta_cognitive_results: None,
846            validation_confidence: 0.90,
847            findings: vec![],
848            tokens_used: ValidationTokenUsage {
849                input_tokens: 100,
850                output_tokens: 50,
851                total_tokens: 150,
852                cost_usd: 0.002,
853            },
854            performance: ValidationPerformance {
855                duration_ms: 500,
856                tokens_per_second: 300.0,
857                memory_usage_mb: 50.0,
858            },
859        }
860    }
861
862    #[test]
863    fn test_merge_validation_results_validated_boosts_confidence() {
864        let executor_config = ExecutorConfig::mock();
865        let validation_config = ValidationExecutorConfig::default();
866        let executor =
867            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
868
869        let base_result = create_mock_output("gigathink", 0.80);
870        let validation_result = create_mock_validation_result(ValidationVerdict::Validated);
871
872        let merged = executor
873            .merge_validation_results(base_result, validation_result)
874            .unwrap();
875
876        // Validated verdict should boost confidence by 10% (clamped to 1.0)
877        // 0.80 * 1.10 = 0.88
878        assert!((merged.confidence - 0.88).abs() < 0.001);
879    }
880
881    #[test]
882    fn test_merge_validation_results_validated_clamps_to_one() {
883        let executor_config = ExecutorConfig::mock();
884        let validation_config = ValidationExecutorConfig::default();
885        let executor =
886            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
887
888        let base_result = create_mock_output("gigathink", 0.95);
889        let validation_result = create_mock_validation_result(ValidationVerdict::Validated);
890
891        let merged = executor
892            .merge_validation_results(base_result, validation_result)
893            .unwrap();
894
895        // 0.95 * 1.10 = 1.045 -> clamped to 1.0
896        assert!((merged.confidence - 1.0).abs() < f64::EPSILON);
897    }
898
899    #[test]
900    fn test_merge_validation_results_partially_validated_neutral() {
901        let executor_config = ExecutorConfig::mock();
902        let validation_config = ValidationExecutorConfig::default();
903        let executor =
904            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
905
906        let base_result = create_mock_output("gigathink", 0.80);
907        let validation_result =
908            create_mock_validation_result(ValidationVerdict::PartiallyValidated);
909
910        let merged = executor
911            .merge_validation_results(base_result, validation_result)
912            .unwrap();
913
914        // PartiallyValidated verdict is neutral (1.0 multiplier)
915        // 0.80 * 1.00 = 0.80
916        assert!((merged.confidence - 0.80).abs() < f64::EPSILON);
917    }
918
919    #[test]
920    fn test_merge_validation_results_needs_improvement_reduces() {
921        let executor_config = ExecutorConfig::mock();
922        let validation_config = ValidationExecutorConfig::default();
923        let executor =
924            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
925
926        let base_result = create_mock_output("gigathink", 0.80);
927        let validation_result = create_mock_validation_result(ValidationVerdict::NeedsImprovement);
928
929        let merged = executor
930            .merge_validation_results(base_result, validation_result)
931            .unwrap();
932
933        // NeedsImprovement reduces by 15%
934        // 0.80 * 0.85 = 0.68
935        assert!((merged.confidence - 0.68).abs() < 0.001);
936    }
937
938    #[test]
939    fn test_merge_validation_results_invalid_significantly_reduces() {
940        let executor_config = ExecutorConfig::mock();
941        let validation_config = ValidationExecutorConfig::default();
942        let executor =
943            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
944
945        let base_result = create_mock_output("gigathink", 0.80);
946        let validation_result = create_mock_validation_result(ValidationVerdict::Invalid);
947
948        let merged = executor
949            .merge_validation_results(base_result, validation_result)
950            .unwrap();
951
952        // Invalid reduces by 40%
953        // 0.80 * 0.60 = 0.48
954        assert!((merged.confidence - 0.48).abs() < 0.001);
955    }
956
957    #[test]
958    fn test_merge_validation_results_critical_issues_severely_reduces() {
959        let executor_config = ExecutorConfig::mock();
960        let validation_config = ValidationExecutorConfig::default();
961        let executor =
962            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
963
964        let base_result = create_mock_output("gigathink", 0.80);
965        let validation_result = create_mock_validation_result(ValidationVerdict::CriticalIssues);
966
967        let merged = executor
968            .merge_validation_results(base_result, validation_result)
969            .unwrap();
970
971        // CriticalIssues reduces by 70%
972        // 0.80 * 0.30 = 0.24
973        assert!((merged.confidence - 0.24).abs() < 0.001);
974    }
975
976    #[test]
977    fn test_merge_validation_results_adds_metadata() {
978        let executor_config = ExecutorConfig::mock();
979        let validation_config = ValidationExecutorConfig::default();
980        let executor =
981            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
982
983        let base_result = create_mock_output("gigathink", 0.80);
984        let validation_result = create_mock_validation_result(ValidationVerdict::Validated);
985
986        let merged = executor
987            .merge_validation_results(base_result, validation_result)
988            .unwrap();
989
990        // Should contain validation metadata
991        assert!(merged.data.contains_key("deepseek_validation"));
992    }
993
994    #[test]
995    fn test_merge_validation_results_adds_tokens() {
996        let executor_config = ExecutorConfig::mock();
997        let validation_config = ValidationExecutorConfig::default();
998        let executor =
999            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1000
1001        let mut base_result = create_mock_output("gigathink", 0.80);
1002        base_result.tokens = TokenUsage::new(200, 100, 0.003);
1003
1004        let validation_result = create_mock_validation_result(ValidationVerdict::Validated);
1005
1006        let merged = executor
1007            .merge_validation_results(base_result, validation_result)
1008            .unwrap();
1009
1010        // Tokens should be added: base + validation
1011        // Input: 200 + 100 = 300
1012        // Output: 100 + 50 = 150
1013        assert_eq!(merged.tokens.input_tokens, 300);
1014        assert_eq!(merged.tokens.output_tokens, 150);
1015        assert_eq!(merged.tokens.total_tokens, 450);
1016    }
1017
1018    #[test]
1019    fn test_merge_validation_results_adds_duration() {
1020        let executor_config = ExecutorConfig::mock();
1021        let validation_config = ValidationExecutorConfig::default();
1022        let executor =
1023            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1024
1025        let mut base_result = create_mock_output("gigathink", 0.80);
1026        base_result.duration_ms = 1000;
1027
1028        let validation_result = create_mock_validation_result(ValidationVerdict::Validated);
1029
1030        let merged = executor
1031            .merge_validation_results(base_result, validation_result)
1032            .unwrap();
1033
1034        // Duration should be added: 1000 + 500 = 1500
1035        assert_eq!(merged.duration_ms, 1500);
1036    }
1037
1038    // =========================================================================
1039    // EXECUTION FLOW TESTS (with mock)
1040    // =========================================================================
1041
1042    #[tokio::test]
1043    async fn test_execute_with_mock_returns_success() {
1044        let executor_config = ExecutorConfig::mock();
1045        let validation_config = ValidationExecutorConfig {
1046            enable_validation: false, // Disable to avoid DeepSeek API call
1047            ..Default::default()
1048        };
1049
1050        let executor =
1051            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1052
1053        let input = ProtocolInput::query("What is machine learning?");
1054        let result = executor
1055            .execute_with_validation("gigathink", input)
1056            .await
1057            .unwrap();
1058
1059        assert!(result.success);
1060        assert!(result.confidence > 0.0);
1061        assert!(!result.steps.is_empty());
1062    }
1063
1064    #[tokio::test]
1065    async fn test_execute_profile_with_mock_returns_success() {
1066        let executor_config = ExecutorConfig::mock();
1067        let validation_config = ValidationExecutorConfig {
1068            enable_validation: false, // Disable to avoid DeepSeek API call
1069            ..Default::default()
1070        };
1071
1072        let executor =
1073            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1074
1075        let input = ProtocolInput::query("Should we use microservices?");
1076        let result = executor
1077            .execute_profile_with_validation("quick", input)
1078            .await
1079            .unwrap();
1080
1081        assert!(result.success);
1082        assert!(result.confidence > 0.0);
1083    }
1084
1085    #[tokio::test]
1086    async fn test_execute_nonexistent_protocol_returns_error() {
1087        let executor_config = ExecutorConfig::mock();
1088        let validation_config = ValidationExecutorConfig {
1089            enable_validation: false,
1090            ..Default::default()
1091        };
1092
1093        let executor =
1094            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1095
1096        let input = ProtocolInput::query("Test query");
1097        let result = executor
1098            .execute_with_validation("nonexistent_protocol", input)
1099            .await;
1100
1101        assert!(result.is_err());
1102    }
1103
1104    #[tokio::test]
1105    async fn test_execute_nonexistent_profile_returns_error() {
1106        let executor_config = ExecutorConfig::mock();
1107        let validation_config = ValidationExecutorConfig {
1108            enable_validation: false,
1109            ..Default::default()
1110        };
1111
1112        let executor =
1113            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1114
1115        let input = ProtocolInput::query("Test query");
1116        let result = executor
1117            .execute_profile_with_validation("nonexistent_profile", input)
1118            .await;
1119
1120        assert!(result.is_err());
1121    }
1122
1123    // =========================================================================
1124    // ERROR REPORTING TESTS
1125    // =========================================================================
1126
1127    #[test]
1128    fn test_validation_engine_not_available_error() {
1129        // Create executor with validation disabled (no engine)
1130        let executor_config = ExecutorConfig::mock();
1131        let validation_config = ValidationExecutorConfig {
1132            enable_validation: false,
1133            ..Default::default()
1134        };
1135
1136        let executor =
1137            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1138
1139        // Try to access validation engine directly (should be None)
1140        assert!(executor.validation_engine.is_none());
1141    }
1142
1143    // =========================================================================
1144    // EDGE CASES
1145    // =========================================================================
1146
1147    #[test]
1148    fn test_zero_confidence_output() {
1149        let executor_config = ExecutorConfig::mock();
1150        let validation_config = ValidationExecutorConfig::default();
1151        let executor =
1152            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1153
1154        let output = create_mock_output("gigathink", 0.0);
1155
1156        // Should NOT validate when confidence is 0 (below threshold)
1157        assert!(!executor.should_validate("gigathink", &output));
1158    }
1159
1160    #[test]
1161    fn test_exact_threshold_confidence() {
1162        let executor_config = ExecutorConfig::mock();
1163        let validation_config = ValidationExecutorConfig {
1164            min_confidence_threshold: 0.75,
1165            ..Default::default()
1166        };
1167        let executor =
1168            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1169
1170        // Exactly at threshold should validate
1171        let output = create_mock_output("gigathink", 0.75);
1172        assert!(executor.should_validate("gigathink", &output));
1173    }
1174
1175    #[test]
1176    fn test_just_below_threshold() {
1177        let executor_config = ExecutorConfig::mock();
1178        let validation_config = ValidationExecutorConfig {
1179            min_confidence_threshold: 0.75,
1180            ..Default::default()
1181        };
1182        let executor =
1183            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1184
1185        // Just below threshold should NOT validate
1186        let output = create_mock_output("gigathink", 0.7499999);
1187        assert!(!executor.should_validate("gigathink", &output));
1188    }
1189
1190    #[test]
1191    fn test_empty_validate_protocols_means_all() {
1192        let executor_config = ExecutorConfig::mock();
1193        let validation_config = ValidationExecutorConfig {
1194            enable_validation: true,
1195            validation_level: ValidationLevel::Standard,
1196            validate_protocols: Vec::new(), // Empty = validate all
1197            skip_protocols: Vec::new(),
1198            min_confidence_threshold: 0.0,
1199        };
1200        let executor =
1201            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1202
1203        let output = create_mock_output("any_protocol", 0.50);
1204        assert!(executor.should_validate("any_protocol", &output));
1205    }
1206
1207    #[test]
1208    fn test_skip_takes_precedence_over_validate() {
1209        let executor_config = ExecutorConfig::mock();
1210        let validation_config = ValidationExecutorConfig {
1211            enable_validation: true,
1212            validation_level: ValidationLevel::Standard,
1213            validate_protocols: vec!["gigathink".to_string()],
1214            skip_protocols: vec!["gigathink".to_string()], // Both contain gigathink
1215            min_confidence_threshold: 0.0,
1216        };
1217        let executor =
1218            ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
1219
1220        let output = create_mock_output("gigathink", 0.90);
1221
1222        // Skip should take precedence - should NOT validate
1223        assert!(!executor.should_validate("gigathink", &output));
1224    }
1225
1226    #[test]
1227    fn test_default_executor_via_default_trait() {
1228        // Test that Default trait implementation works
1229        let executor = ValidatingProtocolExecutor::default();
1230        assert!(!executor.list_protocols().is_empty());
1231    }
1232
1233    #[test]
1234    fn test_validation_level_serde_roundtrip() {
1235        for level in [
1236            ValidationLevel::None,
1237            ValidationLevel::Quick,
1238            ValidationLevel::Standard,
1239            ValidationLevel::Rigorous,
1240            ValidationLevel::Paranoid,
1241        ] {
1242            let json = serde_json::to_string(&level).unwrap();
1243            let deserialized: ValidationLevel = serde_json::from_str(&json).unwrap();
1244            assert_eq!(deserialized, level);
1245        }
1246    }
1247
1248    #[test]
1249    fn test_config_with_all_fields_set() {
1250        let config = ValidationExecutorConfig {
1251            enable_validation: true,
1252            validation_level: ValidationLevel::Rigorous,
1253            min_confidence_threshold: 0.95,
1254            validate_protocols: vec!["a".to_string(), "b".to_string()],
1255            skip_protocols: vec!["c".to_string()],
1256        };
1257
1258        assert!(config.enable_validation);
1259        assert_eq!(config.validation_level, ValidationLevel::Rigorous);
1260        assert!((config.min_confidence_threshold - 0.95).abs() < f64::EPSILON);
1261        assert_eq!(config.validate_protocols.len(), 2);
1262        assert_eq!(config.skip_protocols.len(), 1);
1263    }
1264}