Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Test Infrastructure Requirements

Custom Test Harness (ic-test-harness)

A dedicated crate providing:

#![allow(unused)]
fn main() {
/// Run a deterministic sim scenario and return the final state hash.
pub fn run_scenario(scenario: &Scenario, seed: u64) -> SyncHash;

/// Run the same scenario N times and assert all hashes match.
pub fn assert_deterministic(scenario: &Scenario, seed: u64, runs: usize);

/// Run a scenario with a known-cheat replay and assert detection fires.
pub fn assert_cheat_detected(replay: &ReplayFile, expected: CheatType);

/// Run a scenario with a known-clean replay and assert no flags.
pub fn assert_no_false_positive(replay: &ReplayFile);

/// Run a scenario with deliberate desync injection and assert detection.
pub fn assert_desync_detected(scenario: &Scenario, desync_at: SimTick);

/// Run a scenario and measure tick time, returning percentile statistics.
pub fn benchmark_scenario(scenario: &Scenario, ticks: usize) -> TickStats;

/// Run a scenario and assert zero heap allocations in the hot path.
pub fn assert_zero_alloc_hot_path(scenario: &Scenario, ticks: usize);

/// Run a scenario with a sandbox module and assert all escape vectors are blocked.
pub fn assert_sandbox_contained(module: &WasmModule, escape_vectors: &[EscapeVector]);

/// Run order validation and assert sim state hash is unchanged (purity check).
pub fn assert_validation_pure(snap: &SimCoreSnapshot, orders: &[PlayerOrder]);

/// Run two sim instances with identical input and assert hash match at every tick.
pub fn assert_twin_determinism(scenario: &Scenario, seed: u64, ticks: usize);

/// Run the same scenario on the current platform and compare hash against
/// a stored cross-platform reference hash.
pub fn assert_cross_platform_hash(scenario: &Scenario, reference: &HashFile);

/// Run snapshot round-trip and assert state identity via hash comparison.
/// Takes a snapshot, restores it into a fresh sim, and verifies that
/// `state_hash()` matches the original — state identity, not byte-exactness.
pub fn assert_snapshot_roundtrip(snap: &SimCoreSnapshot);

/// Run a campaign mission sequence and verify roster carryover.
pub fn assert_roster_carryover(campaign: &CampaignGraph, mission_sequence: &[MissionId]);

/// Run a mod loading scenario and verify sandbox limits are enforced.
pub fn assert_mod_sandbox_limits(mod_path: &Path, limits: &SandboxLimits);
}

Tick Statistics (TickStats)

#![allow(unused)]
fn main() {
/// Per-scenario benchmark output — all values in microseconds.
pub struct TickStats {
    pub p50: u64,
    pub p95: u64,
    pub p99: u64,
    pub max: u64,
    pub heap_allocs: u64,      // total heap allocations during measurement window
    pub peak_rss_bytes: u64,   // peak resident set size
}
}

Performance Benchmark Suite (ic-bench)

Using criterion for statistical benchmarks with regression detection:

BenchmarkBudgetRegression Threshold
Sim tick (100 units)< 2ms+10% = warning
Sim tick (1000 units)< 10ms+10% = warning
Pathfinding (A*, 256x256)< 1ms+20% = warning
Fog-of-war update< 0.5ms+15% = warning
Network serialization< 0.1ms/message+10% = warning
YAML config load< 50ms+25% = warning
Replay frame write< 0.05ms/frame+20% = warning
Pathfinding LOD transition (256x256, 500 units)< 0.25ms+15% = warning
Stagger schedule overhead (1000 units)< 2.5ms+15% = warning
Spatial hash query (1M entities, 8K result)< 1ms+20% = warning
Flowfield generation (256x256)< 0.5ms+15% = warning
ECS cache miss rate (hot tick loop)< 5% L1 misses+2% absolute = warning
Weather state update (full map)< 0.3ms+20% = warning
Merkle tree hash (32 archetypes)< 0.2ms+15% = warning
Order validation (256 orders/tick)< 0.5ms+10% = warning

Allocation tracking: Hot-path benchmarks also measure heap allocations. Any allocation in a previously zero-alloc path is a test failure.

Fuzz Testing Targets

TargetInput SourceKnown CVE Coverage
ic-cnc-content (.oramap)Random archive bytesZip Slip, decompression bomb, path traversal
ic-cnc-content (.mix)Random file bytesBuffer overread, integer overflow
YAML tier configRandom YAMLV33 injection vectors
Network protocol messagesRandom byte streamV17 state saturation, oversized messages
Replay file parserRandom replay bytesV45 frame loss, signature chain gaps
strict-path inputsRandom path strings19+ CVE patterns (symlink, ADS, 8.3, etc.)
Display name validatorRandom UnicodeV46 confusable/homoglyph corpus
BiDi sanitizerRandom UnicodeV56 override injection vectors
Pathfinding inputRandom topology + start/endBuffer overflow, infinite loop on pathological graphs
Campaign DAG definitionRandom YAML graphCycles, unreachable nodes, missing outcome refs
Workshop manifest + depsRandom package manifestsCircular deps, version constraint contradictions
p2p-distribute bencodeRandom byte streamMalformed integers, nested dicts, oversized strings, unterminated containers
p2p-distribute BEP 3 wireRandom peer messagesInvalid message IDs, oversized piece indices, malformed bitfields, request flooding
p2p-distribute .torrentRandom metadata bytesOversized piece counts, missing required keys, hash length mismatch, info_hash collision
WASM memory requestsAdversarial memory.grow sequencesOOM, growth beyond sandbox limit
Balance preset YAMLRandom inheritance chainsCycles, missing parents, conflicting overrides
Cross-engine map formatRandom .mpr/.mmx bytesMalformed geometry, out-of-bounds spawns
LLM-generated mission YAMLRandom trigger/objective treesUnreachable objectives, invalid trigger refs

Labeled Replay Corpus

For anti-cheat calibration (V54):

CategorySourceMinimum Count
Confirmed-cheatTest accounts with known cheat tools500 replays
Confirmed-cleanTournament players, manually verified2000 replays
Edge-caseHigh-APM legitimate players (pro gamers)200 replays
Bot-assistedKnown automation scripts100 replays
Platform-bug desyncReproduced cross-platform desyncs (V55)50 replays

The labeled corpus is a living dataset — confirmed cases from post-launch human review (V54 continuous calibration) are ingested automatically. Quarterly corpus audits verify partition hygiene (no mislabeled replays, stale entries archived after 12 months).

Population Baseline Validation

For population-baseline statistical comparison (V12):

TestMethodPass CriteriaCI Tier
Baseline computationSeed db with 10K synthetic match profiles, compute baselinesp99/p1/p5 percentiles match expected values within 1%T2
Per-tier separationGenerate profiles with distinct per-tier distributionsBaselines for each rating tier differ meaningfullyT2
Recalculation stabilityRecompute baselines on overlapping windows with <5% data changeBaselines shift <2% between recomputationsT3
Outlier vs populationInject synthetic outlier profiles (APM 2000+, reaction <40ms)Outliers flagged by population comparison AND hard-floor thresholdsT2

Trust Score Validation

For behavioral matchmaking trust score (V12):

TestMethodPass CriteriaCI Tier
Factor computationSeed player history db, compute trust scoreScore within expected range for known-good/known-bad profilesT2
Matchmaking influenceQueue 100 synthetic players with varied trust scoresHigh-trust players grouped preferentially with high-trustT3
Recovery rateSimulate clean play after trust score dropScore recovers at defined asymmetric rate (slower gain than loss)T2
Community scopingCompute trust across two independent community serversScores are independent per community (no cross-community leakage)T2

Subsystem Test Specifications

Detailed test specifications organized by subsystem. Each entry defines: what is tested, test method, pass criteria, and CI tier.

Simulation Fairness (D008)

TestMethodPass CriteriaTier
Sub-tick tiebreak determinismTwo players issue Move orders to same target at identical sub-tick timestamps. Run 100 timesPlayer with lower PlayerId always wins tiebreak. Results identical across all runsT2 + T3 (proptest)
Timestamp ordering correctnessPlayer A timestamps at T+100us, Player B at T+200us for same contested resourcePlayer A always wins. Reversing timestamps reverses winnerT2
Relay timestamp envelope clampingClient submits timestamp outside feasible envelope (too far in the future or past)Relay clamps to envelope boundary. Anti-abuse telemetry event firesT2
Listen-server relay paritySame scenario run with EmbeddedRelayNetwork vs RelayLockstepNetworkIdentical TickOrders output from both pathsT2

Order Validation Matrix (D012)

TestMethodPass CriteriaTier
Exhaustive rejection matrixFor each order type (Move, Attack, Build, etc.) × each of the 8 rejection categories (ownership, unit-type mismatch, out-of-range, insufficient resources, tech prerequisite, placement invalid, budget exceeded, unsupported-for-phase): construct an order that triggers exactly that rejectionCorrect OrderRejectionCategory (D012) returned for every cell in the matrix; concrete variant within each category is implementation-definedT1
Random order validationProptest generates random PlayerOrder values with arbitrary fieldsValidation never panics; always returns a valid OrderValidity variantT3
Validation purityRun validate_order_checked with debug assertions enabled; verify sim state hash before and after validationState hash unchanged — validation has zero side effectsT1
Rejection telemetrySubmit 50 invalid orders from one player across 10 ticksAll 50 rejections appear in anti-cheat telemetry with correct categoriesT2

Merkle Tree Desync Localization

TestMethodPass CriteriaTier
Single-archetype divergenceRun two sim instances. At tick T, inject deliberate mutation in one archetype on instance BMerkle roots diverge. Tree traversal identifies mutated archetype leaf in ≤ ceil(log2(N)) roundsT2
Multi-archetype divergenceInject divergence in 3 archetypes simultaneouslyAll 3 divergent archetypes identifiedT2
Proof verificationFor a given leaf, verify the Merkle proof path reconstructs to the correct root hashProof verifies. Tampered proof fails verificationT3 (proptest)

Reconnection Snapshot Verification

TestMethodPass CriteriaTier
Happy-path reconnection2-player game. Player B disconnects at tick 500. Player B reconnects, receives snapshot, resumesAfter 1000 more ticks, Player B’s state hash matches Player A’sT2
Corrupted snapshot rejectionFlip one byte of the snapshot during transferReceiving client detects hash mismatch and rejects snapshotT4
Stale snapshot rejectionSend snapshot from tick 400 instead of 500Client detects tick mismatch and requests correct snapshotT4

Workshop Dependency Resolution (D030)

TestMethodPass CriteriaTier
Transitive resolutionPackage A → B → C. Install AAll three installed in dependency order; versions satisfy constraintsT1
Version conflict detectionPackage A requires B v2, Package C requires B v1. Install A + CConflict detected and reported with both constraint chainsT1
Circular dependency rejectionA → B → C → A dependency cycle. Attempt resolutionResolver returns cycle error with full cycle pathT1
Diamond dependencyA→B, A→C, B→D, C→D. Install AD installed once; version satisfies both B and C constraintsT1
Version immutabilityAttempt to re-publish same publisher/name@versionPublish rejected. Existing package unchangedT2
Random dependency graphsProptest generates random dependency graphs with varying depths and widthsResolver terminates for all inputs; detects all cycles; produces valid install order or errorT3

Campaign Graph Validation (D021)

TestMethodPass CriteriaTier
Valid DAG acceptanceConstruct valid branching campaign graph. ValidateAll missions reachable from entry. All outcomes lead to valid next missions or campaign endT1
Cycle rejectionInsert cycle (mission 3 outcome routes back to mission 1)Validation returns cycle error with pathT1
Dangling reference rejectionMission outcome points to nonexistent MissionIdValidation returns dangling reference errorT1
Unit roster carryoverComplete mission with 5 surviving units (varied health/veterancy). Start next missionRoster contains exactly those 5 units with correct health and veterancy levelsT2
Story flag persistenceSet flag in M1, unset in M2, read in M3Correct value at each pointT2
Campaign save mid-transitionSave during mission-to-mission transition. Load. ContinueState matches uninterrupted playthroughT4

WASM Sandbox Security (V50)

TestMethodPass CriteriaTier
Cross-module data probeModule A calls host API requesting Module B’s ECS data via crafted queryHost returns permission error. Module B’s state unchangedT3
Memory growth attackModule requests memory.grow(65536) (4GB)Growth denied at configured limit. Module receives trap. Host stableT3
Cross-module function callModule A attempts to call Module B’s exported functions directlyCall fails. Only host-mediated communication permittedT3
WASM float rejectionModule performs f32 arithmetic and attempts to write result to sim stateSim API rejects float values. Fixed-point conversion requiredT3
Module startup time budgetModule with artificially slow initialization (1000ms)Module loading cancelled at timeout. Game continues without moduleT3

Balance Preset Validation (D019)

TestMethodPass CriteriaTier
Inheritance chain resolutionPreset chain: Base → Competitive → Tournament. Query effective valuesTournament overrides Competitive, which overrides Base. No gaps in resolved valuesT2
Circular inheritance rejectionPreset A inherits B inherits ALoader rejects with cycle errorT1
Multiplayer preset enforcementAll players in lobby must resolve to identical effective presetSHA-256 hash of resolved preset identical across all clientsT2
Negative value rejectionPreset sets unit cost to -500 or health to 0Schema validator rejects with specific field errorT1
Random inheritance chainsProptest generates random preset inheritance treesResolver terminates; detects all cycles; produces valid resolved preset or errorT3

Weather State Machine Determinism (D022)

TestMethodPass CriteriaTier
Schedule determinismRun identical weather schedule on two sim instances with same seedWeatherState (type, intensity, transition_remaining) identical at every tickT2
Surface state syncWeather transition triggers surface state updateSurface condition buffer matches between instances. Fixed-point intensity ramp is bit-exactT2
Weather serializationSave game during blizzard → load → continue 1000 ticksWeather state persists. Hash matches fresh run from same pointT3

AI Behavior Determinism (D041/D043)

TestMethodPass CriteriaTier
Seed reproducibilityRun AI with seed S on map M for 1000 ticks. Repeat 10 timesBuild order, unit positions, resource totals identical across all 10 runsT2
Cross-platform matchRun same AI scenario on Linux and WindowsState hash match at every tickT3
Performance budgetAI tick for 500 units< 0.5ms. No heap allocations in steady stateT3

Console Command Security (D058)

TestMethodPass CriteriaTier
Permission enforcementNon-admin client sends admin-only commandCommand rejected with permission error. No state changeT1
Cvar bounds clampingSet cvar to value outside [MIN, MAX] rangeValue clamped to nearest bound. Telemetry event firesT1
Command rate limitingSend 1000 commands in one tickCommands beyond rate limit dropped. Client notified. Remaining budget recovers next tickT2
Dev mode replay flaggingExecute dev command during game. Save replayReplay metadata records dev-mode flag. Replay ineligible for ranked leaderboardT2
Autoexec.cfg gameplay rejectionRanked mode loads autoexec.cfg with gameplay commands (/build harvester)Gameplay commands rejected. Only cvars acceptedT2

SCR Credential Security (D052)

TestMethodPass CriteriaTier
Monotonic sequence enforcementPresent SCR with sequence number lower than last acceptedSCR rejected as replayed/rolled-backT2
Key rotation grace periodRotate key. Authenticate with old key during grace periodAuthentication succeeds with deprecation warningT4
Post-grace rejectionAuthenticate with old key after grace period expiresAuthentication rejected. Error directs to key recoveryT4
Emergency revocationRevoke key via BIP-39 mnemonicOld key immediately invalid. New key worksT4
Malformed SCR rejectionTruncated signature, invalid version byte, corrupted payloadAll rejected with specific error codesT3 (fuzz)

Cross-Engine Map Exchange

TestMethodPass CriteriaTier
OpenRA map round-tripImport .oramap with known geometry. Export to IC format. Re-importSpawn points, terrain, resources match original within defined toleranceT2
Out-of-bounds spawn rejectionImport map with spawn coordinates beyond map dimensionsValidator rejects with clear errorT2
Malformed map fuzzingRandom map file bytesParser never panics; produces clean error or valid mapT3

Mod Profile Fingerprinting (D062)

TestMethodPass CriteriaTier
Fingerprint stabilityCompute fingerprint, serialize/deserialize mod set, recomputeIdentical fingerprints. Stable across runsT2
Ordering independenceCompute fingerprint with mods [A, B, C] and [C, A, B]Identical fingerprints regardless of insertion orderT2
Conflict resolution determinismTwo mods override same YAML key with different values. Apply with explicit priorityWinner matches declared priority. All clients agree on resolved valueT3

LLM-Generated Content Validation (D016/D038)

TestMethodPass CriteriaTier
Objective reachabilityGenerated mission with objectives at known positionsAll objectives reachable from player starting position via pathfindingT3
Invalid trigger rejectionGenerated Lua triggers with syntax errors or undefined referencesValidation pass catches all errors before mission loadsT3
Invalid unit type rejectionGenerated YAML referencing nonexistent unit typesContent validator rejects with specific missing-type errorsT3
Seed reproducibilityGenerate mission with same seed twiceIdentical YAML outputT4