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