Debug Simulation Outcomes
This guide helps you diagnose unexpected simulation results systematically. Use these techniques when outcomes don’t match theoretical predictions or when values fall outside expected ranges.
Prerequisites
Completed Quickstart
Basic understanding of Survival Calculus
Access to
misetask runner
Symptom Identification
Before debugging, identify which symptom you’re experiencing:
- Values Out of Range
Probability values outside [0, 1]
Negative wealth
Consciousness exceeding bounds
- Unexpected Bifurcation
Fascism when solidarity edges exist
Revolution without sufficient P(S|R)
Stalled consciousness drift
- Timing Issues
Death occurring too early/late
Crossover threshold never reached
Rent extraction not accumulating
Step 1: Verify Formula Correctness
Run the formula doctests to ensure mathematical operations work correctly:
mise run doctest
This validates all formulas in src/babylon/systems/formulas.py against
their documented examples. If tests fail, the bug is in formula implementation.
See also
Formulas Reference for the complete formula specification.
Step 2: Run a Trace Analysis
Capture full simulation state over time:
mise run analyze-trace
This outputs a CSV to results/trace.csv with per-tick data:
Entity wealth, consciousness, organization
Survival probabilities (P(S|A), P(S|R))
Edge tension and value flows
Open the CSV in a spreadsheet to identify:
Inflection points: Where do values change direction?
Correlations: Do related values move together?
Anomalies: Any sudden jumps or flat periods?
Step 3: Use Structured Logging
For detailed event-by-event debugging, use the vertical slice tool:
poetry run python tools/vertical_slice.py
This tool provides:
Tick-by-tick state display: All entity values per tick
Event logging: What events triggered each state change
JSON structured logs: Machine-readable logs in
logs/
Interpreting JSON Logs
The logs/vertical_slice_<timestamp>.json file contains:
{
"event_type": "simulation_tick",
"data": {
"tick": 5,
"entities": {
"C001_periphery_worker": 0.0823,
"C004_labor_aristocracy": 0.2156
},
"economy": {
"imperial_rent_pool": 0.15,
"super_wage_rate": 0.08
},
"tension": 0.42,
"events": ["SURPLUS_EXTRACTION: 0.018 from C001"]
}
}
Search the JSON for:
"event_type": "error"to find logged errors"success": falseto find failed operationsSpecific entity IDs to trace their state changes
Step 4: Compare Against Theory
Use the survival calculus formulas to verify expected behavior:
- P(S|A) Should:
Increase when wealth increases
Approach 0 as wealth approaches subsistence threshold
Follow sigmoid curve centered at subsistence level
- P(S|R) Should:
Increase with organization
Decrease with repression
Cross P(S|A) when revolution becomes rational choice
- Bifurcation Should:
Route to fascism when solidarity edges absent
Route to revolution when solidarity edges present
Trigger when wages fall and agitation increases
See also
George Jackson Bifurcation Model for bifurcation theory.
Step 5: Isolate the Problem
Once you’ve identified which system is misbehaving:
- For formula bugs:
Create a minimal test case in
tests/unit/formulas/.- For system bugs:
Check the relevant system in
src/babylon/systems/:economic.py- Imperial rent extractionsolidarity.py- Consciousness transmissionideology.py- Bifurcation and driftsurvival.py- P(S|A) and P(S|R)
- For graph bugs:
Use
state.to_graph()to inspect the NetworkX graph directly:from babylon.engine.scenarios import create_imperial_circuit_scenario state, config, defines = create_imperial_circuit_scenario() G = state.to_graph() # Inspect edges print(list(G.edges(data=True))) # Check for missing solidarity edges solidarity_edges = [ (u, v) for u, v, d in G.edges(data=True) if d.get("type") == "SOLIDARITY" ]
Common Failure Patterns
Death at Tick 1
Symptom: Periphery worker dies immediately.
Cause: Initial wealth below subsistence threshold combined with high extraction efficiency.
Fix: Check extraction_efficiency in GameDefines or increase initial
periphery wealth in scenario.
P(S|R) Always Zero
Symptom: Revolution probability never increases.
Cause: Organization value not increasing, or repression too high.
Fix: Verify solidarity edges exist and organization field updates.
Consciousness Never Drifts
Symptom: class_consciousness stays constant.
Cause: Missing solidarity edges (required for transmission) or
drift_sensitivity_k set too low.
Fix: Check graph structure for SOLIDARITY edges between entities.
Fascism Without Trigger
Symptom: Ideology shifts to +1 without visible cause.
Cause: Agitation accumulated while solidarity edges were absent.
Fix: Review edge creation in scenario setup; ensure solidarity edges added before agitation triggers.
Getting Help
If you’ve followed these steps and still can’t identify the issue:
Create a minimal reproduction script
Include the trace CSV output
Note which tick the unexpected behavior occurs
Check existing tests for similar scenarios
See Also
Analyze Parameter Sensitivity - Systematic parameter exploration
Tune Simulation Parameters - Adjusting GameDefines values
Formulas Reference - Complete formula specifications
Error Codes - Error code reference