//! StemeDB Simulation Library //! //! This module provides the core simulation logic for validating the StemeDB //! "Spine" (Durability + Schema + Ingestion) and "Cortex" (Query + Lenses) //! under agent-driven stress tests. //! //! # Design Philosophy //! //! Following "Philosophy of Software Design" principles: //! - **Deep Module**: Simple `run_simulation()` interface hides all complexity //! - **Define Errors Out of Existence**: Failures are collected, not panicked //! - **Strategic Programming**: Built for testability and extension //! //! # Arena Phases //! //! - **Arena 0**: Spine validation (WAL + Ingestor + KV Store) //! - **Arena 1**: Query path validation (QueryEngine + Lenses + Lifecycle + Audits) //! - **Arena 2**: Voting & Consensus (VoteStore + VoteAwareConsensusLens) //! //! # Example //! //! ```ignore //! use stemedb_sim::{run_simulation, SimulationConfig}; //! //! let config = SimulationConfig::default(); //! let result = run_simulation(config).await?; //! //! assert_eq!(result.assertions_verified, result.assertions_written); //! assert!(result.errors.is_empty()); //! ``` // Module declarations mod agent; mod arenas; mod helpers; mod runner; pub mod strategy; mod types; // Public re-exports pub use runner::run_simulation; pub use strategy::{ AgentAction, AgentSpec, AgentStrategy, StrategyMetrics, StrategyType, WorldState, }; pub use types::{ ErrorKind, SimulationConfig, SimulationError, SimulationResult, SimulationSetupError, }; #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_simulation_default_config_succeeds() { let config = SimulationConfig::default(); let result = run_simulation(config).await.expect("Simulation should not fail setup"); assert!(result.is_success(), "Simulation should succeed: {:?}", result.errors); // Arena 0: tick_count assertions (strategy-dependent, some agents may skip) // Arena 2: 2 (vote consensus) + 2 (troll resistance) // Arena 3: 1 (MV integration) + 1 (fast-path) + 10 (freshness) assert!(result.assertions_written >= 16, "Should have arena test assertions + base"); // Arena 2 votes: 3 (vote consensus) + 3 (troll resistance) assert!(result.votes_written >= 6); assert!(result.recency_test_passed, "Recency test should pass"); assert!(result.lifecycle_test_passed, "Lifecycle test should pass"); assert!(result.audit_test_passed, "Audit test should pass"); assert!(result.vote_consensus_test_passed, "Vote consensus test should pass"); assert!(result.troll_resistance_test_passed, "Troll resistance test should pass"); assert!(result.mv_integration_test_passed, "MV integration test should pass"); assert!(result.fast_path_test_passed, "Fast-path test should pass"); assert!(result.mv_freshness_test_passed, "MV freshness test should pass"); } #[tokio::test] async fn test_simulation_custom_config() { let config = SimulationConfig { agents: vec![ AgentSpec { count: 2, strategy: StrategyType::Scientist }, AgentSpec { count: 2, strategy: StrategyType::Troll }, AgentSpec { count: 1, strategy: StrategyType::Believer }, ], tick_count: 20, ingestion_wait_ms: 600, }; let result = run_simulation(config).await.expect("Simulation should not fail setup"); assert!(result.is_success()); // Strategy-driven: agents may assert, vote, query, or skip per tick assert!(result.assertions_written >= 16, "Should have arena test assertions + base"); assert!(result.votes_written >= 6); assert_eq!(result.agent_count, 5); assert_eq!(result.tick_count, 20); } #[tokio::test] async fn test_simulation_result_summary() { let success = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(success.summary().contains("✅")); assert!(success.summary().contains("recency=✓")); assert!(success.summary().contains("lifecycle=✓")); assert!(success.summary().contains("audit=✓")); assert!(success.summary().contains("vote_consensus=✓")); assert!(success.summary().contains("troll_resist=✓")); assert!(success.summary().contains("mv_integ=✓")); assert!(success.summary().contains("fast_path=✓")); assert!(success.summary().contains("mv_fresh=✓")); let failure = SimulationResult { assertions_written: 10, assertions_verified: 8, queries_executed: 10, votes_written: 6, recency_test_passed: false, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: false, mv_integration_test_passed: true, fast_path_test_passed: false, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 2, errors: vec![SimulationError { tick: 5, kind: ErrorKind::VerificationFailure, message: "Test error".to_string(), }], agent_count: 3, tick_count: 10, }; assert!(failure.summary().contains("❌")); assert!(failure.summary().contains("recency=✗")); assert!(failure.summary().contains("fast_path=✗")); assert!(failure.summary().contains("troll_resist=✗")); } }