batuta/oracle/
types.rs

1#![allow(dead_code)]
2//! Oracle Mode type definitions
3//!
4//! Based on Oracle Mode Specification v1.0 (BATUTA-ORACLE-001)
5
6use serde::{Deserialize, Serialize};
7
8// =============================================================================
9// Stack Layer Definitions
10// =============================================================================
11
12/// Layer in the Sovereign AI Stack hierarchy
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub enum StackLayer {
15    /// Layer 0: Compute primitives (trueno, trueno-db, trueno-graph)
16    Primitives,
17    /// Layer 1: ML algorithms (aprender)
18    MlAlgorithms,
19    /// Layer 2: Training & inference (entrenar, realizar)
20    MlPipeline,
21    /// Layer 3: Transpilers (depyler, decy, bashrs)
22    Transpilers,
23    /// Layer 4: Orchestration (batuta, repartir)
24    Orchestration,
25    /// Layer 5: Quality & profiling (certeza, pmat, renacer)
26    Quality,
27    /// Layer 6: Data loading (alimentar)
28    Data,
29}
30
31impl StackLayer {
32    /// Get numeric layer index
33    pub fn index(&self) -> u8 {
34        match self {
35            StackLayer::Primitives => 0,
36            StackLayer::MlAlgorithms => 1,
37            StackLayer::MlPipeline => 2,
38            StackLayer::Transpilers => 3,
39            StackLayer::Orchestration => 4,
40            StackLayer::Quality => 5,
41            StackLayer::Data => 6,
42        }
43    }
44
45    /// Get all layers in order
46    pub fn all() -> Vec<StackLayer> {
47        vec![
48            StackLayer::Primitives,
49            StackLayer::MlAlgorithms,
50            StackLayer::MlPipeline,
51            StackLayer::Transpilers,
52            StackLayer::Orchestration,
53            StackLayer::Quality,
54            StackLayer::Data,
55        ]
56    }
57}
58
59impl std::fmt::Display for StackLayer {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self {
62            StackLayer::Primitives => write!(f, "Compute Primitives"),
63            StackLayer::MlAlgorithms => write!(f, "ML Algorithms"),
64            StackLayer::MlPipeline => write!(f, "Training & Inference"),
65            StackLayer::Transpilers => write!(f, "Transpilers"),
66            StackLayer::Orchestration => write!(f, "Orchestration"),
67            StackLayer::Quality => write!(f, "Quality & Profiling"),
68            StackLayer::Data => write!(f, "Data Loading"),
69        }
70    }
71}
72
73// =============================================================================
74// Capability Definitions
75// =============================================================================
76
77/// Category of capability
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
79pub enum CapabilityCategory {
80    Compute,
81    Storage,
82    MachineLearning,
83    Transpilation,
84    Validation,
85    Profiling,
86    Distribution,
87}
88
89/// A capability provided by a component
90#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
91pub struct Capability {
92    pub name: String,
93    pub category: CapabilityCategory,
94    pub description: Option<String>,
95}
96
97impl Capability {
98    pub fn new(name: impl Into<String>, category: CapabilityCategory) -> Self {
99        Self {
100            name: name.into(),
101            category,
102            description: None,
103        }
104    }
105
106    pub fn with_description(mut self, desc: impl Into<String>) -> Self {
107        self.description = Some(desc.into());
108        self
109    }
110}
111
112// =============================================================================
113// Component Definitions
114// =============================================================================
115
116/// A component in the Sovereign AI Stack
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct StackComponent {
119    /// Component name (e.g., "trueno", "aprender")
120    pub name: String,
121    /// Component version
122    pub version: String,
123    /// Stack layer
124    pub layer: StackLayer,
125    /// Description of component purpose
126    pub description: String,
127    /// Capabilities provided
128    pub capabilities: Vec<Capability>,
129    /// Crates.io package name (if different from name)
130    pub crate_name: Option<String>,
131    /// Academic references
132    pub references: Vec<Citation>,
133}
134
135impl StackComponent {
136    pub fn new(
137        name: impl Into<String>,
138        version: impl Into<String>,
139        layer: StackLayer,
140        description: impl Into<String>,
141    ) -> Self {
142        Self {
143            name: name.into(),
144            version: version.into(),
145            layer,
146            description: description.into(),
147            capabilities: Vec::new(),
148            crate_name: None,
149            references: Vec::new(),
150        }
151    }
152
153    pub fn with_capability(mut self, cap: Capability) -> Self {
154        self.capabilities.push(cap);
155        self
156    }
157
158    pub fn with_capabilities(mut self, caps: Vec<Capability>) -> Self {
159        self.capabilities.extend(caps);
160        self
161    }
162
163    pub fn has_capability(&self, name: &str) -> bool {
164        self.capabilities.iter().any(|c| c.name == name)
165    }
166}
167
168/// Academic citation/reference
169#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct Citation {
171    pub id: u32,
172    pub authors: String,
173    pub year: u16,
174    pub title: String,
175    pub venue: Option<String>,
176}
177
178// =============================================================================
179// Query Types
180// =============================================================================
181
182/// Hardware specification for queries
183#[derive(Debug, Clone, Default, Serialize, Deserialize)]
184pub struct HardwareSpec {
185    pub has_gpu: bool,
186    pub gpu_memory_gb: Option<f32>,
187    pub cpu_cores: Option<u32>,
188    pub ram_gb: Option<f32>,
189    pub is_distributed: bool,
190    pub node_count: Option<u32>,
191}
192
193impl HardwareSpec {
194    pub fn cpu_only() -> Self {
195        Self {
196            has_gpu: false,
197            ..Default::default()
198        }
199    }
200
201    pub fn with_gpu(memory_gb: f32) -> Self {
202        Self {
203            has_gpu: true,
204            gpu_memory_gb: Some(memory_gb),
205            ..Default::default()
206        }
207    }
208
209    pub fn has_gpu(&self) -> bool {
210        self.has_gpu
211    }
212}
213
214/// Data size specification
215#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
216pub enum DataSize {
217    /// Number of samples/rows
218    Samples(u64),
219    /// Size in bytes
220    Bytes(u64),
221    /// Unknown/unspecified
222    Unknown,
223}
224
225impl DataSize {
226    pub fn samples(n: u64) -> Self {
227        DataSize::Samples(n)
228    }
229
230    pub fn bytes(n: u64) -> Self {
231        DataSize::Bytes(n)
232    }
233
234    /// Get sample count if available
235    pub fn as_samples(&self) -> Option<u64> {
236        match self {
237            DataSize::Samples(n) => Some(*n),
238            _ => None,
239        }
240    }
241
242    /// Estimate if this is "large" data (>100K samples or >1GB)
243    pub fn is_large(&self) -> bool {
244        match self {
245            DataSize::Samples(n) => *n > 100_000,
246            DataSize::Bytes(n) => *n > 1_000_000_000,
247            DataSize::Unknown => false,
248        }
249    }
250}
251
252/// Optimization target for queries
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
254pub enum OptimizationTarget {
255    /// Optimize for execution speed
256    #[default]
257    Speed,
258    /// Optimize for memory efficiency
259    Memory,
260    /// Optimize for power efficiency
261    Power,
262    /// Balance all factors
263    Balanced,
264}
265
266/// Query constraints
267#[derive(Debug, Clone, Default, Serialize, Deserialize)]
268pub struct QueryConstraints {
269    /// Maximum latency requirement (ms)
270    pub max_latency_ms: Option<u64>,
271    /// Data size
272    pub data_size: Option<DataSize>,
273    /// Must run locally (no cloud)
274    pub sovereign_only: bool,
275    /// EU AI Act compliance required
276    pub eu_compliant: bool,
277    /// Available hardware
278    pub hardware: HardwareSpec,
279}
280
281/// Query preferences
282#[derive(Debug, Clone, Default, Serialize, Deserialize)]
283pub struct QueryPreferences {
284    /// Optimization target
285    pub optimize_for: OptimizationTarget,
286    /// Preference for simpler solutions (0.0-1.0)
287    pub simplicity_weight: f32,
288    /// Existing stack components to integrate with
289    pub existing_components: Vec<String>,
290}
291
292/// Oracle query structure
293#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct OracleQuery {
295    /// Problem description in natural language
296    pub description: String,
297    /// Constraints
298    pub constraints: QueryConstraints,
299    /// Preferences
300    pub preferences: QueryPreferences,
301}
302
303impl OracleQuery {
304    pub fn new(description: impl Into<String>) -> Self {
305        Self {
306            description: description.into(),
307            constraints: QueryConstraints::default(),
308            preferences: QueryPreferences::default(),
309        }
310    }
311
312    pub fn with_constraints(mut self, constraints: QueryConstraints) -> Self {
313        self.constraints = constraints;
314        self
315    }
316
317    pub fn with_preferences(mut self, preferences: QueryPreferences) -> Self {
318        self.preferences = preferences;
319        self
320    }
321
322    pub fn with_data_size(mut self, size: DataSize) -> Self {
323        self.constraints.data_size = Some(size);
324        self
325    }
326
327    pub fn with_hardware(mut self, hardware: HardwareSpec) -> Self {
328        self.constraints.hardware = hardware;
329        self
330    }
331
332    pub fn sovereign_only(mut self) -> Self {
333        self.constraints.sovereign_only = true;
334        self
335    }
336
337    pub fn eu_compliant(mut self) -> Self {
338        self.constraints.eu_compliant = true;
339        self
340    }
341}
342
343// =============================================================================
344// Response Types
345// =============================================================================
346
347/// Compute backend selection
348#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
349#[allow(clippy::upper_case_acronyms)]
350pub enum Backend {
351    Scalar,
352    SIMD,
353    GPU,
354    Distributed,
355}
356
357impl std::fmt::Display for Backend {
358    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
359        match self {
360            Backend::Scalar => write!(f, "Scalar"),
361            Backend::SIMD => write!(f, "SIMD"),
362            Backend::GPU => write!(f, "GPU"),
363            Backend::Distributed => write!(f, "Distributed"),
364        }
365    }
366}
367
368/// Operation complexity classification
369#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
370pub enum OpComplexity {
371    /// O(n) - element-wise operations
372    Low,
373    /// O(n log n) to O(n²) - reductions, sorts
374    Medium,
375    /// O(n²) to O(n³) - matrix operations
376    High,
377}
378
379/// Compute recommendation
380#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct ComputeRecommendation {
382    pub backend: Backend,
383    pub rationale: String,
384}
385
386/// Distribution recommendation
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct DistributionRecommendation {
389    pub tool: Option<String>,
390    pub needed: bool,
391    pub rationale: String,
392    pub node_count: Option<u32>,
393}
394
395/// Component recommendation with confidence
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub struct ComponentRecommendation {
398    /// Component name
399    pub component: String,
400    /// Specific module/function path (e.g., "aprender::tree::RandomForest")
401    pub path: Option<String>,
402    /// Confidence score (0.0-1.0)
403    pub confidence: f32,
404    /// Reason for recommendation
405    pub rationale: String,
406}
407
408/// Complete Oracle response
409#[derive(Debug, Clone, Serialize, Deserialize)]
410pub struct OracleResponse {
411    /// Problem classification
412    pub problem_class: String,
413    /// Detected algorithm/approach
414    pub algorithm: Option<String>,
415    /// Primary recommendation
416    pub primary: ComponentRecommendation,
417    /// Supporting components
418    pub supporting: Vec<ComponentRecommendation>,
419    /// Compute backend recommendation
420    pub compute: ComputeRecommendation,
421    /// Distribution recommendation
422    pub distribution: DistributionRecommendation,
423    /// Example code snippet
424    pub code_example: Option<String>,
425    /// Related queries for follow-up
426    pub related_queries: Vec<String>,
427}
428
429impl OracleResponse {
430    pub fn new(problem_class: impl Into<String>, primary: ComponentRecommendation) -> Self {
431        Self {
432            problem_class: problem_class.into(),
433            algorithm: None,
434            primary,
435            supporting: Vec::new(),
436            compute: ComputeRecommendation {
437                backend: Backend::SIMD,
438                rationale: "Default SIMD backend".into(),
439            },
440            distribution: DistributionRecommendation {
441                tool: None,
442                needed: false,
443                rationale: "Single-node sufficient".into(),
444                node_count: None,
445            },
446            code_example: None,
447            related_queries: Vec::new(),
448        }
449    }
450
451    pub fn with_algorithm(mut self, algo: impl Into<String>) -> Self {
452        self.algorithm = Some(algo.into());
453        self
454    }
455
456    pub fn with_supporting(mut self, rec: ComponentRecommendation) -> Self {
457        self.supporting.push(rec);
458        self
459    }
460
461    pub fn with_compute(mut self, compute: ComputeRecommendation) -> Self {
462        self.compute = compute;
463        self
464    }
465
466    pub fn with_distribution(mut self, dist: DistributionRecommendation) -> Self {
467        self.distribution = dist;
468        self
469    }
470
471    pub fn with_code_example(mut self, code: impl Into<String>) -> Self {
472        self.code_example = Some(code.into());
473        self
474    }
475}
476
477// =============================================================================
478// Problem Domain Classification
479// =============================================================================
480
481/// Problem domain for classification
482#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
483pub enum ProblemDomain {
484    // ML domains
485    SupervisedLearning,
486    UnsupervisedLearning,
487    DeepLearning,
488    Inference,
489    // Compute domains
490    LinearAlgebra,
491    VectorSearch,
492    GraphAnalytics,
493    // Transpilation domains
494    PythonMigration,
495    CMigration,
496    ShellMigration,
497    // Infrastructure domains
498    DistributedCompute,
499    DataPipeline,
500    ModelServing,
501    // Quality domains
502    Testing,
503    Profiling,
504    Validation,
505}
506
507impl std::fmt::Display for ProblemDomain {
508    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
509        match self {
510            ProblemDomain::SupervisedLearning => write!(f, "Supervised Learning"),
511            ProblemDomain::UnsupervisedLearning => write!(f, "Unsupervised Learning"),
512            ProblemDomain::DeepLearning => write!(f, "Deep Learning"),
513            ProblemDomain::Inference => write!(f, "Model Inference"),
514            ProblemDomain::LinearAlgebra => write!(f, "Linear Algebra"),
515            ProblemDomain::VectorSearch => write!(f, "Vector Search"),
516            ProblemDomain::GraphAnalytics => write!(f, "Graph Analytics"),
517            ProblemDomain::PythonMigration => write!(f, "Python Migration"),
518            ProblemDomain::CMigration => write!(f, "C/C++ Migration"),
519            ProblemDomain::ShellMigration => write!(f, "Shell Migration"),
520            ProblemDomain::DistributedCompute => write!(f, "Distributed Computing"),
521            ProblemDomain::DataPipeline => write!(f, "Data Pipeline"),
522            ProblemDomain::ModelServing => write!(f, "Model Serving"),
523            ProblemDomain::Testing => write!(f, "Testing"),
524            ProblemDomain::Profiling => write!(f, "Profiling"),
525            ProblemDomain::Validation => write!(f, "Validation"),
526        }
527    }
528}
529
530// =============================================================================
531// Integration Patterns
532// =============================================================================
533
534/// Integration pattern between components
535#[derive(Debug, Clone, Serialize, Deserialize)]
536pub struct IntegrationPattern {
537    pub from: String,
538    pub to: String,
539    pub pattern_name: String,
540    pub description: String,
541    pub code_template: Option<String>,
542}
543
544// =============================================================================
545// Tests
546// =============================================================================
547
548#[cfg(test)]
549mod tests {
550    use super::*;
551
552    // =========================================================================
553    // StackLayer Tests
554    // =========================================================================
555
556    #[test]
557    fn test_stack_layer_index() {
558        assert_eq!(StackLayer::Primitives.index(), 0);
559        assert_eq!(StackLayer::MlAlgorithms.index(), 1);
560        assert_eq!(StackLayer::MlPipeline.index(), 2);
561        assert_eq!(StackLayer::Transpilers.index(), 3);
562        assert_eq!(StackLayer::Orchestration.index(), 4);
563        assert_eq!(StackLayer::Quality.index(), 5);
564        assert_eq!(StackLayer::Data.index(), 6);
565    }
566
567    #[test]
568    fn test_stack_layer_all() {
569        let layers = StackLayer::all();
570        assert_eq!(layers.len(), 7);
571        assert_eq!(layers[0], StackLayer::Primitives);
572        assert_eq!(layers[6], StackLayer::Data);
573    }
574
575    #[test]
576    fn test_stack_layer_display() {
577        assert_eq!(StackLayer::Primitives.to_string(), "Compute Primitives");
578        assert_eq!(StackLayer::MlAlgorithms.to_string(), "ML Algorithms");
579        assert_eq!(StackLayer::Transpilers.to_string(), "Transpilers");
580    }
581
582    #[test]
583    fn test_stack_layer_serialization() {
584        let layer = StackLayer::MlAlgorithms;
585        let json = serde_json::to_string(&layer).unwrap();
586        let parsed: StackLayer = serde_json::from_str(&json).unwrap();
587        assert_eq!(layer, parsed);
588    }
589
590    // =========================================================================
591    // Capability Tests
592    // =========================================================================
593
594    #[test]
595    fn test_capability_new() {
596        let cap = Capability::new("simd", CapabilityCategory::Compute);
597        assert_eq!(cap.name, "simd");
598        assert_eq!(cap.category, CapabilityCategory::Compute);
599        assert!(cap.description.is_none());
600    }
601
602    #[test]
603    fn test_capability_with_description() {
604        let cap = Capability::new("vector_ops", CapabilityCategory::Compute)
605            .with_description("SIMD-accelerated vector operations");
606        assert_eq!(
607            cap.description.as_deref(),
608            Some("SIMD-accelerated vector operations")
609        );
610    }
611
612    #[test]
613    fn test_capability_equality() {
614        let cap1 = Capability::new("simd", CapabilityCategory::Compute);
615        let cap2 = Capability::new("simd", CapabilityCategory::Compute);
616        let cap3 = Capability::new("gpu", CapabilityCategory::Compute);
617        assert_eq!(cap1, cap2);
618        assert_ne!(cap1, cap3);
619    }
620
621    // =========================================================================
622    // StackComponent Tests
623    // =========================================================================
624
625    #[test]
626    fn test_stack_component_new() {
627        let comp = StackComponent::new(
628            "trueno",
629            "0.7.3",
630            StackLayer::Primitives,
631            "SIMD-accelerated tensor operations",
632        );
633        assert_eq!(comp.name, "trueno");
634        assert_eq!(comp.version, "0.7.3");
635        assert_eq!(comp.layer, StackLayer::Primitives);
636        assert!(comp.capabilities.is_empty());
637    }
638
639    #[test]
640    fn test_stack_component_with_capability() {
641        let comp = StackComponent::new("trueno", "0.7.3", StackLayer::Primitives, "SIMD tensors")
642            .with_capability(Capability::new("simd", CapabilityCategory::Compute))
643            .with_capability(Capability::new("gpu", CapabilityCategory::Compute));
644        assert_eq!(comp.capabilities.len(), 2);
645        assert!(comp.has_capability("simd"));
646        assert!(comp.has_capability("gpu"));
647        assert!(!comp.has_capability("tpu"));
648    }
649
650    #[test]
651    fn test_stack_component_with_capabilities() {
652        let caps = vec![
653            Capability::new("vector_ops", CapabilityCategory::Compute),
654            Capability::new("matrix_ops", CapabilityCategory::Compute),
655        ];
656        let comp = StackComponent::new("trueno", "0.7.3", StackLayer::Primitives, "SIMD tensors")
657            .with_capabilities(caps);
658        assert_eq!(comp.capabilities.len(), 2);
659    }
660
661    #[test]
662    fn test_stack_component_serialization() {
663        let comp =
664            StackComponent::new("aprender", "0.12.0", StackLayer::MlAlgorithms, "ML library")
665                .with_capability(Capability::new(
666                    "random_forest",
667                    CapabilityCategory::MachineLearning,
668                ));
669        let json = serde_json::to_string(&comp).unwrap();
670        let parsed: StackComponent = serde_json::from_str(&json).unwrap();
671        assert_eq!(comp.name, parsed.name);
672        assert_eq!(comp.version, parsed.version);
673        assert_eq!(comp.capabilities.len(), parsed.capabilities.len());
674    }
675
676    // =========================================================================
677    // HardwareSpec Tests
678    // =========================================================================
679
680    #[test]
681    fn test_hardware_spec_default() {
682        let hw = HardwareSpec::default();
683        assert!(!hw.has_gpu);
684        assert!(hw.gpu_memory_gb.is_none());
685        assert!(!hw.is_distributed);
686    }
687
688    #[test]
689    fn test_hardware_spec_cpu_only() {
690        let hw = HardwareSpec::cpu_only();
691        assert!(!hw.has_gpu());
692    }
693
694    #[test]
695    fn test_hardware_spec_with_gpu() {
696        let hw = HardwareSpec::with_gpu(16.0);
697        assert!(hw.has_gpu());
698        assert_eq!(hw.gpu_memory_gb, Some(16.0));
699    }
700
701    // =========================================================================
702    // DataSize Tests
703    // =========================================================================
704
705    #[test]
706    fn test_data_size_samples() {
707        let size = DataSize::samples(1_000_000);
708        assert_eq!(size.as_samples(), Some(1_000_000));
709        assert!(size.is_large());
710    }
711
712    #[test]
713    fn test_data_size_bytes() {
714        let size = DataSize::bytes(2_000_000_000);
715        assert!(size.is_large());
716        assert!(size.as_samples().is_none());
717    }
718
719    #[test]
720    fn test_data_size_small() {
721        let size = DataSize::samples(1000);
722        assert!(!size.is_large());
723    }
724
725    #[test]
726    fn test_data_size_unknown() {
727        let size = DataSize::Unknown;
728        assert!(!size.is_large());
729        assert!(size.as_samples().is_none());
730    }
731
732    // =========================================================================
733    // OracleQuery Tests
734    // =========================================================================
735
736    #[test]
737    fn test_oracle_query_new() {
738        let query = OracleQuery::new("Train a random forest on 1M samples");
739        assert_eq!(query.description, "Train a random forest on 1M samples");
740        assert!(!query.constraints.sovereign_only);
741        assert!(!query.constraints.eu_compliant);
742    }
743
744    #[test]
745    fn test_oracle_query_with_data_size() {
746        let query =
747            OracleQuery::new("classification task").with_data_size(DataSize::samples(1_000_000));
748        assert_eq!(
749            query.constraints.data_size,
750            Some(DataSize::Samples(1_000_000))
751        );
752    }
753
754    #[test]
755    fn test_oracle_query_sovereign_only() {
756        let query = OracleQuery::new("GDPR compliant training").sovereign_only();
757        assert!(query.constraints.sovereign_only);
758    }
759
760    #[test]
761    fn test_oracle_query_eu_compliant() {
762        let query = OracleQuery::new("EU AI Act compliant").eu_compliant();
763        assert!(query.constraints.eu_compliant);
764    }
765
766    #[test]
767    fn test_oracle_query_with_hardware() {
768        let query = OracleQuery::new("GPU training").with_hardware(HardwareSpec::with_gpu(24.0));
769        assert!(query.constraints.hardware.has_gpu());
770    }
771
772    #[test]
773    fn test_oracle_query_serialization() {
774        let query = OracleQuery::new("Test query")
775            .with_data_size(DataSize::samples(10000))
776            .sovereign_only();
777        let json = serde_json::to_string(&query).unwrap();
778        let parsed: OracleQuery = serde_json::from_str(&json).unwrap();
779        assert_eq!(query.description, parsed.description);
780        assert_eq!(
781            query.constraints.sovereign_only,
782            parsed.constraints.sovereign_only
783        );
784    }
785
786    // =========================================================================
787    // Backend Tests
788    // =========================================================================
789
790    #[test]
791    fn test_backend_display() {
792        assert_eq!(Backend::Scalar.to_string(), "Scalar");
793        assert_eq!(Backend::SIMD.to_string(), "SIMD");
794        assert_eq!(Backend::GPU.to_string(), "GPU");
795        assert_eq!(Backend::Distributed.to_string(), "Distributed");
796    }
797
798    #[test]
799    fn test_backend_serialization() {
800        let backend = Backend::GPU;
801        let json = serde_json::to_string(&backend).unwrap();
802        let parsed: Backend = serde_json::from_str(&json).unwrap();
803        assert_eq!(backend, parsed);
804    }
805
806    // =========================================================================
807    // OracleResponse Tests
808    // =========================================================================
809
810    #[test]
811    fn test_oracle_response_new() {
812        let rec = ComponentRecommendation {
813            component: "aprender".into(),
814            path: Some("aprender::tree::RandomForest".into()),
815            confidence: 0.95,
816            rationale: "Random forest is ideal for tabular data".into(),
817        };
818        let response = OracleResponse::new("supervised_learning", rec);
819        assert_eq!(response.problem_class, "supervised_learning");
820        assert_eq!(response.primary.component, "aprender");
821        assert!(!response.distribution.needed);
822    }
823
824    #[test]
825    fn test_oracle_response_with_algorithm() {
826        let rec = ComponentRecommendation {
827            component: "aprender".into(),
828            path: None,
829            confidence: 0.9,
830            rationale: "Test".into(),
831        };
832        let response = OracleResponse::new("ml", rec).with_algorithm("random_forest");
833        assert_eq!(response.algorithm.as_deref(), Some("random_forest"));
834    }
835
836    #[test]
837    fn test_oracle_response_with_supporting() {
838        let primary = ComponentRecommendation {
839            component: "aprender".into(),
840            path: None,
841            confidence: 0.9,
842            rationale: "Primary".into(),
843        };
844        let supporting = ComponentRecommendation {
845            component: "trueno".into(),
846            path: None,
847            confidence: 0.8,
848            rationale: "Backend compute".into(),
849        };
850        let response = OracleResponse::new("ml", primary).with_supporting(supporting);
851        assert_eq!(response.supporting.len(), 1);
852        assert_eq!(response.supporting[0].component, "trueno");
853    }
854
855    #[test]
856    fn test_oracle_response_with_code_example() {
857        let rec = ComponentRecommendation {
858            component: "aprender".into(),
859            path: None,
860            confidence: 0.9,
861            rationale: "Test".into(),
862        };
863        let code = r#"use aprender::tree::RandomForest;
864let model = RandomForest::new();"#;
865        let response = OracleResponse::new("ml", rec).with_code_example(code);
866        assert!(response.code_example.is_some());
867        assert!(response.code_example.unwrap().contains("RandomForest"));
868    }
869
870    // =========================================================================
871    // ProblemDomain Tests
872    // =========================================================================
873
874    #[test]
875    fn test_problem_domain_display() {
876        assert_eq!(
877            ProblemDomain::SupervisedLearning.to_string(),
878            "Supervised Learning"
879        );
880        assert_eq!(
881            ProblemDomain::PythonMigration.to_string(),
882            "Python Migration"
883        );
884        assert_eq!(ProblemDomain::GraphAnalytics.to_string(), "Graph Analytics");
885    }
886
887    #[test]
888    fn test_problem_domain_serialization() {
889        let domain = ProblemDomain::DeepLearning;
890        let json = serde_json::to_string(&domain).unwrap();
891        let parsed: ProblemDomain = serde_json::from_str(&json).unwrap();
892        assert_eq!(domain, parsed);
893    }
894
895    // =========================================================================
896    // OptimizationTarget Tests
897    // =========================================================================
898
899    #[test]
900    fn test_optimization_target_default() {
901        let target = OptimizationTarget::default();
902        assert_eq!(target, OptimizationTarget::Speed);
903    }
904
905    #[test]
906    fn test_optimization_target_serialization() {
907        let target = OptimizationTarget::Memory;
908        let json = serde_json::to_string(&target).unwrap();
909        let parsed: OptimizationTarget = serde_json::from_str(&json).unwrap();
910        assert_eq!(target, parsed);
911    }
912
913    // =========================================================================
914    // QueryConstraints Tests
915    // =========================================================================
916
917    #[test]
918    fn test_query_constraints_default() {
919        let constraints = QueryConstraints::default();
920        assert!(constraints.max_latency_ms.is_none());
921        assert!(constraints.data_size.is_none());
922        assert!(!constraints.sovereign_only);
923        assert!(!constraints.eu_compliant);
924    }
925
926    // =========================================================================
927    // QueryPreferences Tests
928    // =========================================================================
929
930    #[test]
931    fn test_query_preferences_default() {
932        let prefs = QueryPreferences::default();
933        assert_eq!(prefs.optimize_for, OptimizationTarget::Speed);
934        assert_eq!(prefs.simplicity_weight, 0.0);
935        assert!(prefs.existing_components.is_empty());
936    }
937
938    // =========================================================================
939    // IntegrationPattern Tests
940    // =========================================================================
941
942    #[test]
943    fn test_integration_pattern() {
944        let pattern = IntegrationPattern {
945            from: "aprender".into(),
946            to: "realizar".into(),
947            pattern_name: "model_export".into(),
948            description: "Export trained model for serving".into(),
949            code_template: Some("model.export_apr(\"model.apr\")".into()),
950        };
951        assert_eq!(pattern.from, "aprender");
952        assert_eq!(pattern.to, "realizar");
953        assert!(pattern.code_template.is_some());
954    }
955
956    #[test]
957    fn test_integration_pattern_serialization() {
958        let pattern = IntegrationPattern {
959            from: "depyler".into(),
960            to: "aprender".into(),
961            pattern_name: "sklearn_convert".into(),
962            description: "Convert sklearn to aprender".into(),
963            code_template: None,
964        };
965        let json = serde_json::to_string(&pattern).unwrap();
966        let parsed: IntegrationPattern = serde_json::from_str(&json).unwrap();
967        assert_eq!(pattern.from, parsed.from);
968        assert_eq!(pattern.to, parsed.to);
969    }
970}