Break monolith source files into focused modules: - stemedb-core/types.rs → types/ directory (assertion, source, gold_standard, etc.) - stemedb-storage: audit_store, quota_store, trust_rank_store, vector_index, vote_store → module directories - stemedb-ingest/worker.rs → worker/ with separate test modules - stemedb-query: engine, materializer, query → module directories - stemedb-lens: epoch_aware, skeptic → module directories - stemedb-sim/lib.rs → agent, arenas/, helpers, runner, strategy, types - stemedb-api/tests: integration_tests → http_basic, http_validation, http_epoch, http_pipeline - stemedb-api/tests: e2e_flow_test → e2e_full_pipeline, e2e_lens_resolution - stemedb-query/tests: e2e_pipeline → e2e_pipeline + e2e_decay Also adds new features: gold standard verification, escalation handlers, admin endpoints, concept hierarchy spec, arena roadmap, and Go SDK. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
158 lines
6.1 KiB
Rust
158 lines
6.1 KiB
Rust
//! 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=✗"));
|
|
}
|
|
}
|