1use 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
17pub struct ValidatingProtocolExecutor {
19 base_executor: ProtocolExecutor,
20 validation_engine: Option<DeepSeekValidationEngine>,
21 validation_config: ValidationExecutorConfig,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ValidationExecutorConfig {
27 #[serde(default)]
29 pub enable_validation: bool,
30
31 #[serde(default)]
33 pub validation_level: ValidationLevel,
34
35 #[serde(default = "default_min_confidence_threshold")]
37 pub min_confidence_threshold: f64,
38
39 #[serde(default)]
41 pub validate_protocols: Vec<String>,
42
43 #[serde(default)]
45 pub skip_protocols: Vec<String>,
46}
47
48fn default_min_confidence_threshold() -> f64 {
49 0.70
50}
51
52#[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 pub fn new() -> Result<Self> {
79 Self::with_configs(
80 ExecutorConfig::default(),
81 ValidationExecutorConfig::default(),
82 )
83 }
84
85 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 pub async fn execute_with_validation(
107 &self,
108 protocol_id: &str,
109 input: ProtocolInput,
110 ) -> Result<ProtocolOutput> {
111 let base_result = self
113 .base_executor
114 .execute(protocol_id, input.clone())
115 .await?;
116
117 if !self.should_validate(protocol_id, &base_result) {
119 return Ok(base_result);
120 }
121
122 let validation_result = self
124 .apply_validation(protocol_id, &input, &base_result)
125 .await?;
126
127 self.merge_validation_results(base_result, validation_result)
129 }
130
131 pub async fn execute_profile_with_validation(
133 &self,
134 profile_id: &str,
135 input: ProtocolInput,
136 ) -> Result<ProtocolOutput> {
137 let base_result = self
139 .base_executor
140 .execute_profile(profile_id, input.clone())
141 .await?;
142
143 if !self.should_validate_profile(profile_id, &base_result) {
145 return Ok(base_result);
146 }
147
148 let validation_result = self
150 .apply_validation(profile_id, &input, &base_result)
151 .await?;
152
153 self.merge_validation_results(base_result, validation_result)
155 }
156
157 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 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 if result.confidence < self.validation_config.min_confidence_threshold {
187 return false; }
189
190 true
191 }
192
193 fn should_validate_profile(&self, profile_id: &str, result: &ProtocolOutput) -> bool {
195 if !self.validation_config.enable_validation {
196 return false;
197 }
198
199 match profile_id {
201 "paranoid" | "deep" => true, "quick" => self.validation_config.validation_level != ValidationLevel::None,
203 _ => result.confidence >= self.validation_config.min_confidence_threshold,
204 }
205 }
206
207 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 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 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 fn merge_validation_results(
254 &self,
255 mut base_result: ProtocolOutput,
256 validation_result: DeepSeekValidationResult,
257 ) -> Result<ProtocolOutput> {
258 base_result.data.insert(
260 "deepseek_validation".into(),
261 serde_json::to_value(&validation_result)?,
262 );
263
264 let validation_impact = match validation_result.verdict {
266 ValidationVerdict::Validated => 1.10, ValidationVerdict::PartiallyValidated => 1.00, ValidationVerdict::NeedsImprovement => 0.85, ValidationVerdict::Invalid => 0.60, ValidationVerdict::CriticalIssues => 0.30, };
272
273 base_result.confidence = (base_result.confidence * validation_impact).clamp(0.0, 1.0);
274
275 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 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
312impl ValidationExecutorConfig {
314 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 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 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 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 #[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 #[tokio::test]
492 async fn test_executor_creation_with_default_config() {
493 let executor = ValidatingProtocolExecutor::new().unwrap();
494
495 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 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 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 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 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 let output_proofguard = create_mock_output("proofguard", 0.85);
643 assert!(executor.should_validate("proofguard", &output_proofguard));
644
645 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 let output_quick = create_mock_output("quick", 0.85);
665 assert!(!executor.should_validate("quick", &output_quick));
666
667 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 let output_low_confidence = create_mock_output("gigathink", 0.75);
687 assert!(!executor.should_validate("gigathink", &output_low_confidence));
688
689 let output_at_threshold = create_mock_output("gigathink", 0.80);
691 assert!(executor.should_validate("gigathink", &output_at_threshold));
692
693 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(), 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 #[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, ..Default::default()
743 };
744
745 let executor =
746 ValidatingProtocolExecutor::with_configs(executor_config, validation_config).unwrap();
747
748 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 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 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 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 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 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 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 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 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 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 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 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 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 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 assert_eq!(merged.duration_ms, 1500);
1036 }
1037
1038 #[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, ..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, ..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 #[test]
1128 fn test_validation_engine_not_available_error() {
1129 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 assert!(executor.validation_engine.is_none());
1141 }
1142
1143 #[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 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 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 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(), 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()], 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 assert!(!executor.should_validate("gigathink", &output));
1224 }
1225
1226 #[test]
1227 fn test_default_executor_via_default_trait() {
1228 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}