mockforge_core/
reality.rs

1//! Pillars: [Reality]
2//!
3//! Reality Slider - Unified control for mock environment realism
4//!
5//! This module provides a unified control mechanism that transitions mock environments
6//! between "stubbed simplicity" (level 1) and "production chaos" (level 5) by
7//! automatically coordinating chaos engineering, latency injection, and MockAI behaviors.
8
9use crate::chaos_utilities::ChaosConfig;
10use crate::intelligent_behavior::config::IntelligentBehaviorConfig;
11use crate::latency::{LatencyDistribution, LatencyProfile};
12use serde::{Deserialize, Serialize};
13use std::sync::Arc;
14use tokio::sync::RwLock;
15
16/// Reality level for mock environments (1-5)
17///
18/// Each level represents a different degree of realism, from simple static mocks
19/// to full production-like chaos behavior.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
21#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
22#[serde(rename_all = "snake_case")]
23#[derive(Default)]
24pub enum RealityLevel {
25    /// Level 1: Static Stubs - Simple, instant responses with no chaos
26    StaticStubs = 1,
27    /// Level 2: Light Simulation - Minimal latency, basic intelligence
28    LightSimulation = 2,
29    /// Level 3: Moderate Realism - Some chaos, moderate latency, full intelligence
30    #[default]
31    ModerateRealism = 3,
32    /// Level 4: High Realism - Increased chaos, realistic latency, session state
33    HighRealism = 4,
34    /// Level 5: Production Chaos - Maximum chaos, production-like latency, full features
35    ProductionChaos = 5,
36}
37
38impl RealityLevel {
39    /// Get the numeric value (1-5)
40    pub fn value(&self) -> u8 {
41        *self as u8
42    }
43
44    /// Get a human-readable name
45    pub fn name(&self) -> &'static str {
46        match self {
47            RealityLevel::StaticStubs => "Static Stubs",
48            RealityLevel::LightSimulation => "Light Simulation",
49            RealityLevel::ModerateRealism => "Moderate Realism",
50            RealityLevel::HighRealism => "High Realism",
51            RealityLevel::ProductionChaos => "Production Chaos",
52        }
53    }
54
55    /// Get a short description
56    pub fn description(&self) -> &'static str {
57        match self {
58            RealityLevel::StaticStubs => "Simple, instant responses with no chaos",
59            RealityLevel::LightSimulation => "Minimal latency, basic intelligence",
60            RealityLevel::ModerateRealism => "Some chaos, moderate latency, full intelligence",
61            RealityLevel::HighRealism => "Increased chaos, realistic latency, session state",
62            RealityLevel::ProductionChaos => {
63                "Maximum chaos, production-like latency, full features"
64            }
65        }
66    }
67
68    /// Create from numeric value (1-5)
69    pub fn from_value(value: u8) -> Option<Self> {
70        match value {
71            1 => Some(RealityLevel::StaticStubs),
72            2 => Some(RealityLevel::LightSimulation),
73            3 => Some(RealityLevel::ModerateRealism),
74            4 => Some(RealityLevel::HighRealism),
75            5 => Some(RealityLevel::ProductionChaos),
76            _ => None,
77        }
78    }
79
80    /// Get all available levels
81    pub fn all() -> Vec<Self> {
82        vec![
83            RealityLevel::StaticStubs,
84            RealityLevel::LightSimulation,
85            RealityLevel::ModerateRealism,
86            RealityLevel::HighRealism,
87            RealityLevel::ProductionChaos,
88        ]
89    }
90}
91
92/// Reality configuration that maps a level to specific subsystem settings
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct RealityConfig {
95    /// Current reality level
96    pub level: RealityLevel,
97    /// Chaos configuration for this level
98    pub chaos: ChaosConfig,
99    /// Latency profile for this level
100    pub latency: LatencyProfile,
101    /// MockAI configuration for this level
102    pub mockai: IntelligentBehaviorConfig,
103}
104
105impl RealityConfig {
106    /// Create configuration for a specific reality level
107    pub fn for_level(level: RealityLevel) -> Self {
108        match level {
109            RealityLevel::StaticStubs => Self::level_1_static_stubs(),
110            RealityLevel::LightSimulation => Self::level_2_light_simulation(),
111            RealityLevel::ModerateRealism => Self::level_3_moderate_realism(),
112            RealityLevel::HighRealism => Self::level_4_high_realism(),
113            RealityLevel::ProductionChaos => Self::level_5_production_chaos(),
114        }
115    }
116
117    /// Level 1: Static Stubs
118    ///
119    /// - Chaos: Disabled
120    /// - Latency: 0ms (instant)
121    /// - MockAI: Disabled (static responses only)
122    fn level_1_static_stubs() -> Self {
123        Self {
124            level: RealityLevel::StaticStubs,
125            chaos: ChaosConfig {
126                enabled: false,
127                error_rate: 0.0,
128                delay_rate: 0.0,
129                min_delay_ms: 0,
130                max_delay_ms: 0,
131                status_codes: vec![],
132                inject_timeouts: false,
133                timeout_ms: 0,
134            },
135            latency: LatencyProfile {
136                base_ms: 0,
137                jitter_ms: 0,
138                distribution: LatencyDistribution::Fixed,
139                std_dev_ms: None,
140                pareto_shape: None,
141                min_ms: 0,
142                max_ms: Some(0),
143                tag_overrides: Default::default(),
144            },
145            mockai: IntelligentBehaviorConfig {
146                enabled: false,
147                ..Default::default()
148            },
149        }
150    }
151
152    /// Level 2: Light Simulation
153    ///
154    /// - Chaos: Disabled
155    /// - Latency: 10-50ms (minimal)
156    /// - MockAI: Enabled (basic intelligence)
157    fn level_2_light_simulation() -> Self {
158        Self {
159            level: RealityLevel::LightSimulation,
160            chaos: ChaosConfig {
161                enabled: false,
162                error_rate: 0.0,
163                delay_rate: 0.0,
164                min_delay_ms: 0,
165                max_delay_ms: 0,
166                status_codes: vec![],
167                inject_timeouts: false,
168                timeout_ms: 0,
169            },
170            latency: LatencyProfile {
171                base_ms: 30,
172                jitter_ms: 20,
173                distribution: LatencyDistribution::Fixed,
174                std_dev_ms: None,
175                pareto_shape: None,
176                min_ms: 10,
177                max_ms: Some(50),
178                tag_overrides: Default::default(),
179            },
180            mockai: IntelligentBehaviorConfig {
181                enabled: true,
182                ..Default::default()
183            },
184        }
185    }
186
187    /// Level 3: Moderate Realism
188    ///
189    /// - Chaos: Enabled (5% error rate, 10% delay rate)
190    /// - Latency: 50-200ms (moderate)
191    /// - MockAI: Enabled (full intelligence)
192    fn level_3_moderate_realism() -> Self {
193        Self {
194            level: RealityLevel::ModerateRealism,
195            chaos: ChaosConfig {
196                enabled: true,
197                error_rate: 0.05,
198                delay_rate: 0.10,
199                min_delay_ms: 50,
200                max_delay_ms: 200,
201                status_codes: vec![500, 502, 503],
202                inject_timeouts: false,
203                timeout_ms: 0,
204            },
205            latency: LatencyProfile {
206                base_ms: 125,
207                jitter_ms: 75,
208                distribution: LatencyDistribution::Normal,
209                std_dev_ms: Some(30.0),
210                pareto_shape: None,
211                min_ms: 50,
212                max_ms: Some(200),
213                tag_overrides: Default::default(),
214            },
215            mockai: IntelligentBehaviorConfig {
216                enabled: true,
217                ..Default::default()
218            },
219        }
220    }
221
222    /// Level 4: High Realism
223    ///
224    /// - Chaos: Enabled (10% error rate, 20% delay rate)
225    /// - Latency: 100-500ms (realistic)
226    /// - MockAI: Enabled (full intelligence + session state)
227    fn level_4_high_realism() -> Self {
228        Self {
229            level: RealityLevel::HighRealism,
230            chaos: ChaosConfig {
231                enabled: true,
232                error_rate: 0.10,
233                delay_rate: 0.20,
234                min_delay_ms: 100,
235                max_delay_ms: 500,
236                status_codes: vec![500, 502, 503, 504],
237                inject_timeouts: false,
238                timeout_ms: 0,
239            },
240            latency: LatencyProfile {
241                base_ms: 300,
242                jitter_ms: 200,
243                distribution: LatencyDistribution::Normal,
244                std_dev_ms: Some(80.0),
245                pareto_shape: None,
246                min_ms: 100,
247                max_ms: Some(500),
248                tag_overrides: Default::default(),
249            },
250            mockai: IntelligentBehaviorConfig {
251                enabled: true,
252                performance: crate::intelligent_behavior::config::PerformanceConfig {
253                    max_history_length: 100,
254                    session_timeout_seconds: 3600,
255                    ..Default::default()
256                },
257                ..Default::default()
258            },
259        }
260    }
261
262    /// Level 5: Production Chaos
263    ///
264    /// - Chaos: Enabled (15% error rate, 30% delay rate, timeouts enabled)
265    /// - Latency: 200-2000ms (production-like, heavy-tailed)
266    /// - MockAI: Enabled (full intelligence + session state + mutations)
267    fn level_5_production_chaos() -> Self {
268        Self {
269            level: RealityLevel::ProductionChaos,
270            chaos: ChaosConfig {
271                enabled: true,
272                error_rate: 0.15,
273                delay_rate: 0.30,
274                min_delay_ms: 200,
275                max_delay_ms: 2000,
276                status_codes: vec![500, 502, 503, 504, 408],
277                inject_timeouts: true,
278                timeout_ms: 5000,
279            },
280            latency: LatencyProfile {
281                base_ms: 1100,
282                jitter_ms: 900,
283                distribution: LatencyDistribution::Pareto,
284                std_dev_ms: None,
285                pareto_shape: Some(2.0),
286                min_ms: 200,
287                max_ms: Some(2000),
288                tag_overrides: Default::default(),
289            },
290            mockai: IntelligentBehaviorConfig {
291                enabled: true,
292                performance: crate::intelligent_behavior::config::PerformanceConfig {
293                    max_history_length: 200,
294                    session_timeout_seconds: 7200,
295                    ..Default::default()
296                },
297                ..Default::default()
298            },
299        }
300    }
301}
302
303impl Default for RealityConfig {
304    fn default() -> Self {
305        Self::for_level(RealityLevel::default())
306    }
307}
308
309/// Reality preset for export/import
310#[derive(Debug, Clone, Serialize, Deserialize)]
311pub struct RealityPreset {
312    /// Preset name
313    pub name: String,
314    /// Preset description
315    pub description: Option<String>,
316    /// Reality configuration
317    pub config: RealityConfig,
318    /// Metadata
319    pub metadata: Option<PresetMetadata>,
320}
321
322/// Preset metadata
323#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct PresetMetadata {
325    /// Created timestamp
326    pub created_at: Option<String>,
327    /// Author
328    pub author: Option<String>,
329    /// Tags
330    pub tags: Vec<String>,
331    /// Version
332    pub version: Option<String>,
333}
334
335impl Default for PresetMetadata {
336    fn default() -> Self {
337        Self {
338            created_at: None,
339            author: None,
340            tags: vec![],
341            version: Some("1.0".to_string()),
342        }
343    }
344}
345
346/// Reality engine that coordinates chaos, latency, and MockAI subsystems
347///
348/// This engine applies the appropriate settings to each subsystem based on
349/// the current reality level. It acts as a coordinator and doesn't own the
350/// subsystems directly, but provides configuration that can be applied to them.
351#[derive(Debug, Clone)]
352pub struct RealityEngine {
353    /// Current reality configuration
354    config: Arc<RwLock<RealityConfig>>,
355}
356
357impl RealityEngine {
358    /// Create a new reality engine with default level
359    pub fn new() -> Self {
360        Self {
361            config: Arc::new(RwLock::new(RealityConfig::default())),
362        }
363    }
364
365    /// Create a new reality engine with a specific level
366    pub fn with_level(level: RealityLevel) -> Self {
367        Self {
368            config: Arc::new(RwLock::new(RealityConfig::for_level(level))),
369        }
370    }
371
372    /// Get the current reality level
373    pub async fn get_level(&self) -> RealityLevel {
374        self.config.read().await.level
375    }
376
377    /// Set the reality level and update configuration
378    pub async fn set_level(&self, level: RealityLevel) {
379        let mut config = self.config.write().await;
380        *config = RealityConfig::for_level(level);
381    }
382
383    /// Get the current reality configuration
384    pub async fn get_config(&self) -> RealityConfig {
385        self.config.read().await.clone()
386    }
387
388    /// Get chaos configuration for current level
389    pub async fn get_chaos_config(&self) -> ChaosConfig {
390        self.config.read().await.chaos.clone()
391    }
392
393    /// Get latency profile for current level
394    pub async fn get_latency_profile(&self) -> LatencyProfile {
395        self.config.read().await.latency.clone()
396    }
397
398    /// Get MockAI configuration for current level
399    pub async fn get_mockai_config(&self) -> IntelligentBehaviorConfig {
400        self.config.read().await.mockai.clone()
401    }
402
403    /// Create a preset from current configuration
404    pub async fn create_preset(&self, name: String, description: Option<String>) -> RealityPreset {
405        let config = self.config.read().await.clone();
406        RealityPreset {
407            name,
408            description,
409            config,
410            metadata: Some(PresetMetadata {
411                created_at: Some(chrono::Utc::now().to_rfc3339()),
412                author: None,
413                tags: vec![],
414                version: Some("1.0".to_string()),
415            }),
416        }
417    }
418
419    /// Apply a preset configuration
420    pub async fn apply_preset(&self, preset: RealityPreset) {
421        let mut config = self.config.write().await;
422        *config = preset.config;
423    }
424
425    /// Apply reality configuration to a ServerConfig
426    ///
427    /// This method updates the provided ServerConfig with chaos, latency, and MockAI
428    /// settings from the current reality level. This should be called when initializing
429    /// the server or when the reality level changes.
430    pub async fn apply_to_config(&self, config: &mut crate::config::ServerConfig) {
431        let reality_config = self.get_config().await;
432
433        // Apply chaos configuration
434        if config.reality.enabled {
435            // Update chaos config if it exists in observability
436            if let Some(ref mut chaos_eng) = config.observability.chaos {
437                chaos_eng.enabled = reality_config.chaos.enabled;
438                if let Some(ref mut fault) = chaos_eng.fault_injection {
439                    fault.enabled = reality_config.chaos.enabled;
440                    fault.http_error_probability = reality_config.chaos.error_rate;
441                    fault.timeout_errors = reality_config.chaos.inject_timeouts;
442                    fault.timeout_ms = reality_config.chaos.timeout_ms;
443                }
444                if let Some(ref mut latency) = chaos_eng.latency {
445                    latency.enabled = reality_config.latency.base_ms > 0;
446                    latency.fixed_delay_ms = Some(reality_config.latency.base_ms);
447                    latency.jitter_percent = if reality_config.latency.jitter_ms > 0 {
448                        (reality_config.latency.jitter_ms as f64
449                            / reality_config.latency.base_ms as f64)
450                            .min(1.0)
451                    } else {
452                        0.0
453                    };
454                }
455            }
456        }
457
458        // Apply latency configuration
459        if config.reality.enabled {
460            config.core.default_latency = reality_config.latency.clone();
461            config.core.latency_enabled = reality_config.latency.base_ms > 0;
462        }
463
464        // Apply MockAI configuration
465        if config.reality.enabled {
466            config.mockai.enabled = reality_config.mockai.enabled;
467            config.mockai.intelligent_behavior = reality_config.mockai.clone();
468        }
469    }
470}
471
472impl Default for RealityEngine {
473    fn default() -> Self {
474        Self::new()
475    }
476}
477
478#[cfg(test)]
479mod tests {
480    use super::*;
481
482    #[test]
483    fn test_reality_level_values() {
484        assert_eq!(RealityLevel::StaticStubs.value(), 1);
485        assert_eq!(RealityLevel::LightSimulation.value(), 2);
486        assert_eq!(RealityLevel::ModerateRealism.value(), 3);
487        assert_eq!(RealityLevel::HighRealism.value(), 4);
488        assert_eq!(RealityLevel::ProductionChaos.value(), 5);
489    }
490
491    #[test]
492    fn test_reality_level_from_value() {
493        assert_eq!(RealityLevel::from_value(1), Some(RealityLevel::StaticStubs));
494        assert_eq!(RealityLevel::from_value(3), Some(RealityLevel::ModerateRealism));
495        assert_eq!(RealityLevel::from_value(5), Some(RealityLevel::ProductionChaos));
496        assert_eq!(RealityLevel::from_value(0), None);
497        assert_eq!(RealityLevel::from_value(6), None);
498    }
499
500    #[test]
501    fn test_level_1_config() {
502        let config = RealityConfig::for_level(RealityLevel::StaticStubs);
503        assert!(!config.chaos.enabled);
504        assert_eq!(config.latency.base_ms, 0);
505        assert!(!config.mockai.enabled);
506    }
507
508    #[test]
509    fn test_level_5_config() {
510        let config = RealityConfig::for_level(RealityLevel::ProductionChaos);
511        assert!(config.chaos.enabled);
512        assert!(config.chaos.inject_timeouts);
513        assert_eq!(config.chaos.error_rate, 0.15);
514        assert!(config.latency.base_ms >= 200);
515        assert!(config.mockai.enabled);
516    }
517
518    #[tokio::test]
519    async fn test_reality_engine() {
520        let engine = RealityEngine::with_level(RealityLevel::StaticStubs);
521        assert_eq!(engine.get_level().await, RealityLevel::StaticStubs);
522
523        engine.set_level(RealityLevel::ProductionChaos).await;
524        assert_eq!(engine.get_level().await, RealityLevel::ProductionChaos);
525
526        let chaos_config = engine.get_chaos_config().await;
527        assert!(chaos_config.enabled);
528    }
529
530    #[tokio::test]
531    async fn test_preset_creation() {
532        let engine = RealityEngine::with_level(RealityLevel::ModerateRealism);
533        let preset = engine
534            .create_preset("test-preset".to_string(), Some("Test description".to_string()))
535            .await;
536
537        assert_eq!(preset.name, "test-preset");
538        assert_eq!(preset.config.level, RealityLevel::ModerateRealism);
539        assert!(preset.metadata.is_some());
540    }
541}