stemedb/crates/stemedb-sim/tests/smoke.rs
jordan 1ce4004807 feat: Complete Phase 2 (The Cortex) - query, lens, and API layers
This commit adds the read path (Cortex) to complement the write path (Spine):

## Crates
- stemedb-api: HTTP API with axum + utoipa OpenAPI
  - /v1/assert, /v1/query, /v1/epoch, /v1/skeptic, /v1/trace, /v1/audit
  - Metered endpoints with quota enforcement
  - Ed25519 signature verification
- stemedb-lens: Truth resolution lenses
  - RecencyLens, ConsensusLens, ConfidenceLens
  - VoteAwareConsensusLens (Ballot Box pattern)
  - TrustAwareAuthorityLens (The Hive pattern)
  - SkepticLens (conflict analysis)
  - EpochAwareLens (paradigm-safe queries)
- stemedb-query: Query engine with materialized views

## Storage Extensions
- VoteStore: Vote aggregation with cached counts
- TrustRankStore: Agent reputation with decay
- AuditStore: Query audit trail
- IndexStore: SP/P/S index structures
- SupersessionStore: Epoch supersession chains

## SDKs
- sdk/go/steme: Go HTTP client with Ed25519 signing
- sdk/go/adk: ADK-Go tools for AI agents

## Documentation
- Updated CLAUDE.md, architecture.md, roadmap.md
- New ai-lookup entries for all services
- Use case docs for consumer health intelligence
- Arena roadmap for simulation advancement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 13:22:44 -07:00

302 lines
11 KiB
Rust

//! Smoke tests for the StemeDB simulation.
//!
//! These tests validate that the simulation infrastructure works correctly
//! and can be run in CI. They exercise the core simulation loop and verify
//! that the Spine (WAL + Ingestor + KV Store), Cortex (Query + Lenses),
//! and Ballot Box (Votes + VoteAwareConsensusLens) correctly process data.
use stemedb_sim::{run_simulation, ErrorKind, SimulationConfig, SimulationResult};
/// Verify the default simulation configuration succeeds.
///
/// This is the primary smoke test - if this passes, Spine, Cortex, and Ballot Box are working.
#[tokio::test]
async fn smoke_default_simulation_succeeds() {
let config = SimulationConfig::default();
let result = run_simulation(config).await.expect("Simulation setup should not fail");
assert!(result.is_success(), "Default simulation should succeed. Errors: {:?}", result.errors);
// All Arena 1 tests should pass
assert!(result.recency_test_passed, "Recency lens test should pass");
assert!(result.lifecycle_test_passed, "Lifecycle filtering test should pass");
assert!(result.audit_test_passed, "Query audit test should pass");
// All Arena 2 tests 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.votes_written >= 6, "Should have written at least 6 votes");
}
/// Verify simulation works with increased load.
#[tokio::test]
async fn smoke_high_volume_simulation() {
let config = SimulationConfig {
agent_count: 10,
tick_count: 50,
ingestion_wait_ms: 1000, // More time for larger workload
};
let result = run_simulation(config).await.expect("Simulation setup should not fail");
assert!(
result.is_success(),
"High-volume simulation should succeed. Errors: {:?}",
result.errors
);
// 50 base + 2 (vote consensus) + 2 (troll resistance)
assert_eq!(result.assertions_written, 54);
assert_eq!(result.assertions_verified, 50);
// All Arena 1 + 2 tests should pass
assert!(result.recency_test_passed);
assert!(result.lifecycle_test_passed);
assert!(result.audit_test_passed);
assert!(result.vote_consensus_test_passed);
assert!(result.troll_resistance_test_passed);
}
/// Verify simulation result accessors work correctly.
#[test]
fn test_simulation_result_is_success() {
// Success case: all assertions verified, no errors, all tests pass
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,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
assert!(success.is_success());
// Note: mismatched assertions_written != assertions_verified is allowed
// because Arena 2 tests write additional test assertions.
let with_mismatch = SimulationResult {
assertions_written: 10,
assertions_verified: 8,
queries_executed: 10,
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,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
// This is now allowed - mismatched counts don't fail
assert!(with_mismatch.is_success());
// Failure case: has errors
let with_errors = 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,
errors: vec![stemedb_sim::SimulationError {
tick: 5,
kind: ErrorKind::VerificationFailure,
message: "Test error".to_string(),
}],
agent_count: 3,
tick_count: 10,
};
assert!(!with_errors.is_success());
// Failure case: recency test failed
let recency_failed = SimulationResult {
assertions_written: 10,
assertions_verified: 10,
queries_executed: 12,
votes_written: 6,
recency_test_passed: false,
lifecycle_test_passed: true,
audit_test_passed: true,
vote_consensus_test_passed: true,
troll_resistance_test_passed: true,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
assert!(!recency_failed.is_success());
// Failure case: lifecycle test failed
let lifecycle_failed = SimulationResult {
assertions_written: 10,
assertions_verified: 10,
queries_executed: 12,
votes_written: 6,
recency_test_passed: true,
lifecycle_test_passed: false,
audit_test_passed: true,
vote_consensus_test_passed: true,
troll_resistance_test_passed: true,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
assert!(!lifecycle_failed.is_success());
// Failure case: audit test failed
let audit_failed = SimulationResult {
assertions_written: 10,
assertions_verified: 10,
queries_executed: 12,
votes_written: 6,
recency_test_passed: true,
lifecycle_test_passed: true,
audit_test_passed: false,
vote_consensus_test_passed: true,
troll_resistance_test_passed: true,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
assert!(!audit_failed.is_success());
// Failure case: vote consensus test failed
let vote_consensus_failed = 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: false,
troll_resistance_test_passed: true,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
assert!(!vote_consensus_failed.is_success());
// Failure case: troll resistance test failed
let troll_resistance_failed = 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: false,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
assert!(!troll_resistance_failed.is_success());
}
/// Verify summary formatting.
#[test]
fn test_simulation_result_summary_format() {
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,
errors: vec![],
agent_count: 3,
tick_count: 10,
};
let summary = success.summary();
assert!(summary.contains(""), "Success should show checkmark");
assert!(summary.contains("10"), "Should show assertion count");
assert!(summary.contains("6"), "Should show vote count");
assert!(summary.contains("recency=✓"), "Should show recency passed");
assert!(summary.contains("lifecycle=✓"), "Should show lifecycle passed");
assert!(summary.contains("audit=✓"), "Should show audit passed");
assert!(summary.contains("vote_consensus=✓"), "Should show vote consensus passed");
assert!(summary.contains("troll_resist=✓"), "Should show troll resistance passed");
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,
errors: vec![stemedb_sim::SimulationError {
tick: 5,
kind: ErrorKind::VerificationFailure,
message: "Test".to_string(),
}],
agent_count: 3,
tick_count: 10,
};
let summary = failure.summary();
assert!(summary.contains(""), "Failure should show X");
assert!(summary.contains("1 error"), "Should show error count");
assert!(summary.contains("recency=✗"), "Should show recency failed");
assert!(summary.contains("troll_resist=✗"), "Should show troll resistance failed");
}
/// Verify all error kinds are representable.
#[test]
fn test_error_kinds_are_complete() {
// This test documents all error kinds - if a new one is added,
// this test should be updated to cover it.
let kinds = [
ErrorKind::WriteFailure,
ErrorKind::VerificationFailure,
ErrorKind::SignatureInvalid,
ErrorKind::StorageCorruption,
ErrorKind::SerializationFailure,
ErrorKind::QueryFailure,
ErrorKind::LensResolutionFailure,
ErrorKind::AuditFailure,
ErrorKind::VoteWriteFailure,
ErrorKind::VoteConsensusFailure,
];
for kind in kinds {
let error =
stemedb_sim::SimulationError { tick: 0, kind, message: format!("{:?} test", kind) };
// Verify Debug trait works
let debug_str = format!("{:?}", error);
assert!(!debug_str.is_empty());
}
}
/// Verify minimum viable configuration works.
/// Note: Minimal simulation requires at least 3 agents for voting tests.
#[tokio::test]
async fn smoke_minimal_simulation() {
let config = SimulationConfig { agent_count: 3, tick_count: 1, ingestion_wait_ms: 300 };
let result = run_simulation(config).await.expect("Simulation setup should not fail");
assert!(result.is_success(), "Minimal simulation should succeed: {:?}", result.errors);
// 1 base + 2 (vote consensus) + 2 (troll resistance)
assert_eq!(result.assertions_written, 5);
assert_eq!(result.assertions_verified, 1);
assert_eq!(result.agent_count, 3);
assert_eq!(result.tick_count, 1);
// All Arena 1 + 2 tests should pass
assert!(result.recency_test_passed);
assert!(result.lifecycle_test_passed);
assert!(result.audit_test_passed);
assert!(result.vote_consensus_test_passed);
assert!(result.troll_resistance_test_passed);
}