Block 7: Final Engine Hardening — Integration, Wiring, & Fidelity¶
Motivation¶
Blocks 1–6 built 57 phases of subsystems, from core infrastructure through combat, C2, EW, space, CBRN, four historical eras, a web UI, and full scenario validation. The result is a simulation with ~8,655 tests, 37 validated scenarios, and zero unresolved deficits.
However, a comprehensive audit reveals that the project suffers from a systemic build-then-defer-wiring pattern. The consequence is severe:
- 36 environmental parameters are computed every tick but never consumed by any downstream system
- 16 combat engines are instantiated but unreachable from the battle loop (including ALL air combat)
- 4 EngagementType enum values (MISSILE, AIR_TO_AIR, AIR_TO_GROUND, SAM) are declared but never assigned or routed
- The event bus is observational only — 73 files publish events, zero functional subscribers react to them
- Damage detail is discarded — DamageEngine computes casualties, equipment damage, fires, and ammo cookoff, but only
damage_fractionis used for a binary DESTROYED/DISABLED check - Logistics doesn't gate combat — units with zero fuel still move, maintenance state doesn't affect readiness
- Checkpoint infrastructure saves nothing — 136 classes implement get_state/set_state but none are registered
- DUG_IN provides zero protection — only stops movement, doesn't reduce incoming damage
- Detection → AI uses ground truth — AI sees raw enemy count, not detected contacts or confidence levels
Block 7 is the final hardening block. It comprehensively addresses every integration gap — environment, combat routing, cross-module feedback loops, and dead code — with a triage framework that prevents scope creep and structural verification tests that prevent future regression.
Block 7 exit criterion: 1. Every instantiated engine either contributes to simulation outcomes or is removed 2. Every computed parameter is consumed by at least one downstream system (verified by automated test) 3. Every published event type has at least one functional subscriber (verified by automated test) 4. Every cross-module feedback loop is either fully wired or explicitly documented as deferred 5. All scenarios still produce correct historical outcomes after integration
Current State: Engine Wiring Audit¶
Fully Wired & Active (contributing to outcomes)¶
| Engine | Lines | What It Does |
|---|---|---|
| WeatherEngine | 289 | Markov weather, wind (O-U process), visibility, temperature |
| TimeOfDayEngine | 197 | Solar/lunar illumination, thermal contrast, NVG effectiveness |
| SeasonsEngine | 253 | Ground state (frozen/thawing/wet/dry), mud, snow, vegetation, trafficability |
| FogOfWarManager | 433 | Per-side detection, track lifecycle, COP sharing |
| PoliticalPressureEngine | 268 | Escalation ladder, desperation index, war crimes cascade |
| HeightmapManager | 260 | Elevation, slope, aspect |
| TerrainClassification | 280 | Land cover classes, trafficability lookup |
| LOSEngine | 450 | DDA line-of-sight, viewshed |
| DetectionEngine | 400+ | Unified SNR detection, Kalman tracking |
| CombatEngines (8+) | 3,000+ | All domain combat resolution |
| MoraleEngine | 600+ | Continuous Markov morale, rout, rally |
| MovementEngine | 800+ | A* pathfinding, formations, domain movement |
Instantiated but Output Ignored¶
These engines are created and updated each tick, but their computed state is never consumed by downstream systems.
| Engine | Lines | Gap |
|---|---|---|
| SeasonsEngine | 253 | trafficability, mud_depth, vegetation_density, snow_depth computed but never queried by movement or detection |
| SeaStateEngine | 218 | Wave height used for gunnery dispersion only; no effect on ship movement, carrier ops, amphibious assault, mine drift |
| EMPropagationEngine | 200+ | GPS accuracy wired; radar horizon, atmospheric attenuation, EM ducting NOT used by detection or comms |
Instantiated but Never Called¶
These engines exist on the SimulationContext, have full implementations, but no method is ever invoked from engine.py or battle.py.
| Engine | Lines | What It Would Add |
|---|---|---|
| ObscurantsEngine | 256 | Smoke/dust/fog clouds with drift, dispersion, spectral blocking |
| ConditionsEngine | 249 | Facade aggregating all environment sub-engines (may be redundant) |
| SpaceISREngine | 206 | Satellite overpass detection of formations |
| EarlyWarningEngine | 143 | Ballistic missile launch detection via GEO/HEO satellites |
| ASATEngine | 353 | Anti-satellite warfare, debris cascade (Kessler syndrome) |
| SIGINTEngine | 488 | Radar/comms geolocation, traffic analysis |
| ECCMEngine | 270 | Electronic protection techniques reducing jam effectiveness |
| OrderPropagationEngine | 315 | Order delay (echelon-scaled) + misinterpretation probability |
| PlanningProcessEngine | 564 | MDMP state machine with planning phase delays |
| ATOPlanningEngine | 459 | Air tasking order generation with sortie limits |
| UnconventionalWarfareEngine | 397 | IED, guerrilla hit-and-run, human shields |
Partially Wired (gate checks but no execution)¶
| Engine | Lines | Gap |
|---|---|---|
| StratagemEngine | 416 | Eligibility evaluation works; activate_stratagem() never called |
| MineWarfareEngine | 541 | resolve_mine_encounter() called; lay_mines() never called |
Dead YAML Fields¶
| Field | Defined In | Consumed? | Notes |
|---|---|---|---|
weight_kg |
AmmoDefinition, Equipment | No | No weight-of-fire calculations |
propulsion |
AmmoDefinition | No | Rocket/turbojet/ramjet — no propulsion modeling |
unit_cost_factor |
AmmoDefinition | No | No logistics cost modeling |
data_link_range |
AerialUnit loader | No | UAV data link range never checked |
Cross-Module Integration Gaps (Non-Environment)¶
These are systemic integration failures that affect every domain, not just environment.
Event Bus: Observational Only¶
73 files publish events. 2 files subscribe — the Recorder (captures all events for replay) and scenario_runner (one generic subscription). Zero modules take functional action based on event receipt.
Events published but never processed by domain logic:
| Event | Publisher | Expected Subscriber | Missing Effect |
|---|---|---|---|
CasualtyTreatedEvent |
MedicalEngine | Unit strength tracker | Treated personnel never return to duty (unit stays depleted) |
ReturnToDutyEvent |
MedicalEngine | Unit strength tracker | Same — RTD published but nobody restores personnel |
EquipmentBreakdownEvent |
MaintenanceEngine | Unit readiness | Breakdown published but unit continues at full capability |
MaintenanceCompletedEvent |
MaintenanceEngine | Unit readiness | Repair published but readiness never restored |
SupplyDeliveredEvent |
SupplyEngine | Stockpile tracker | Supply arrives but stockpile may not update consumption state |
RouteInterdictedEvent |
DisruptionEngine | Supply routing | Route severed but no reactive rerouting or supply crisis |
ConvoyDestroyedEvent |
LogisticsEngine | Supply planning | Convoy loss has no feedback to logistics or C2 |
MoraleStateChangeEvent |
MoraleEngine | AI assessment | Morale transition published but AI doesn't adapt tactics |
RallyEvent |
RallyEngine | Movement/engagement | Rally published but unit doesn't automatically resume operations |
ATOGeneratedEvent |
ATOPlanningEngine | Air ops dispatcher | ATO entries generated but never consumed by air missions |
PlanningCompletedEvent |
PlanningProcessEngine | OODA cycle | Planning completes but nobody reads the result |
OrderIssuedEvent |
OrderPropagationEngine | Unit execution | Order published but no delayed-execution queue |
StratagemActivatedEvent |
StratagemEngine | Combat modifier | Stratagem activates but no modifier applied |
Root cause: The EventBus was designed for cross-module communication but modules were built with direct parameter passing instead. Events serve only as audit trail for the recorder.
Combat Routing: 16 Unreachable Engines¶
4 dead EngagementType values:
| EngagementType | Status | Consequence |
|---|---|---|
MISSILE |
Never assigned by _infer_engagement_type() |
Missile flights tracked by MissileEngine but never end in impact |
AIR_TO_AIR |
Never assigned | Air-to-air engagements route as DIRECT_FIRE (gun duel physics) |
AIR_TO_GROUND |
Never assigned | CAS/strike uses generic engagement, not air-specific Pk model |
SAM |
Never assigned | SAM engagements use generic engagement, not AD-specific model |
16 engines instantiated but unreachable from battle loop:
| Category | Engines | Lines | Impact |
|---|---|---|---|
| Air combat | AirCombatEngine, AirDefenseEngine, AirGroundEngine | ~1,200 | Air engagements use wrong physics (ground combat Pk for air duels) |
| Strategic air | AirCampaignEngine, StrategicBombingEngine, StrategicTargetingEngine | ~800 | Strategic air campaigns can't execute |
| Missiles | MissileEngine, MissileDefenseEngine | ~600 | Missile flight/intercept models unused |
| Naval air | CarrierOpsEngine | ~300 | CAP management, recovery windows unused |
| Historical naval | NavalOarEngine | ~200 | Ancient trireme combat uses generic model |
| Damage effects | IncendiaryDamageEngine, UXOEngine | ~400 | Fire zones and UXO contamination never created |
| Unconventional | UnconventionalWarfareEngine | ~400 | IED/guerrilla tactics dead |
| Siege | SiegeEngine | ~300 | Siege mechanics never invoked |
| C2 | VisualSignalsEngine, AmphibiousAssaultEngine | ~400 | Ancient C2 and amphibious assault dead |
Damage Detail Discarded¶
DamageEngine.resolve_damage() returns a DamageResult with:
- damage_fraction (0.0–1.0) — USED: compared to destruction/disable thresholds
- casualties (list of CasualtyResult) — DISCARDED: personnel losses never extracted
- systems_damaged (list of equipment hits) — DISCARDED: equipment never degrades
- fire_started (bool) — DISCARDED: no fire zone creation
- ammo_cookoff (bool) — DISCARDED: no secondary explosions
- penetrated (bool) — DISCARDED: no armor degradation
Consequence: A unit is either OPERATIONAL, DISABLED, or DESTROYED. No partial degradation. A tank with 49% damage has full combat power; at 50% it's destroyed. No crew casualties, no degraded systems, no fires.
Logistics Does Not Gate Combat¶
| Resource | Tracked? | Consumed? | Gates Action? |
|---|---|---|---|
| Ammunition | Yes | Yes (weapon.fire()) | NO — unit fires at 0 ammo |
| Fuel | Yes | No (movement doesn't consume) | NO — unit moves at 0 fuel |
| Maintenance/Readiness | Yes | Yes (breakdown events) | NO — disabled equipment still functions |
| Medical | Yes | Yes (treatment events) | NO — RTD events not consumed |
| Supply routes | Yes | Yes (disruption modeled) | NO — severed routes don't create shortages |
Note: The third agent's investigation confirmed ammo consumption IS wired via weapon.fire(). However, ammo depletion does not prevent firing.
Checkpoint State Not Saved¶
CheckpointManager.register() exists but is never called in production code. Checkpoints contain only clock and RNG state. Module state (morale, detection tracks, supply levels, equipment condition) is not saved. This means checkpoint restore produces a simulation with correct time and RNG but wrong unit states.
Detection → AI Uses Ground Truth¶
The AI assessment system receives:
- contacts = enemy_unit_count (raw count, not detected count)
- enemy_power = float(enemies) (true strength, not estimated)
FogOfWarManager exists and tracks per-side contacts with confidence/age, but this data is not passed to the AI assessment pipeline. The AI has perfect information about enemy forces regardless of sensor coverage.
Exception: When enable_fog_of_war is True (never set by any scenario), contact count comes from FOW tracking. But even then, quality/confidence/error is not conveyed.
Posture Protection Gap¶
| Posture | Speed Mult | Damage Reduction | Should Have |
|---|---|---|---|
| MOVING | 1.0 | 0% | 0% (correct) |
| HALTED | 1.0 | 0% | 0% (correct) |
| DEFENSIVE | 0.5 | 0% | ~20% (hasty fighting position) |
| DUG_IN | 0.0 | 0% | ~50% (prepared position) |
| FORTIFIED | 0.0 | 0% | ~70% (hardened position) |
DUG_IN/FORTIFIED units take the same casualties as units in the open. The only benefit is speed=0 (they don't move). Terrain cover from obstacles provides some protection, but posture itself does not.
C2 Authority Not Enforced¶
- ROE: Works. Engagement gated by ROE level per target category.
- Command authority: Not enforced. Any unit engages any target regardless of command chain.
- Orders → behavior: Orders are not consumed. Units don't read orders to modify target selection or movement.
- Comms loss → independent action: Comms degradation affects assessment confidence but not engagement rules. A unit with zero comms fights identically to one with perfect comms.
CalibrationSchema Fields Never Exercised¶
16 calibration fields have defaults but are never set by any scenario YAML (confirmed via YAML audit):
disable_threshold, dew_disable_threshold, dig_in_ticks, wave_interval_s, target_selection_mode, night_thermal_floor, wind_accuracy_penalty_scale, rain_attenuation_factor, c2_min_effectiveness, enable_fog_of_war, engagement_concealment_threshold, target_value_weights, gas_casualty_floor, gas_protection_scaling, subsystem_weibull_shapes, victory_weights
Note: observation_decay_rate was previously listed but is set in at least one scenario YAML.
Triage Framework¶
Every identified gap must be triaged before implementation. This prevents scope creep and ensures we focus on high-impact work.
Priority Levels¶
| Priority | Criterion | Action | Examples |
|---|---|---|---|
| P0: Must Wire | Existing code with clear consumer path; high fidelity impact; missing wiring is a bug | Wire in this block | Rain detection factor (function exists, never called), air combat routing, damage detail extraction, posture protection |
| P1: Should Wire | Moderate fidelity impact; straightforward integration; improves realism noticeably | Wire in this block | Seasonal trafficability → movement, obscurants → detection, radar horizon, HF quality → comms |
| P2: Wire If Time | Lower fidelity impact; useful but not essential; may require new code beyond simple wiring | Wire if ahead of schedule | Fire spread model, altitude sickness, wave period resonance, biological sonar noise |
| P3: Defer | Edge cases, very low impact, or requires significant new architecture | Document and defer to future block | Spin drift, soil CBRN absorption, dynamic cratering, Faraday rotation |
| P4: Remove | Computed values with no meaningful consumer; dead code that generates false audit findings | Delete computation | shadow_azimuth (no consumer), deep_channel_depth (niche), solar/lunar decomposition (diagnostic only) |
Triage: Environment Parameters (36 items)¶
| Parameter | Priority | Rationale |
|---|---|---|
_compute_rain_detection_factor() — function exists, never called |
P0 | Bug — implemented ITU-R P.838 model, zero call sites |
| DEW humidity/precip_rate — params accepted, never passed | P0 | Bug — physics model exists, call site doesn't pass values |
| SeasonsEngine.mud_depth → movement | P1 | Rasputitsa, WW1 mud — major historical effect |
| SeasonsEngine.snow_depth → movement | P1 | Eastern Front, Korean War — major historical effect |
| SeasonsEngine.vegetation_density → detection | P1 | Seasonal concealment — moderate historical effect |
| SeasonsEngine.sea_ice_thickness → crossing | P1 | Eastern Front frozen rivers — scenario-specific |
| ObscurantsEngine (full instantiation + wiring) | P1 | Smoke screens, dust trails — significant tactical effect |
| EMPropagation.radar_horizon → detection | P1 | Earth curvature on radar — fundamental physics |
| EMPropagation.hf_quality → comms | P1 | Day/night HF reliability — affects WW2/historical comms |
| EMPropagation.atmospheric_attenuation → radar/comms | P1 | Rain loss on high-freq systems — moderate effect |
| EMPropagation.ducting → radar range | P1 | Maritime radar extension — scenario-specific |
| UnderwaterAcoustics.thermocline → sonar | P1 | ASW layer tactics — fundamental naval effect |
| UnderwaterAcoustics.convergence_zones → sonar | P1 | 55km detection rings — fundamental ASW |
| SeaState.tidal_current → ship movement | P1 | Ship routing, mine drift — moderate effect |
| TimeOfDay.background_temp → thermal ΔT detection | P1 | Thermal crossover vulnerability — real planning factor |
| TimeOfDay.nvg_effectiveness → detection | P1 | NVG-equipped night detection — moderate effect |
| WeatherEngine.wind.gust → operation gates | P2 | Helicopter abort, parachute accuracy — niche |
| WeatherEngine.pressure → air density | P2 | Ideal gas correction — small effect at sea level |
| SeasonsEngine.vegetation_moisture → fire | P2 | Fire ignition probability — requires fire system |
| SeasonsEngine.wildfire_risk → fire events | P2 | Spontaneous fire — requires fire system |
| SeasonsEngine.daylight_hours → ops planning | P2 | Operational tempo — low tactical impact |
| SeaState.wave_period → ship resonance | P2 | Roll amplitude — niche effect |
| SeaState.beaufort → small craft gate | P2 | Landing craft operations — scenario-specific |
| UnderwaterAcoustics.surface_duct → sonar | P2 | In-duct detection — niche ASW |
| Terrain.vegetation_height → LOS | P2 | Ground-level vegetation block — moderate |
| Terrain.combustibility → fire | P2 | Fire ignition — requires fire system |
| Obstacles.traversal_risk → casualties | P2 | Wire crossing casualties — niche |
| Obstacles.traversal_time → movement | P2 | Obstacle delay — moderate |
| Hydrography.ford_points → crossing | P2 | River ford routing — scenario-specific |
| Infrastructure.bridge_capacity → weight gate | P2 | Heavy vehicle bridge limit — niche |
| TimeOfDay.shadow_azimuth | P4 | No meaningful consumer — remove |
| TimeOfDay.solar/lunar contribution split | P4 | Diagnostic only — remove computation |
| UnderwaterAcoustics.deep_channel_depth | P3 | SOFAR channel — very niche |
| Equipment.temperature_range → stress | P2 | Weapon jam in extreme cold/heat — moderate |
| Infrastructure.Road.speed_factor override | P3 | Per-road speed — low impact vs hardcoded table |
| Infrastructure.Tunnel routing | P3 | Tunnel in pathfinding — niche |
Triage: Combat Integration (16+ items)¶
| Gap | Priority | Rationale |
|---|---|---|
| Air combat routing (AIR_TO_AIR, AIR_TO_GROUND, SAM) | P0 | 3 engines exist with correct physics; currently air duels use ground combat Pk |
| Damage detail extraction (casualties, systems_damaged) | P0 | DamageEngine computes it; discarding is a bug |
| Posture → damage reduction (DUG_IN/FORTIFIED protection) | P0 | DUG_IN providing zero protection is a bug |
| MISSILE engagement routing | P1 | MissileEngine exists; missiles currently route as DIRECT_FIRE or COASTAL_DEFENSE |
| IncendiaryDamageEngine → fire zones | P1 | Engine exists; fire_started from DamageResult should trigger it |
| CarrierOpsEngine → naval air | P1 | CAP management, recovery windows — significant for naval scenarios |
| SiegeEngine → campaign loop | P2 | Ancient/medieval siege — era-specific |
| AmphibiousAssaultEngine → naval ops | P2 | Beach assault state machine — scenario-specific |
| UXOEngine → post-engagement | P2 | Submunition contamination — niche |
| NavalOarEngine → ancient naval | P3 | Ancient trireme propulsion — era-specific niche |
| VisualSignalsEngine → ancient C2 | P3 | Ancient visual communication — era-specific niche |
| StrategicBombingEngine → WW2 campaign | P2 | Strategic air campaign — era-specific |
| StrategicTargetingEngine → bombing | P2 | Target prioritization — paired with StrategicBombing |
| AirCampaignEngine → campaign loop | P2 | Campaign-level air operations — moderate |
| MissileDefenseEngine → AD | P2 | Air defense missiles — moderate |
Triage: Cross-Module Integration¶
| Gap | Priority | Rationale |
|---|---|---|
| Fuel consumption → movement gate | P0 | Fundamental logistics — units at 0 fuel should not move |
| Ammo depletion → firing gate | P0 | Unit fires at 0 ammo — bug |
| Maintenance/readiness → combat gate | P1 | Disabled equipment should degrade combat performance |
| Medical RTD → unit strength restoration | P1 | Treated casualties should return to duty |
| Detection → AI assessment (use FOW contacts, not ground truth) | P1 | AI has perfect information — defeats purpose of detection system |
| Comms loss → C2 degradation → independent action | P1 | Comms down should force units to last received orders |
| Checkpoint state registration | P1 | Checkpoint saves nothing — defeats purpose of checkpoint system |
| Event bus functional subscribers | P2 | Most events are consumed via direct passing; event subscribers are optional improvement |
| Supply route interdiction → supply shortage | P2 | Logistics feedback loop — moderate |
| CalibrationSchema exercised in scenarios | P2 | 16 fields never set — either exercise or remove |
Structural Verification Tests¶
These tests must be created before implementation begins and run continuously to prevent regression.
Test 1: Unconsumed Parameter Audit¶
def test_no_unconsumed_engine_outputs():
"""Every engine property computed during simulation is read by at least one consumer."""
# Instrument all engine classes with property access tracking
# Run a representative scenario with all systems active
# Collect set of properties that were written but never read
# Assert empty set (or only P4-triaged items)
Implementation: Monkey-patch engine classes with __getattr__/__setattr__ tracking, or use a coverage-like instrumentation approach. Run a modern scenario + one historical scenario to exercise all code paths.
Test 2: Dead Method Audit¶
def test_no_uncalled_public_methods():
"""Every public method on every engine class has at least one external caller."""
# AST-parse all source files
# Build method definition set (all public methods on engine classes)
# Build call site set (all method calls across all source files)
# Assert: definitions ⊆ call sites (minus test-only callers)
Implementation: Use ast.parse() to walk source trees. Flag any public method defined in stochastic_warfare/ that has zero call sites outside its own module and tests.
Test 3: Event Subscription Audit¶
def test_all_event_types_have_subscribers():
"""Every event type published in the simulation has at least one functional subscriber."""
# AST-parse all source files for bus.publish(EventType(...))
# AST-parse all source files for bus.subscribe(EventType, handler)
# Assert: every published type has at least one subscriber (beyond Recorder)
# OR: published type is in OBSERVATION_ONLY_EVENTS allowlist
Test 4: Engagement Routing Completeness¶
def test_all_engagement_types_routed():
"""Every EngagementType enum value has a handler in the battle loop."""
# For each EngagementType value
# Assert: route_engagement() or _infer_engagement_type() can produce it
# AND: a handler exists that resolves it
Test 5: Feedback Loop Verification¶
def test_logistics_gates_combat():
"""Unit with depleted ammo cannot fire; unit with depleted fuel cannot move."""
def test_damage_detail_applied():
"""DamageResult casualties are extracted and reduce unit personnel count."""
def test_posture_protection():
"""DUG_IN unit takes less damage than MOVING unit from same attack."""
def test_checkpoint_state_round_trip():
"""Checkpoint saves and restores all module state, not just clock/RNG."""
Theme 1: Environmental Fidelity Gap Analysis (Priority: Highest)¶
The environment subsystem has rich physics models whose outputs are largely ignored. This section is an exhaustive, domain-by-domain audit of every environmental parameter — what's computed, what's consumed, and what's missing entirely. The goal is "excruciatingly exact" fidelity: every computed value consumed, every real-world effect that matters at campaign/battle scale represented.
Legend¶
- WIRED: Computed and consumed by downstream combat/movement/detection systems
- COMPUTED/UNCONSUMED: Engine calculates the value every tick, but no system reads it
- DEFINED/UNCALLED: Method or API exists in source code but is never invoked
- NOT IMPLEMENTED: Physics model doesn't exist yet but should for high fidelity
1.1 Atmospheric Physics¶
Air Density & Pressure¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Air density (altitude-dependent) | WIRED (partial) | Exponential model in ballistics (scale height 8500m). Used for Mach drag. | Also needed for: aircraft engine performance, helicopter lift margin, DEW thermal blooming, unguided rocket range |
| Barometric pressure | NOT IMPLEMENTED | WeatherEngine computes pressure field but it's never consumed anywhere |
Should feed air density via ideal gas law (ρ = P/RT). Affects ballistic drag, acoustic propagation, altimeter accuracy |
| Humidity → air density | NOT IMPLEMENTED | Humidity computed in WeatherEngine, never affects air density | Moist air is ~0.5% less dense than dry air. Small effect but contributes to density altitude calculation |
| Temperature lapse rate | NOT IMPLEMENTED | Ballistics uses constant temperature at all altitudes | ISA lapse rate (−6.5°C/km to tropopause, isothermal above). Affects speed of sound, Mach number, drag coefficient at altitude |
| Density altitude | COMPUTED/UNCONSUMED | ConditionsEngine.air().density_altitude computed |
Should gate: helicopter operations (high+hot = no-go), aircraft takeoff distance, engine power output |
Wind¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Mean wind (speed, direction) | WIRED | Ornstein-Uhlenbeck process, consumed by crosswind penalty, CBRN drift, obscurant drift | — |
| Wind gusts | COMPUTED/UNCONSUMED | WeatherEngine.wind.gust computed every tick |
Should affect: helicopter operations (gust > threshold = abort landing), bridge-laying operations, parachute drop accuracy, amphibious small craft capsizing |
| Wind shear (altitude-dependent) | NOT IMPLEMENTED | Wind is constant at all altitudes | Real wind varies with altitude (boundary layer). Affects artillery at high angles, parachute drift, aircraft approach. Model: log wind profile or power law |
| High wind halt threshold | NOT IMPLEMENTED | No maximum wind speed for operations | Should force infantry to halt in extreme wind (>25 m/s / ~50 mph), prevent helicopter operations, degrade vehicle stability |
| Turbulence | NOT IMPLEMENTED | Only mean wind modeled | Adds stochastic dispersion to ballistic trajectories, parachute drops, helicopter hover stability. Model: σ_wind as fraction of mean wind |
Temperature¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Ambient temperature | WIRED | Diurnal cycle + monthly mean. Fed to ballistics (speed of sound), weather state transitions | — |
| Temperature at altitude | COMPUTED/UNCONSUMED | WeatherEngine.temperature_at_altitude() exists |
Should drive lapse rate calculations, icing determination, engine performance curves |
| Temperature inversion | NOT IMPLEMENTED | No inversion layer detection | Critical for: CBRN (traps agents below inversion, 10x concentration increase), EM ducting (extends radar range), acoustic propagation (sound channels). Model: detect when temperature increases with altitude |
| Propellant temperature → muzzle velocity | NOT IMPLEMENTED | All rounds assume nominal MV | Cold propellant (−20°C) reduces MV by 2–5%. Hot propellant (+50°C) increases MV by 1–3%. Affects range tables for artillery. Source: MIL-STD-1474 |
| Equipment temperature stress | DEFINED/UNCALLED | EquipmentItem.temperature_range defined in YAML, EquipmentManager.environment_stress() computes degradation factor |
Degradation factor never applied in simulation loop. Should affect: weapon reliability (jams in extreme cold/heat), electronics failure rate, battery capacity |
Icing¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Icing risk | COMPUTED/UNCONSUMED | ConditionsEngine.air().icing_risk calculated (temperature 0 to −20°C + cloud/precip) |
Should affect: aircraft performance (wing ice = lift loss, engine ice = power loss), helicopter blade ice, radar dome ice (degrades signal), weapon system freeze-up |
| Road/runway icing | NOT IMPLEMENTED | No surface ice model | Snow/ice on runways should degrade aircraft operations. Road ice should reduce vehicle traction. Model: surface temperature < 0°C + precipitation = ice |
1.2 Optical & Visual Environment¶
Illumination & Visibility¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Total illumination (lux) | WIRED | Solar + lunar + cloud cover → detection range modifier | — |
| Twilight stages (5-level) | WIRED | Civil/nautical/astronomical/full night → graduated visual/thermal modifiers | — |
| Weather visibility | WIRED | Weather state → visibility_m → detection range cap | — |
| Solar contribution (decomposed) | COMPUTED/UNCONSUMED | Separated from total lux but only total used | Low value — decomposition is diagnostic data |
| Lunar contribution (decomposed) | COMPUTED/UNCONSUMED | Same as solar | Low value |
| Artificial illumination (flares, searchlights) | DEFINED/UNCALLED | API exists in TimeOfDayEngine (artificial_contribution) but never populated |
Should allow: flare illumination events (brief high-lux area), searchlight beams, urban ambient light. Model: point source with inverse-square falloff |
| Shadow azimuth | COMPUTED/UNCONSUMED | Computed from solar position, never queried | Could affect: visual detection from specific angles (target in shadow harder to spot from shadow side). Low priority |
| NVG effectiveness | COMPUTED/UNCONSUMED | TimeOfDayEngine.nvg_effectiveness() exists |
Partially consumed by movement (0.7x night speed recovery with NVG). NOT consumed by detection engine — NVG-equipped units should detect further at night |
Thermal Environment¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Thermal contrast | WIRED (partial) | TimeOfDayEngine.thermal_environment().thermal_contrast computed. Detection uses illumination-based modifier instead |
Should be the primary driver of thermal detection SNR. Vehicles have high thermal contrast at night (engine heat vs cold background), low at dawn/dusk crossover |
| Background temperature | COMPUTED/UNCONSUMED | Computed as ambient + solar heating + surface material | Should feed thermal detection SNR calculation: target_temp − background_temp = ΔT → SNR. Currently uses generic thermal_contrast scalar instead of physics-based ΔT |
| Thermal crossover timing | COMPUTED/UNCONSUMED | crossover_in_hours computed — tells how long until thermal signatures blend into background |
Should create vulnerability windows: at crossover, thermal detection is near-zero for stationary vehicles. Dawn and dusk crossovers are real-world tactical planning factors |
Obscurants (Smoke, Dust, Fog)¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Smoke cloud deployment | DEFINED/UNCALLED | Full API: deploy_smoke(center, radius, multispectral) in ObscurantsEngine (256 lines) |
Barrages/mortars should spawn smoke at impact. Smoke grenades/pots for deliberate screening. Spectral blocking: visual 0.9, thermal 0.1 (standard) or 0.8 (multispectral), radar 0.0–0.3 |
| Smoke drift & decay | DEFINED/UNCALLED | Wind-driven drift, radial dispersion (r ∝ √t), exponential decay (30min half-life) all implemented | ObscurantsEngine.update() should be called each tick. Currently never instantiated on SimulationContext |
| Dust from vehicle movement | NOT IMPLEMENTED | No dust generation hook in movement | Vehicles on dry terrain (DRY ground_state + non-road) should spawn dust trails. Intensity ∝ speed × vehicle_count. Dust reveals movement (signature enhancement) + degrades following-vehicle LOS |
| Dust from explosions | NOT IMPLEMENTED | Impact detonations don't create dust | HE impacts on dry ground should create short-duration dust clouds at impact site. Affects BDA (can't see if target was hit) |
| Fog auto-generation | DEFINED/UNCALLED | ObscurantsEngine has fog generation when WeatherState.FOG | Never triggered because engine never instantiated. Should auto-create fog patches when weather transitions to FOG. Radiation fog (clear nights), advection fog (warm air over cold water), sea fog |
| Fog dissipation by solar heating | NOT IMPLEMENTED | Fog uses generic exponential decay | Real fog lifts when solar heating warms ground (morning burn-off). Model: fog opacity × (1 − solar_heating_factor) |
| Spectral opacity query | DEFINED/UNCALLED | opacity_at(pos) returns per-spectrum opacity (visual, thermal, radar) |
Should be queried by: detection engine (degrade SNR by spectrum), combat engine (reduce Pk for visual/thermal-guided weapons), DEW engine (attenuate beam) |
| Pre-placed smoke/fog in scenarios | NOT IMPLEMENTED | No scenario YAML field for initial obscurant placement | Allow environment_config.smoke_zones and fog_zones for historical accuracy (Austerlitz morning fog, Falklands sea fog, WW1 smoke barrages) |
1.3 Electromagnetic Environment¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| GPS accuracy | WIRED | EMPropagationEngine → detection/space/EW integration | — |
| GPS spoofing offset | WIRED | EW module → EMPropagation → position error | — |
| GPS jam degradation | WIRED | EW module → EMPropagation → accuracy degradation | — |
| Free-space path loss | COMPUTED/UNCONSUMED | free_space_path_loss(freq, range) public API exists, only called internally |
Should be used by: communications range calculation, radar detection range, EW intercept range |
| Radar horizon | DEFINED/UNCALLED | radar_horizon(antenna_height) computes 4/3 Earth radius geometric horizon |
Should gate air defense radar detection range. Currently detection uses fixed max_range_m from sensor YAML, ignoring Earth curvature. A ground radar at 10m height has ~13km horizon; at 30m, ~22km. Low-flying aircraft below horizon are invisible to radar |
| Atmospheric attenuation (freq-dependent) | COMPUTED/UNCONSUMED | Computed per frequency band (O₂ absorption peak at 60 GHz, water vapor at 22 GHz) | Should attenuate radar and comms at high frequencies. X-band (10 GHz) loses ~0.01 dB/km dry, ~0.1 dB/km in rain. Ka-band (35 GHz) loses ~0.4 dB/km in rain |
| EM ducting (super-refraction) | COMPUTED/UNCONSUMED | ducting_possible and refraction factor computed based on humidity + temperature gradient |
Should extend radar and comms range beyond geometric horizon in warm, humid maritime environments (common in Persian Gulf, South China Sea). Factor of 2–3x range extension |
| Duct height | COMPUTED/UNCONSUMED | Computed but never read | Determines which systems benefit from ducting (antenna must be within duct layer) |
| HF propagation quality (day/night) | COMPUTED/UNCONSUMED | hf_propagation_quality() computes D-layer absorption (day) vs F-layer reflection (night) |
Should modulate HF radio reliability in communications engine. Day: D-layer absorbs → short HF range. Night: F-layer reflects → long HF range (skip propagation). Critical for WW2, some modern scenarios |
| Rain clutter on radar | DEFINED/UNCALLED | _compute_rain_detection_factor(precip_rate, range) implemented in battle.py with ITU-R P.838 model but never called |
Should reduce radar detection probability in rain. Heavy rain (25 mm/hr) creates radar returns that mask targets. Already implemented — just needs a call site |
| Frequency-dependent rain attenuation for comms | NOT IMPLEMENTED | Generic comms model doesn't consider frequency | UHF (300 MHz–3 GHz): negligible rain attenuation. SHF (3–30 GHz): significant. EHF (30–300 GHz): severe. Should vary comms reliability by frequency band in rain |
| Tropospheric ducting for radio | NOT IMPLEMENTED | Only modeled for radar, not comms | Same physics extends radio comms range in certain weather conditions. Common in maritime operations |
| Ionospheric storm effects | NOT IMPLEMENTED | No space weather model | Solar flares and geomagnetic storms degrade HF comms for hours to days. Model: random events with probability ∝ solar cycle |
| Radio horizon (altitude-dependent) | NOT IMPLEMENTED | Only radar_horizon() exists for radar |
Identical physics applies to radio — higher antenna = longer range. Mobile units at different altitudes have different comms range. Model: same as radar_horizon but for comms |
1.4 Acoustic Environment¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Sound velocity profile (SVP) | WIRED | Mackenzie equation (T, S, depth) → sonar detection | — |
| Ambient noise (Wenz curves) | WIRED | Beaufort → dB ambient noise → sonar SNR threshold | — |
| Transmission loss | WIRED | Spherical spreading + absorption → sonar range | — |
| Surface duct depth | COMPUTED/UNCONSUMED | Calculated from temperature profile but never used | Sonar trapped in surface duct has enhanced range within duct but cannot detect below it. Submarine can hide below duct. Model: if target_depth > duct_depth, add 20 dB loss |
| Thermocline depth | COMPUTED/UNCONSUMED | Calculated but never used in detection | Layer below which sound bends downward. Submarine below thermocline is very difficult to detect from surface sonar. Critical for ASW tactics |
| Deep sound channel depth | COMPUTED/UNCONSUMED | Calculated but never used | SOFAR channel enables detection at extreme ranges (hundreds of km). Low priority — mostly for fixed sonobuoy networks |
| Convergence zone ranges | COMPUTED/UNCONSUMED | convergence_zone_ranges(source_depth) calculates 55km interval CZ detections |
Should create detection "rings" at 55km, 110km, 165km from sonar source. Target between zones is in shadow. Fundamental to deep-water ASW |
| Shipping noise | NOT IMPLEMENTED | Only wind-driven Wenz curve ambient noise | Busy shipping lanes increase ambient noise, degrading sonar. Model: proximity to shipping lanes → +5–15 dB ambient noise |
| Biological noise | NOT IMPLEMENTED | No marine life noise model | Whale song, snapping shrimp can mask sonar contacts in certain waters/seasons. Low priority — niche effect |
1.5 Ground & Terrain Environment¶
Seasonal Ground State¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Ground trafficability (seasonal) | WIRED (partial) | SeasonsEngine → ground_trafficability scalar consumed by MovementEngine |
Currently uses coarse lookup: FROZEN=0.9, THAWING=0.3, WET=0.6, DRY=1.0, SATURATED=0.2, SNOW=0.5. Wired but should also differentiate wheeled vs tracked (wheeled suffer more in mud) |
| Mud depth | COMPUTED/UNCONSUMED | SeasonalConditions.mud_depth accumulated from rain + thaw |
Should provide granular speed penalty beyond binary trafficability. Deep mud (>20cm) immobilizes wheeled vehicles entirely. Tracked vehicles at 50% speed. Logistics transport has mud_speed_fraction=0.5 but battle movement ignores mud depth |
| Snow depth | COMPUTED/UNCONSUMED | SeasonalConditions.snow_depth accumulated from snowfall |
Deep snow (>30cm) should slow infantry to 40% speed, vehicles to 60%. Snow on roads should degrade road speed bonus. Plowed roads partially recover. Ski troops should have reduced penalty |
| Vegetation density | COMPUTED/UNCONSUMED | Sigmoid of growing-degree-days, 0.0–1.0 | Should modify: visual detection concealment (summer foliage hides, winter bare exposes), movement speed through dense vegetation, fire spread rate |
| Vegetation moisture | COMPUTED/UNCONSUMED | Tracked alongside vegetation density | Should affect: fire spread probability (dry vegetation burns easily, wet doesn't), agent persistence (moist surfaces break down chemical agents faster) |
| Sea ice thickness | COMPUTED/UNCONSUMED | Accumulated from freezing degree-days, latitude > 50° | Should enable: ice crossing for infantry (>10cm), light vehicles (>30cm), heavy vehicles (>60cm). Model: weight-dependent ice failure threshold. Critical for Eastern Front (crossing frozen rivers), Finnish Winter War, Korean War Chosin Reservoir |
| Wildfire risk | COMPUTED/UNCONSUMED | Composite of dryness × heat × wind × low humidity | Should trigger: random wildfire events in high-risk areas, fire spread after incendiary strikes. Feeds fire zone system |
| Daylight hours | COMPUTED/UNCONSUMED | From astronomy day_length_hours | Should affect: operational planning (short winter days = less time for maneuver), fatigue accumulation rate, solar panel power for unmanned systems |
| Rasputitsa (spring mud season) | PARTIALLY IMPLEMENTED | Mud depth mechanics exist but transitions not dramatic enough | Historical spring mud seasons halted entire armies (Eastern Front 1941, 1942, 1943, 1944). Thawing ground + rain should create impassable conditions lasting weeks. Model: THAWING state + rain → SATURATED with mud_depth spike |
Terrain Properties¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Vegetation height | COMPUTED/UNCONSUMED | TerrainProperties.vegetation_height per land cover class |
Should affect: visual detection (tall vegetation conceals vehicles at distance), LOS check (thick vegetation blocks LOS at ground level), helicopter landing clearance |
| Combustibility | COMPUTED/UNCONSUMED | TerrainProperties.combustibility per land cover class (e.g., dry_grass=0.9, urban=0.2) |
Should feed fire zone creation: incendiary weapons on high-combustibility terrain create fires; on low-combustibility terrain they don't. Currently defined but never read |
| Obstacle traversal risk | DEFINED/UNCALLED | Obstacle.traversal_risk defined in obstacle model |
Should apply: casualty probability when crossing obstacles (e.g., wire, minefield, rubble). Currently obstacles are binary pass/block |
| Obstacle traversal time | DEFINED/UNCALLED | Obstacle.traversal_time_multiplier defined |
Should slow units crossing obstacles (wire obstacles = 3x time, rubble = 2x, water = 4x). Currently hardcoded in movement |
| Ford points | DEFINED/UNCALLED | Hydrography.is_fordable(), ford_points_near() implemented |
Should enable river crossing at ford points with depth/current-dependent time cost. Currently river crossing is binary passable/not-passable |
| Bridge capacity | DEFINED/UNCALLED | Bridge.capacity_tons defined |
Should gate heavy vehicles on bridges (MBT at 60+ tons can't cross a 20-ton bridge). Currently all bridges passable by all units |
| Tunnel routing | DEFINED/UNCALLED | Tunnel geometry defined in infrastructure |
Should be available in pathfinding for protection from air attack. Currently never routed |
| Road speed factor override | DEFINED/UNCALLED | Road.speed_factor field exists |
Currently uses hardcoded _ROAD_SPEED_FACTORS dict instead of per-road values. Should use road-specific factors (highway vs dirt road vs track) |
| Soil type → dig-in time | NOT IMPLEMENTED | All terrain has same dig-in rate | Sandy soil: fast digging, poor fortification. Rocky soil: slow digging, good fortification. Frozen ground: very slow digging. Clay: moderate. Model: soil_type multiplier on dig_in_ticks |
| Dynamic terrain (cratering) | NOT IMPLEMENTED | Heightmap is static | Heavy artillery should create craters that affect movement and provide cover. Low priority — high implementation cost (pathfinding cache invalidation) |
1.6 Maritime Environment¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Wave height (Pierson-Moskowitz) | WIRED | Sig. wave height → naval gunnery dispersion, carrier bolter probability, amphibious penalty | — |
| Wave period | COMPUTED/UNCONSUMED | Computed from wave spectrum | Should affect: ship resonance (period matching hull natural frequency = extreme roll), helicopter deck landing difficulty. Model: roll amplitude ∝ 1/( |
| Tide height | WIRED (partial) | Harmonic model (M2/S2/K1/O1), consumed by amphibious calculations | Should also affect: shallow-water navigation (ground contact risk), beach approach timing, submarine depth clearance in littoral waters |
| Tidal current (speed, direction) | COMPUTED/UNCONSUMED | Computed from tidal harmonics but never consumed | Should affect: ship movement speed (with/against current), mine drift (floating mines move with current), submarine station-keeping effort, amphibious assault beach approach vector |
| SST (sea surface temperature) | WIRED (partial) | Fed to underwater acoustics SVP calculation | — |
| Beaufort scale | WIRED (partial) | Drives sonar ambient noise (Wenz curves) | Should also affect: small craft operations (Beaufort > 5 = dangerous for landing craft), deck operations, helicopter landing, radar sea clutter |
| Sea spray/salt fog | NOT IMPLEMENTED | No maritime atmospheric effect | Sea spray in high winds creates: visual obscuration (like fog, reduces visibility to 1–3 km), DEW attenuation (10× worse than clean air — salt crystals scatter laser), radar clutter (close-range noise from spray droplets), corrosion (long-term equipment degradation) |
| Swell direction vs ship heading | NOT IMPLEMENTED | Wave height is scalar, no direction | Beam seas (waves perpendicular to ship) cause maximum roll; head seas cause pitching; following seas are smoothest. Affects gunnery accuracy, helicopter ops, crew fatigue. Model: roll_factor = sin²(wave_dir − ship_heading) |
| Polar ice navigation | NOT IMPLEMENTED | No ice obstacle for ships | Ice fields should block or slow ships without icebreaker capability. Ice thickness from SeasonsEngine.sea_ice_thickness. Only relevant for Arctic/Antarctic scenarios |
| Littoral current effects | NOT IMPLEMENTED | No coastal current model | Near-shore currents affect: mine drift, amphibious approach, submarine navigation. Could use tidal current as proxy in shallow water |
1.7 CBRN Environment Interaction¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Wind advection of puffs | WIRED | Gaussian puff center moves with wind vector | — |
| Pasquill-Gifford stability class | WIRED | Cloud cover + wind speed + time of day → stability (A–F) | — |
| Terrain channeling | WIRED | Valley concentration (+50%), ridge deflection (×0.5) | — |
| Rain washout of agents | NOT IMPLEMENTED | Rain has no effect on airborne CBRN concentration | Rain scavenges particles and droplets from air. Model: concentration × exp(−washout_coeff × rain_rate × dt). Washout coefficient ~10⁻⁴ per mm/hr for particles. 30 mm/hr rain removes ~30% of agent in 30 minutes |
| Temperature → agent persistence | NOT IMPLEMENTED | Agent decay rate is constant | Nerve agents: half-life 8 hrs at 20°C, 2 hrs at 40°C, 24+ hrs at 0°C. Mustard: persists for days/weeks in cold. Model: decay_rate × exp(−Ea/RT) Arrhenius kinetics |
| UV hydrolysis (sunlight degradation) | NOT IMPLEMENTED | No solar degradation of agents | Direct sunlight breaks down many chemical agents. Agent concentration should decrease faster in daytime CLEAR weather. Model: +solar_degradation when is_day and cloud_cover < 0.5 |
| Temperature inversion trapping | NOT IMPLEMENTED | No inversion detection | Agent trapped below temperature inversion layer reaches 5–10× higher concentration than open-air dispersal. Critical for valley/urban releases at night. Model: if inversion detected, multiply concentration by trapping_factor |
| Surface roughness → mixing height | NOT IMPLEMENTED | Single mixing height for all terrain | Urban terrain has higher surface roughness → lower effective stack height → higher ground-level concentration. Open terrain has lower roughness → better vertical mixing → lower concentration. Model: roughness_length per terrain type |
| Soil absorption of agents | NOT IMPLEMENTED | No ground interaction | Liquid agents pool on ground, creating contact hazard distinct from inhalation. Absorption rate depends on soil porosity. Model: deposition_velocity × concentration → ground_contamination_flux |
| Agent re-aerosolization | NOT IMPLEMENTED | Once deposited, agent is gone | Wind and vehicle traffic can re-aerosolize deposited agents from ground surfaces. Creates secondary hazard hours/days after initial release. Model: re-emission_rate ∝ wind_speed × ground_contamination |
1.8 Equipment & Materiel Environment Interaction¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Equipment temperature range | DEFINED/UNCALLED | EquipmentItem.temperature_range = (-40, 50) defined, environment_stress() computes degradation |
Degradation factor never applied. Should increase weapon jam rate, electronics failure rate, engine stall probability when temperature outside rated range |
| Propellant temperature → MV | NOT IMPLEMENTED | Constant muzzle velocity | Cold propellant (−20°C): −2 to −5% MV. Hot propellant (+50°C): +1 to +3% MV. Directly affects range. Source: MIL-STD-1474. Model: MV × (1 + temp_coefficient × ΔT) where temp_coefficient ≈ 0.001/°C |
| Lubricant viscosity | NOT IMPLEMENTED | Constant weapon reliability | Cold thickens lubricant → increased malfunction rate. Desert heat thins lubricant → increased wear. Model: reliability_modifier = f(temperature, lubricant_type) |
| Battery capacity at temperature | NOT IMPLEMENTED | Constant electronics availability | Li-ion at −20°C: ~50% capacity. Affects: radio endurance, NVG duration, GPS receiver, UAV flight time. Model: capacity × battery_temp_curve(T) |
| Fuel viscosity/gelling | NOT IMPLEMENTED | Constant fuel availability | Diesel gels at −10 to −20°C without arctic additives. Jet fuel (JP-8) freeze point −47°C. Model: fuel_available = temperature > gel_point |
| Engine performance vs altitude | COMPUTED/UNCONSUMED | ConditionsEngine.air().density_altitude exists |
Naturally aspirated engines lose ~3% power per 300m altitude. Turbocharged engines less affected. Turbofan thrust decreases linearly above tropopause. Model: power × (1 − altitude_derating × alt/ref_alt) |
| Dust ingestion on engines | NOT IMPLEMENTED | No desert reliability penalty | Sand/dust degrades engine filters → power loss → eventual failure. Desert operations have 3–5× higher maintenance rates. Model: reliability_modifier in dusty terrain |
| Corrosion in maritime environment | NOT IMPLEMENTED | No salt spray effect | Salt air increases equipment failure rate. Extended maritime operations degrade weapons/electronics. Very low priority — long time scale |
1.9 Human Factors & Environment¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Heat stress / heat casualties | NOT IMPLEMENTED | Temperature has no effect on personnel | WBGT > 32°C (wet-bulb globe temperature) + physical exertion → heat casualties. Model: heat_casualty_rate ∝ f(temperature, humidity, MOPP_level, exertion). MOPP-4 in hot weather can cause 10–20% non-combat casualties per hour |
| Cold injury (frostbite/hypothermia) | NOT IMPLEMENTED | Temperature has no effect on personnel | Wind chill < −25°C with prolonged exposure → cold casualties. Model: cold_casualty_rate ∝ f(wind_chill, exposure_time, clothing_level). Critical for: Chosin Reservoir, Stalingrad, Eastern Front winter |
| Altitude sickness | NOT IMPLEMENTED | No altitude effect on personnel performance | Above 2500m: performance degrades. Above 4000m: incapacitation without acclimatization. Model: performance_modifier = max(0.5, 1 − 0.03 × (altitude − 2500)/100) above 2500m |
| Fatigue from environmental stress | PARTIALLY WIRED | Movement fatigue modeled (speed reduction), not temperature/altitude driven | Temperature extremes and altitude should accelerate fatigue. Model: fatigue_rate × environmental_stress_factor where stress = f(temp_deviation_from_comfort, altitude, MOPP_level) |
| MOPP degradation | PARTIALLY WIRED | MOPP reduces movement speed | Should also reduce: visual detection (hood restricts FOV), manual dexterity (gloves reduce reload speed), communications (mask muffles voice), thermal stress (accelerates heat casualties). Currently only speed reduction |
| Wind chill | NOT IMPLEMENTED | No wind chill calculation | Wind chill = 13.12 + 0.6215T − 11.37V^0.16 + 0.3965TV^0.16. Drives cold injury rate. Model: straightforward formula from T and wind_speed |
| Dehydration in hot environments | NOT IMPLEMENTED | No water consumption model | Hot + dry + high exertion = 1L/hr water consumption. Running out degrades performance → casualties. Mostly a logistics concern, but affects operational tempo |
1.10 Ballistics Environment Interaction¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Wind deflection on projectile | WIRED | RK4 integrator includes wind velocity vector | — |
| Mach-dependent drag | WIRED | Temperature-dependent speed of sound → Mach → drag multiplier | — |
| Air density at altitude | WIRED (partial) | Exponential atmosphere model used in drag calculation | Should also use pressure and humidity for true density (ideal gas + humidity correction). Currently uses fixed scale-height model |
| Coriolis effect | WIRED (optional) | Earth rotation deflection, gated by flag | — |
| Humidity → drag | NOT IMPLEMENTED | Constant air composition assumed | ~0.5% effect on density; negligible for most weapons, measurable for long-range artillery. Low priority |
| Spin drift (gyroscopic precession) | NOT IMPLEMENTED | No spin-stabilized projectile drift | Rifled projectiles drift ~0.1 mil per 1000m range. Accumulates over long range. Model: drift_angle = spin_drift_constant × range. Low priority — small compared to wind |
| Rain impact on trajectory | NOT IMPLEMENTED | Rain doesn't affect ballistics | Heavy rain creates slight deceleration on slow projectiles (mortar). Negligible for high-velocity rounds. Very low priority |
| DEW thermal blooming | NOT IMPLEMENTED | No self-defocus at high power | High-power laser heats air along beam path → refractive index change → beam spreads. Model: blooming_factor = (1 + power/P_critical × range²/range_ref²). Limits effective DEW range in warm/humid air |
| DEW sea spray attenuation | NOT IMPLEMENTED | No maritime-specific DEW degradation | Sea spray extinction ~10 dB/km vs 0.2 dB/km in clean air. Makes shipboard laser weapons much less effective in high sea states. Model: maritime_extinction = base_extinction + sea_spray_factor(beaufort) |
| DEW dust attenuation | NOT IMPLEMENTED | Dust treated same as rain | Dust is ~10× more attenuating than rain at same precipitation-equivalent. Desert dust storms should severely degrade DEW. Model: dust_extinction = dust_density × mass_extinction_coefficient |
| Rain/fog/dust → DEW atmospheric transmittance | PARTIALLY WIRED | DEW engine accepts humidity/precip_rate parameters | Battle loop never passes environmental parameters to DEW engine. The physics model exists — the call site doesn't pass the values |
1.11 Communications Environment Interaction¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Terrain LOS for comms | WIRED | Diffraction loss (6 dB) when terrain blocks LOS | — |
| Distance path loss | WIRED | Range-dependent link budget | — |
| HF propagation quality | COMPUTED/UNCONSUMED | EMPropagation.hf_propagation_quality() computes D-layer/F-layer effects by time of day |
Should modulate HF radio reliability. Day: D-layer absorbs → short range only. Night: F-layer reflects → long range (skip propagation). Transforms HF comms from constant-reliability to diurnally-variable |
| Frequency-dependent rain attenuation | NOT IMPLEMENTED | Generic comms model ignores frequency | UHF (300 MHz – 3 GHz): negligible rain loss. SHF (3–30 GHz): 0.1–10 dB/km. EHF (30–300 GHz): severe. SATCOM uplinks (SHF/EHF) should degrade in rain. Model: ITU-R P.838 attenuation per frequency band |
| Radio horizon (altitude-dependent) | NOT IMPLEMENTED | Comms range is fixed | Same 4/3 Earth radius model as radar. Two units at 2m height have ~11 km radio horizon. One at 2m, one at 30m: ~28 km. Mountain-top relay extends dramatically. Model: reuse radar_horizon() for comms |
| Altitude → comms range | NOT IMPLEMENTED | No altitude benefit for comms | Higher antenna = longer radio range. Aircraft-to-ground comms have much longer range than ground-to-ground. Should improve comms reliability for airborne C2 nodes |
| Tropospheric ducting for comms | NOT IMPLEMENTED | Only radar ducting modeled | Same physics extends UHF/VHF range in certain weather (warm, humid, maritime). Common in Gulf operations. Model: if ducting_possible, multiply comms_range × duct_extension_factor |
1.12 Air Combat Environment Interaction¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Weather sortie abort | WIRED | Global weather modifier < 0.3 = abort | — |
| Visibility → WVR Pk | WIRED | < 10 km visibility degrades guns/WVR Pk | — |
| Cloud ceiling | COMPUTED/UNCONSUMED | ConditionsEngine.air().cloud_ceiling available |
Should gate: CAS operations (need visual contact with ground target), dive bombing (need to see target from altitude), low-level operations (ceiling < 500m forces low-level flight → increased ground fire risk) |
| Icing risk → aircraft performance | COMPUTED/UNCONSUMED | ConditionsEngine.air().icing_risk calculated |
Wing ice: +15% stall speed, −20% max lift. Engine ice: −10–30% power. Radar dome ice: −3 dB signal loss. Model: if icing_risk > threshold, apply performance penalties + periodic de-ice check |
| Density altitude → performance | COMPUTED/UNCONSUMED | Density altitude calculated | Thin air = longer takeoff, reduced climb rate, lower max speed, reduced helicopter hover ceiling. Model: performance × (ρ/ρ₀) for thrust/lift-dependent parameters |
| Wind → BVR range | NOT IMPLEMENTED | BVR missile range ignores wind | Headwind reduces effective missile range; tailwind extends it. Effect is ~10–15% for strong winds. Model: effective_range = base_range × (1 ± wind_component/missile_speed) |
| Altitude → energy advantage | NOT IMPLEMENTED | Altitude tracked but no energy trading | Higher aircraft has more potential energy → can convert to speed in dive. Lower aircraft must climb (losing speed) to engage. This is fundamental to air combat. Model: energy_state = altitude × g + 0.5 × v² → energy advantage modifier |
| Turbulence → gun accuracy | NOT IMPLEMENTED | Smooth flight assumed | Turbulence degrades gun tracking accuracy. Model: guns_Pk × (1 − turbulence_factor) where turbulence = f(terrain_roughness, wind_speed, altitude_AGL) |
1.13 Detection Environment Integration Gaps¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Visibility → visual detection | WIRED | Beer-Lambert atmospheric extinction (3.0/visibility) | — |
| Illumination → visual detection | WIRED | Lux multiplier on visual signature | — |
| Thermal contrast → thermal detection | WIRED (indirect) | Uses illumination-based modifier, not physics ΔT | Should use: background_temperature from TimeOfDayEngine vs target thermal signature. ΔT drives thermal detection range. At thermal crossover (dawn/dusk), ΔT → 0 → thermal detection collapses |
| Obscurant opacity → detection | NOT WIRED | ObscurantsEngine has opacity_at(pos) but detection never calls it |
Should query: visual_opacity and thermal_opacity at target position. Smoke blocks visual (0.9), partially blocks thermal (0.1 standard, 0.8 multispectral), doesn't block radar (0.0) |
| Vegetation density → concealment | NOT WIRED | SeasonsEngine computes, detection ignores | Summer foliage provides concealment (+30% visual signature reduction in forest). Winter bare trees provide much less (+5%). Model: concealment_modifier = base_concealment × vegetation_density |
| Rain → radar detection | NOT WIRED | _compute_rain_detection_factor() exists in battle.py but never called |
Rain creates radar clutter that masks targets. Already implemented with ITU-R P.838 model. Just needs call site in detection flow |
| Convergence zones → sonar | NOT WIRED | convergence_zone_ranges() computed |
Should create detection "rings" at 55km intervals. Target between CZ ranges is in acoustic shadow. Within CZ range, detection probability spikes. Fundamental to deep-water ASW |
| Thermocline → sonar | NOT WIRED | Thermocline depth computed | Submarine below thermocline is very hard to detect from surface sonar (+20 dB loss). Surface ship sonar can't reliably detect deep targets. Model: if target_depth > thermocline_depth, add layer_loss to transmission |
| Sea state → radar clutter | NOT IMPLEMENTED | No sea surface clutter model | Radar returns from waves mask surface targets (sea clutter). Higher sea state = worse clutter. Model: clutter_noise ∝ σ₀(beaufort) × resolution_cell_area. Affects both air defense (low-flying targets) and naval radar |
| NVG → night detection | COMPUTED/UNCONSUMED | nvg_effectiveness() computed |
NVG-equipped units should have enhanced night detection (visual modifier recovery from 0.2 to ~0.6). Currently only affects movement speed (0.7x recovery), not detection range |
1.14 Logistics & Transport Environment Interaction¶
| Parameter | Status | Current State | What Should Happen |
|---|---|---|---|
| Mud speed fraction | DEFINED/UNCALLED | transport.py has mud_speed_fraction=0.5 |
Never applied in battle-loop movement. Should slow logistics convoys by 50% in muddy conditions. Currently only MovementEngine queries ground_trafficability, not transport |
| Snow speed fraction | DEFINED/UNCALLED | transport.py has snow_speed_fraction=0.7 |
Same as mud — defined but never applied |
| Airlift weather gate | WIRED | Ceiling < 500m cancels airlift | — |
| Road condition degradation | NOT IMPLEMENTED | Roads have fixed speed bonus | Heavy rain/freeze-thaw should degrade unpaved roads. Paved roads unaffected by weather but blocked by snow/ice until cleared. Model: road_speed = base_speed × weather_condition_factor |
| Supply route terrain effects | NOT IMPLEMENTED | Supply routing uses networkx shortest path with fixed costs | Route costs should reflect current terrain conditions (flooded bridge, muddy road, snow-blocked pass). Dynamic edge costs from SeasonsEngine |
| Aircraft wind limits for cargo | NOT IMPLEMENTED | No crosswind gate for fixed-wing | Crosswind > 15 knots limits transport aircraft operations. Model: abort if crosswind > aircraft_crosswind_limit |
1.15 Scenario Environment Configuration Gaps¶
| Parameter | Status | What Should Be Configurable |
|---|---|---|
| Starting weather state | PARTIALLY WIRED | weather_conditions.precipitation maps to state. Should also allow explicit weather_state: FOG |
| Starting time of day | WIRED | start_time in scenario YAML sets datetime |
| Starting season | NOT CONFIGURABLE | Season derived from date, but SeasonsEngine ground state starts fresh (no prior accumulation) |
| Latitude for astronomy | PARTIALLY WIRED | Derived from scenario map center |
| Pre-placed smoke/fog | NOT IMPLEMENTED | No scenario YAML field |
| Pre-placed minefields | NOT IMPLEMENTED | No scenario YAML field |
| Sea state initialization | NOT WIRED | sea_state field in some scenario YAMLs but not passed to SeaStateEngine |
| Terrain condition overrides | NOT IMPLEMENTED | All terrain starts at default |
Theme 2: Core Combat Integration (Priority: Highest — P0 Bugs)¶
These are not missing features — they are bugs. Existing code computes results that are silently discarded, engagement types are declared but never routed, and fundamental logistics gates are absent.
2.1 Air Combat Routing — 3 Engines With Wrong Physics¶
Problem: Air-to-air, air-to-ground, and SAM engagements all route through the generic DIRECT_FIRE path, which applies ground combat physics (range-dependent Pk with terrain modifiers). Three purpose-built engines (AirCombatEngine, AirGroundEngine, AirDefenseEngine) with correct domain physics exist but are unreachable because _infer_engagement_type() never assigns AIR_TO_AIR, AIR_TO_GROUND, or SAM.
Fix: Update _infer_engagement_type() to detect attacker/target domain combinations and assign the correct EngagementType. Route each type to its respective engine. This is routing logic only — the engines are fully implemented.
Impact: Every air engagement in every scenario changes from ground-combat Pk to proper air combat Pk. Expect significant recalibration.
2.2 Damage Detail — Computed Then Discarded¶
Problem: DamageEngine.resolve_damage() returns a DamageResult with 6 fields. Only damage_fraction is read — everything else (casualties, systems_damaged, fire_started, ammo_cookoff, penetrated) is discarded. Units are binary: 100% combat power until destroyed/disabled.
Fix: Extract and apply each field. Casualties reduce personnel count. Systems_damaged degrade specific equipment. Fire_started triggers fire zone creation. Ammo_cookoff applies secondary explosion to nearby units. Penetrated degrades armor for subsequent hits.
Impact: Graduated degradation replaces binary threshold. A tank with damaged optics has reduced detection. A unit with 30% casualties has reduced firepower. Fires create persistent battlefield obstacles.
2.3 Posture Protection — DUG_IN Does Nothing¶
Problem: DUG_IN units take the same casualties as units standing in the open. The only effect is speed=0 (they don't move). Terrain cover provides some protection, but posture itself provides zero damage reduction.
Fix: Apply posture damage reduction multiplier: DEFENSIVE ~20%, DUG_IN ~50%, FORTIFIED ~70%. These map to hasty fighting position, prepared position, and hardened position respectively. Values configurable via CalibrationSchema.
Impact: Defensive operations become viable. Currently the only winning strategy is attack (defender has no defensive advantage beyond not moving).
2.4 Logistics Gates — Units Fight Without Resources¶
Problem: Units with 0 fuel still move. Units with 0 ammo still fire. Movement doesn't consume fuel. Logistics is tracked and reported but never constrains combat.
Fix: Check ammo > 0 before weapon.fire(). Check fuel > 0 before movement execution. Consume fuel proportional to distance × consumption_rate during movement.
Impact: Logistics becomes consequential. Cutting supply lines degrades enemy combat power. Long advances require fuel resupply. Ammo conservation becomes a real concern.
(All Phase 58 deliverables)
Theme 3: C2 Friction (Priority: High)¶
Three C2 engines (~1,400 lines total) are fully implemented but disconnected. Wiring them creates realistic command friction — orders take time, get misunderstood, and planning delays create windows of vulnerability.
3.1 Order Propagation — Delay & Misinterpretation¶
Current state: OrderPropagationEngine (315 lines) computes:
- Propagation delay: base_time(echelon) × type_mult × priority_mult × staff_mult + lognormal_noise
- Platoon: ~5 min base, Division: ~2 hr base
- FRAGO: 0.33x, WARNO: 0.1x, OPORD: 1.0x
- FLASH priority: 0.1x, ROUTINE: 1.0x
- Misinterpretation probability: base × (1 − staff_eff) × (1 − comms_quality)
- Comms availability check (can order physically reach recipient?)
Wiring needed: - When AI commander issues orders (OODA DECIDE phase), route through OrderPropagationEngine instead of instant execution. - Delayed orders queue with scheduled delivery time. - On delivery, roll for misinterpretation — misunderstood orders execute with modified parameters (wrong objective, wrong timing). - If comms are down (comms engine reports no path), order fails entirely.
Impact: Creates Clausewitzian friction. Surprise attacks succeed because defenders can't reorganize quickly. Comms degradation (EW jamming, courier intercept) becomes tactically meaningful.
Design consideration: Must be opt-in per scenario (enable_order_propagation: true) to avoid breaking existing scenarios that assume instant C2.
3.2 Planning Process — MDMP Delays¶
Current state: PlanningProcessEngine (564 lines) implements: - Planning phases: RECEIVING_MISSION → ANALYZING → DEVELOPING_COA → COMPARING → APPROVING → ISSUING_ORDERS - Method selection: INTUITIVE (fast, low echelon) vs MDMP (slow, thorough, high echelon) - 1/3-2/3 rule: Commander uses 1/3 of available time for planning, subordinates get 2/3 - Phase durations scaled by method speed multipliers
Wiring needed: - When OODA cycle reaches DECIDE, check if a planning process is already underway. - If not, initiate planning with duration based on echelon and method. - Commander cannot issue new orders until planning completes. - Higher-quality planning (MDMP) produces better COA evaluation scores.
Impact: Creates realistic planning tempo. Low-echelon units (company) can react in minutes. Division-level changes take hours. OODA speed becomes a real differentiator between doctrinal schools (Maneuver warfare has faster planning loops).
Design consideration: Planning delays interact with order propagation delays — total C2 latency = planning time + propagation time. Must not create unplayable stalls for the AI.
3.3 Air Tasking Order Management¶
Current state: ATOPlanningEngine (459 lines) implements: - Aircraft registration with availability tracking (mission-capable, sortie limits, turnaround times) - ATO generation from CAS/strike requests with priority ordering - Sortie counting and reserve management - Publishes ATOGeneratedEvent
Wiring needed: - Register all aerial units with ATOPlanningEngine at scenario start. - CAS requests from ground commanders route through ATO queue. - Air missions allocated from available aircraft pool (not unlimited). - Turnaround time enforced between sorties. - ATO published periodically (default every 12 hours in modern era, shorter for close air support).
Impact: Air support becomes a finite resource. Multiple requests compete for limited aircraft. Attrition of aircraft reduces future sortie capacity. Creates realistic air campaign pacing.
Theme 4: Stratagem & Unconventional Completion (Priority: High)¶
4.1 Stratagem Activation¶
Current state: StratagemEngine (416 lines) evaluates eligibility for 9 stratagem types but never activates them. evaluate_concentration_opportunity() and evaluate_deception_opportunity() are called in battle.py but activate_stratagem() is not.
Wiring needed: - When eligibility evaluation passes, create a stratagem plan and activate it. - Each stratagem type produces effects: - CONCENTRATION: +8% force effectiveness at Schwerpunkt - DECEPTION: Enemy AI receives false force disposition estimates - FEINT: Enemy AI commits reserves to feint axis - ECONOMY_OF_FORCE: Reduced force can hold secondary sector - SURPRISE: First-engagement bonus (defender has no prepared positions) - Effects modulate combat modifiers for the duration of the stratagem.
Impact: AI commanders can employ stratagems as force multipliers. Concentration at the decisive point becomes a real mechanic (Austerlitz, 73 Easting envelopment).
4.2 Unconventional Warfare Engine¶
Current state: UnconventionalWarfareEngine (397 lines) implements IED, guerrilla tactics, and human shields. Never called.
Wiring needed: - Route INSURGENT/MILITIA unit engagements through unconventional engine. - IED encounters triggered by movement through insurgent-controlled areas. - Guerrilla hit-and-run: attack then disengage before response. - Human shield mechanics: reduce casualty Pk when civilian population present.
Impact: Hybrid Gray Zone scenario becomes meaningful. Insurgency dynamics (Phase 24e) can produce IED events. Afghan/Iraq-style asymmetric warfare.
4.3 Mine Warfare Completion¶
Current state: MineWarfareEngine (541 lines) resolves mine encounters but cannot lay mines. Ships can hit pre-placed mines but nobody places them.
Wiring needed:
- lay_mines() callable by naval units with mine-laying capability.
- Minefield persistence on the map as hazard zones.
- Mine sweeping operations by minesweeper units.
- Scenario YAML support for pre-placed minefields.
Impact: Naval blockade scenarios gain teeth. Suez Canal, Persian Gulf, WW2 Channel/Baltic mine warfare.
Theme 5: Space & EW Sub-Engine Activation (Priority: Medium)¶
Five space engines (~1,400 lines) and two EW engines (~760 lines) are instantiated but never called. These are complete implementations with sophisticated physics models.
5.1 Space ISR — Satellite Reconnaissance¶
SpaceISREngine (206 lines): Checks satellite overpasses, resolution-dependent target detection (vehicle <0.5m, company <5m, battalion <15m), cloud cover blocks optical but not SAR.
Wiring: Call check_overpass() each tick. On overpass, generate ISR reports that feed into FogOfWarManager (reveal enemy formations to the side with satellite access). Cloud cover from WeatherEngine gates optical sensors.
Impact: Strategic-level intelligence. Side with satellite advantage sees enemy disposition updates every ~90 minutes. GPS-denied environments (EW jamming) degrade positioning.
5.2 Early Warning — BMD Cueing¶
EarlyWarningEngine (143 lines): Detects ballistic missile launches via GEO/HEO early warning satellites. 30-90s detection delay, computes usable warning time.
Wiring: When a ballistic missile is fired (engagement type BALLISTIC_MISSILE), check if early warning satellites detect the launch. If detected, publish warning event that can trigger air defense interceptors.
Impact: Nuclear/ballistic missile scenarios gain defensive layer. Korean Peninsula (THAAD defense) and space scenarios become more realistic.
5.3 ASAT — Anti-Satellite Warfare¶
ASATEngine (353 lines): 4 ASAT weapon types (kinetic kill, co-orbital, ground laser dazzle, ground laser destruct). Debris cascade (Kessler syndrome). Kinetic Pk model.
Wiring: Route ASAT engagements through ASATEngine. Destroyed satellites removed from ConstellationManager (affects GPS, ISR, SATCOM, early warning). Debris cascade can degrade entire orbital bands.
Impact: Space warfare becomes consequential. Destroying enemy GPS constellation degrades their precision weapons. Kessler cascade can deny LEO to both sides.
5.4 SIGINT — Signals Intelligence¶
SIGINTEngine (488 lines): ELINT (radar parameter capture), COMINT (comms intercept), traffic analysis. AOA/TDOA geolocation. Intercept probability from SNR.
Wiring: Call attempt_intercept() when enemy units emit (radar, comms). Successful intercepts produce geolocation reports feeding FogOfWarManager. Traffic analysis reveals activity levels (enemy massing forces detectable via comms surge).
Impact: EW-capable forces can passively detect enemy radars and comms. SEAD targeting improves (find the SAM radar, then shoot HARM at it). Intelligence fusion between SIGINT + Space ISR + ground sensors.
5.5 ECCM — Electronic Protection¶
ECCMEngine (270 lines): 4 ECCM techniques (frequency hop, spread spectrum, sidelobe blanking, adaptive nulling) with J/S reduction calculations.
Wiring: When EW jamming is computed, query ECCMEngine for target's ECCM suite. Subtract ECCM reduction from jammer J/S ratio. Units with good ECCM resist jamming better.
Impact: Creates asymmetry between advanced forces (NATO ECCM vs Soviet-era radar) and legacy systems. EW scenarios become more nuanced (not just "jammer wins").
Theme 6: Cross-Module Feedback Loops (Priority: High)¶
These are the systemic integration gaps where one module's output should drive another module's behavior but currently doesn't. The build-then-defer pattern created modules that publish state changes as events but no module subscribes to act on them.
6.1 Detection → AI Assessment¶
Problem: AI assessment receives enemy_unit_count (raw ground truth) instead of querying FogOfWarManager for detected contacts with confidence levels. A side with zero sensors sees enemies perfectly.
Fix: When FOW is enabled, AI assessment reads fow_manager.get_contacts(side) — gets detected count, estimated strength, confidence. Assessment quality degrades with poor sensor coverage (fewer contacts, lower confidence → worse decisions). When FOW is disabled, behavior unchanged (backward compatible).
6.2 Medical → Unit Strength¶
Problem: MedicalEngine publishes CasualtyTreatedEvent and ReturnToDutyEvent but nobody subscribes. Treated casualties never return to duty — units stay permanently depleted.
Fix: Subscribe to RTD events. On receipt, increment unit personnel count (capped at original strength). Medical capacity (M/M/c queue) gates throughput — more medical assets = faster RTD.
6.3 Maintenance → Readiness¶
Problem: MaintenanceEngine publishes EquipmentBreakdownEvent and MaintenanceCompletedEvent. Nobody subscribes. Broken equipment continues functioning.
Fix: Subscribe to breakdown events. Reduce unit weapon/sensor count based on equipment lost. Subscribe to maintenance completed events. Restore capability. Units with >30% equipment broken marked DEGRADED (reduced Pk, reduced movement).
6.4 Checkpoint State Registration¶
Problem: CheckpointManager.register() is never called in production. Checkpoints save only clock + RNG state. Restoring a checkpoint produces correct time with wrong morale, wrong detection tracks, wrong supply levels, wrong equipment condition.
Fix: Register all stateful modules: morale state, detection tracks, supply levels, equipment condition, weather state, OODA phase, escalation level. Verify round-trip: save → restore → continue produces identical outcomes.
6.5 MISSILE Engagement Routing¶
Problem: MISSILE EngagementType is declared but never assigned by _infer_engagement_type(). MissileEngine computes flight phases and terminal guidance but is never invoked. Missiles route as DIRECT_FIRE (instant hit, wrong physics).
Fix: Assign MISSILE type for guided missile engagements (ATGM, HARM, cruise missile). Route through MissileEngine. Wire MissileDefenseEngine for intercept attempts. Flight time creates engagement delay (realistic missile time-of-flight).
6.6 Comms → C2 Degradation¶
Problem: Comms degradation (from EW jamming, terrain blockage, range limits) affects assessment confidence score but doesn't constrain what units can do. A unit with zero comms fights identically to one with perfect comms.
Fix: Below c2_min_effectiveness threshold, unit reverts to last received orders. No new targeting assignments, no posture changes, no disengagement. Creates realistic "comms loss = fight in place" behavior. Feeds Phase 64's order propagation failure probability.
(All Phase 63 deliverables)
Theme 7: Code Cleanup & Dead Field Resolution (Priority: Low)¶
7.1 ConditionsEngine Disposition¶
Current state: 249-line facade that aggregates all environment sub-engines into domain-specific query methods (land(), air(), maritime(), acoustic(), electromagnetic()). Never instantiated.
Recommendation: Instantiate as optional convenience facade. Don't refactor existing code. New Block 7 wiring can use it where aggregated queries are cleaner.
7.2 Dead YAML Field Resolution¶
| Field | Action | Rationale |
|---|---|---|
weight_kg |
Keep, document as "data-only" | Useful for scenario documentation; future weight-of-fire calculations |
propulsion |
Wire to drag model | Rocket/turbojet/ramjet propulsion types should affect missile kinematics and altitude performance |
unit_cost_factor |
Keep, document as "data-only" | Future logistics cost modeling |
data_link_range |
Wire to C2 | UAV data link range should gate C2 effectiveness beyond range |
7.3 SimulationContext Stubs¶
7.4 P4 Dead Code Removal¶
Remove computed values with no meaningful consumer to clean up false audit findings:
- TimeOfDayEngine.shadow_azimuth — no consumer, not useful at simulation scale
- TimeOfDayEngine solar/lunar contribution decomposition — diagnostic data, only total lux matters
- UnderwaterAcoustics.deep_channel_depth — SOFAR channel is extremely niche (fixed sonobuoy networks only)
(All Phase 66 deliverables)
Remove TODO comments for engines that are instantiated (SeasonsEngine, ObscurantsEngine, ConditionsEngine).
Comprehensive Inventory: Computed But Unconsumed Parameters¶
This is the definitive list of values that environment engines calculate every tick but that no downstream system reads. Each of these represents wasted computation and missing fidelity.
| Engine | Parameter | Consumers That Should Use It |
|---|---|---|
| SeasonsEngine | mud_depth |
MovementEngine (wheeled penalty), logistics transport |
| SeasonsEngine | snow_depth |
MovementEngine (all-unit penalty), infrastructure (road degradation) |
| SeasonsEngine | vegetation_density |
DetectionEngine (seasonal concealment), fire spread probability |
| SeasonsEngine | vegetation_moisture |
Fire zone creation (wet = no ignition), CBRN agent persistence |
| SeasonsEngine | sea_ice_thickness |
MovementEngine (ice crossing), naval movement (ice navigation) |
| SeasonsEngine | wildfire_risk |
Fire zone system (spontaneous ignition probability) |
| SeasonsEngine | daylight_hours |
Operational planning, fatigue rate |
| SeaStateEngine | wave_period |
Ship resonance roll, helicopter deck landing |
| SeaStateEngine | tidal_current_speed |
Ship movement, mine drift, submarine station-keeping |
| SeaStateEngine | tidal_current_direction |
Same as speed |
| SeaStateEngine | beaufort_scale |
Small craft operations gate, deck operations gate, sea clutter |
| UnderwaterAcoustics | surface_duct_depth |
Sonar detection (in-duct enhancement, below-duct shadow) |
| UnderwaterAcoustics | thermocline_depth |
Sonar detection (+20 dB loss for targets below layer) |
| UnderwaterAcoustics | deep_channel_depth |
SOFAR channel long-range detection |
| UnderwaterAcoustics | convergence_zone_ranges |
Sonar detection rings at 55km intervals |
| EMPropagation | radar_horizon() |
Air defense detection range gate (Earth curvature) |
| EMPropagation | free_space_path_loss() |
Comms range, radar range, EW intercept range |
| EMPropagation | atmospheric_attenuation() |
Radar/comms degradation in rain/humidity |
| EMPropagation | ducting_possible + duct_height |
Radar/comms range extension in warm humid maritime |
| EMPropagation | hf_propagation_quality() |
HF radio reliability (day/night D-layer/F-layer) |
| WeatherEngine | wind.gust |
Helicopter ops, bridge-laying, parachute drops, amphibious small craft |
| WeatherEngine | pressure |
Air density (ideal gas), altimeter accuracy |
| TimeOfDay | background_temperature |
Thermal detection SNR (target vs background ΔT) |
| TimeOfDay | crossover_in_hours |
Thermal detection vulnerability window (ΔT → 0) |
| TimeOfDay | shadow_azimuth |
Visual detection angle dependency |
| TimeOfDay | nvg_effectiveness() |
Night detection range for NVG-equipped units |
| Terrain | vegetation_height |
LOS check (ground-level vegetation blocks), helicopter clearance |
| Terrain | combustibility |
Fire zone ignition probability |
| Obstacles | traversal_risk |
Casualty probability during crossing |
| Obstacles | traversal_time_multiplier |
Movement delay through obstacles |
| Hydrography | is_fordable(), ford_points_near() |
River crossing at ford points with time cost |
| Infrastructure | Bridge.capacity_tons |
Heavy vehicle weight gate |
| Infrastructure | Road.speed_factor override |
Per-road speed instead of hardcoded table |
| Equipment | temperature_range + environment_stress() |
Weapon jam rate, electronics failure rate |
| Battle.py | _compute_rain_detection_factor() |
Radar detection probability in rain (ITU-R P.838) — function exists, never called |
| DEW Engine | humidity/precip_rate parameters | Atmospheric transmittance — accepts params, battle loop never passes them |
Total: 36 unconsumed parameters across 11 engines. ~4,500 lines of computation producing values nobody reads.
Proposed Phase Structure¶
Phase 58: Structural Verification & Core Combat Wiring¶
Focus: Create structural verification tests that prevent future regression, then fix all P0 combat integration bugs — air combat routing, damage detail extraction, posture protection, and logistics gates. These are the highest-impact items: existing code that should work but doesn't.
Why first: Structural tests must exist before wiring begins so that every subsequent phase runs against automated audits. P0 combat items affect every engagement and are the most impactful single changes in this block.
Deliverables:
Structural Verification Tests (run continuously from here forward):
- Unconsumed parameter audit: Instrument engine classes, run representative scenario, assert no property written but never read (allowlist for P4 items)
- Dead method audit: AST-parse all source files, verify every public engine method has at least one external caller (beyond tests)
- Event subscription audit: Verify every published event type has at least one functional subscriber (beyond Recorder) or is in OBSERVATION_ONLY allowlist
- Engagement routing completeness: Every EngagementType enum value is assignable by _infer_engagement_type() and has a resolution handler
- Feedback loop verification: Depleted ammo prevents firing, depleted fuel prevents movement, DUG_IN reduces damage, checkpoint round-trips all state
Air Combat Routing (P0):
- Wire AIR_TO_AIR EngagementType → AirCombatEngine (BVR + WVR physics, not ground combat Pk)
- Wire AIR_TO_GROUND EngagementType → AirGroundEngine (CAS/strike Pk model with altitude, dive angle, CEP)
- Wire SAM EngagementType → AirDefenseEngine (missile Pk with engagement envelope, ECM effects)
- Update _infer_engagement_type() to assign these types based on attacker/target domain (AIR vs GROUND/NAVAL)
Damage Detail Extraction (P0):
- Extract DamageResult.casualties → reduce unit personnel count (not just damage_fraction threshold)
- Extract DamageResult.systems_damaged → degrade specific equipment on unit (weapon destroyed, sensor damaged)
- Extract DamageResult.fire_started → trigger fire zone creation at target position (feeds Phase 60 fire system)
- Extract DamageResult.ammo_cookoff → secondary explosion damage to nearby units
- Extract DamageResult.penetrated → armor degradation (reduced protection on subsequent hits)
Posture Protection (P0):
- DEFENSIVE → ~20% damage reduction (hasty fighting position)
- DUG_IN → ~50% damage reduction (prepared position)
- FORTIFIED → ~70% damage reduction (hardened position)
- Protection applied as multiplier on incoming damage_fraction before threshold comparison
- CalibrationSchema fields for posture protection values (per-scenario tuning)
Logistics Gates (P0):
- Ammo depletion → weapon cannot fire (check remaining rounds before weapon.fire())
- Fuel depletion → unit cannot move (check fuel > 0 before movement execution)
- Fuel consumption by movement (distance × consumption_rate → fuel drawdown)
Tests: ~55-65
Phase 59: Atmospheric & Ground Environment Wiring¶
Focus: Wire all computed-but-unconsumed atmospheric and ground parameters. Make seasons, weather, and terrain fully contribute to movement, detection, and combat.
Deliverables: - Seasons → Movement: Mud depth penalty (wheeled vs tracked differentiation), snow depth penalty, ice crossing (weight-dependent), vegetation speed penalty through dense terrain - Seasons → Detection: Vegetation density as seasonal concealment modifier, vegetation height for ground-level LOS - Seasons → Infrastructure: Snow depth degrades road speed bonus, frozen water bodies traversable - Weather → Ballistics: Pressure + humidity → true air density (ideal gas law correction), temperature lapse rate at altitude - Weather → Operations: Wind gust threshold for helicopter/parachute/bridge-laying abort, high wind halt for infantry - Equipment → Reliability: Wire temperature_range stress → weapon jam rate, electronics failure - Terrain → Movement: Wire obstacle traversal_risk and traversal_time, ford crossing with depth/current, bridge capacity gate - Propellant temperature: MV modifier from ambient temperature (MIL-STD-1474)
Tests: ~45-55
Phase 60: Obscurants, Fire, & Visual Environment¶
Focus: Instantiate and wire ObscurantsEngine. Create fire zone system linked to Phase 58's damage detail extraction (fire_started). Wire all visual/thermal environment parameters.
Deliverables:
- ObscurantsEngine instantiation: Create on SimulationContext, call update() each tick
- Smoke from combat: Artillery/mortar impacts spawn smoke clouds, drift with wind, decay (30min half-life)
- Dust from movement: Vehicles on dry terrain spawn dust trails (signature enhancement + LOS degradation)
- Fog auto-generation: Weather FOG state triggers ObscurantsEngine fog deployment
- Smoke/fog → Detection: opacity_at(pos) degrades visual/thermal detection SNR per spectral blocking table
- Smoke/fog → Combat: Obscurant between attacker/target reduces Pk for visual/thermal-guided weapons
- Thermal environment wiring: Background temperature + target temp → true ΔT for thermal detection. Crossover vulnerability windows
- NVG → detection: NVG-equipped units get night detection range recovery (not just movement)
- Fire zones: Wire IncendiaryDamageEngine (P1). fire_started from DamageResult (Phase 58) triggers fire zone creation. Fire produces smoke (feeds ObscurantsEngine). Fire blocks movement. Fire decays when fuel (vegetation) exhausted
- Combustibility wiring: Terrain combustibility gates fire ignition probability
- Scenario YAML: environment_config for pre-placed smoke/fog zones, season/ground state overrides
- Artificial illumination: Flare events that temporarily raise illumination in area
Tests: ~45-55
Phase 61: Maritime, Acoustic, & EM Environment¶
Focus: Wire all maritime, underwater acoustic, and electromagnetic propagation parameters. Wire CarrierOpsEngine (P1) for naval air operations.
Deliverables:
- Sea state → ship movement: Beaufort-dependent speed penalty (small craft more affected)
- Sea state → carrier ops: Launch/recovery gate by Beaufort scale
- CarrierOpsEngine wiring (P1): CAP station management, recovery windows, sortie tracking for carrier-based aircraft
- Sea state → small craft: Amphibious landing craft casualty risk + speed penalty in high seas
- Sea state → radar: Sea clutter model masking surface targets
- Swell direction: Roll factor from wave direction vs ship heading
- Tidal current → movement: Ship speed adjustment (with/against), mine drift, submarine station-keeping
- Wave period → ship resonance: Roll amplitude when wave period matches hull natural frequency
- Acoustic wiring: Surface duct detection enhancement/shadow, thermocline layer loss (+20 dB), convergence zone detection rings at 55km intervals
- Radar horizon: Gate air defense detection by 4/3 Earth curvature model
- EM ducting: Extend radar range in warm/humid maritime conditions
- Atmospheric attenuation: Frequency-dependent rain loss for radar and comms
- HF propagation: Wire hf_quality → comms reliability (day/night D-layer/F-layer)
- Radio horizon: Altitude-dependent comms range using same 4/3 Earth model
- DEW wiring: Pass humidity/precip_rate/dust to DEW engine (call site fix), sea spray attenuation, dust distinction from rain
- Rain detection: Wire existing _compute_rain_detection_factor() call site in battle loop
Tests: ~50-60
Phase 62: Human Factors, CBRN, & Air Combat Environment¶
Focus: Environmental effects on personnel, CBRN-environment interaction, and air domain environmental coupling.
Deliverables: - Heat stress: WBGT model for heat casualties (temperature × humidity × MOPP level × exertion) - Cold injury: Wind chill formula + exposure time → cold casualty rate - MOPP degradation: Beyond speed — reduce FOV (detection), dexterity (reload speed), voice clarity (comms quality) - Altitude sickness: Performance degradation above 2500m - Environmental fatigue: Temperature/altitude stress accelerates fatigue accumulation - CBRN rain washout: Precipitation scavenges airborne agents (exponential washout) - CBRN temperature persistence: Arrhenius agent decay rate (nerve agent half-life 2hr at 40°C vs 24hr at 0°C) - CBRN inversion trapping: Temperature inversion detection → 5-10x concentration multiplier - CBRN UV degradation: Solar radiation breaks down agents in daylight - Air combat: cloud ceiling gate: CAS/dive bombing requires visual contact below ceiling - Air combat: icing penalties: Wing ice, engine ice, radar dome ice degradation - Air combat: density altitude: Engine thrust/lift penalties at high altitude + hot temperature - Air combat: wind → BVR range: Headwind/tailwind modifies missile effective range - Air combat: altitude energy advantage: Higher aircraft gets energy_state modifier in engagement
Tests: ~40-50
Phase 63: Cross-Module Feedback Loops¶
Focus: Wire all P1 cross-module integration gaps — the feedback loops where one system's output should drive another system's behavior but currently doesn't. This phase closes the systemic build-then-defer-wiring pattern.
Deliverables:
Detection → AI (P1):
- AI assessment reads FOW contacts (detected count, estimated strength, confidence) instead of ground truth enemy count
- When enable_fog_of_war is True, AI assessment quality degrades with sensor coverage gaps
- When FOW is disabled, behavior is unchanged (backward compatible)
Medical → Strength (P1):
- ReturnToDutyEvent consumption: treated casualties restore to unit personnel count
- CasualtyTreatedEvent consumption: track treatment pipeline (triage → treatment → RTD)
- Medical capacity limits (M/M/c queue) gate RTD throughput
Maintenance → Readiness (P1):
- EquipmentBreakdownEvent consumption: broken equipment reduces unit combat power (weapon count, sensor availability)
- MaintenanceCompletedEvent consumption: repaired equipment restores capability
- Maintenance state feeds readiness: units with >30% equipment broken are DEGRADED (reduced Pk, reduced movement)
Checkpoint State Registration (P1): - Register all stateful modules with CheckpointManager: morale state, detection tracks, supply levels, equipment condition, weather state, OODA phase, escalation level - Checkpoint round-trip test: save → restore → continue produces identical outcomes to uninterrupted run - Prioritize modules with expensive state (detection tracks, PRNG streams, morale matrices)
MISSILE Engagement Routing (P1):
- Wire MISSILE EngagementType → MissileEngine (flight phase + terminal guidance)
- Wire MissileDefenseEngine → intercept attempts (launch-on-detect or launch-on-warning)
- Missile flight time creates engagement delay (not instant hit like DIRECT_FIRE)
Comms → C2 (P1):
- Comms loss (from EW jamming, terrain LOS, range) degrades C2 effectiveness below c2_min_effectiveness
- Units with zero comms revert to last received orders (no new targeting, no posture changes)
- Comms degradation feeds order propagation failure probability (Phase 64)
Tests: ~40-50
Phase 64: C2 Friction & Command Delay¶
Focus: Wire the three dormant C2 engines to create realistic command friction. Builds on Phase 63's comms → C2 degradation wiring.
Deliverables:
- OrderPropagationEngine → OODA cycle (order delay + misinterpretation + comms check)
- PlanningProcessEngine → OODA DECIDE phase (planning duration before order issue)
- ATOPlanningEngine → air operations (sortie management, CAS request queue)
- StratagemEngine full activation (9 stratagem types with combat effects)
- C2 friction opt-in flag (enable_c2_friction: true in scenario YAML)
- Environmental coupling: comms weather degradation → order propagation failure
- Environmental coupling: HF day/night quality → comms reliability → C2 latency
Tests: ~35-45
Phase 65: Space & EW Sub-Engine Activation¶
Focus: Wire the five dormant space engines and two dormant EW engines.
Deliverables: - SpaceISREngine → FogOfWarManager (satellite ISR passes reveal formations) - EarlyWarningEngine → air defense (BMD cueing from early warning satellites) - ASATEngine → space warfare (satellite destruction, debris cascade, constellation degradation) - SIGINTEngine → FogOfWarManager (emitter geolocation, traffic analysis) - ECCMEngine → EW jamming loop (ECCM J/S reduction) - Space sub-engine delegation verified end-to-end
Tests: ~35-45
Phase 66: Unconventional, Naval, & Cleanup¶
Focus: Wire remaining dormant engines and clean up dead code.
Deliverables:
- UnconventionalWarfareEngine → battle routing (IED, guerrilla, human shields)
- MineWarfareEngine completion (mine laying, minefield persistence, sweeping, scenario YAML minefields)
- SiegeEngine → campaign loop (P2 — ancient/medieval siege mechanics)
- AmphibiousAssaultEngine → naval ops (P2 — beach assault state machine)
- ConditionsEngine instantiation (optional facade)
- Dead YAML field resolution (wire propulsion → drag model, data_link_range → C2 range gate)
- P4 dead code removal (shadow_azimuth computation, solar/lunar decomposition, deep_channel_depth)
- SimulationContext stub cleanup
Tests: ~30-35
Phase 67: Integration Validation & Recalibration¶
Focus: Validate all scenarios still produce correct outcomes with all new systems active. Run structural verification tests to confirm zero remaining gaps. This is the final hardening pass.
Deliverables: - Full scenario evaluation with all new systems active - Recalibration of affected scenarios (expect significant recalibration — air combat routing, posture protection, logistics gates, and environmental effects all change outcomes) - MC validation at 80% threshold with N=10 seeds - Structural verification test results: - Zero unconsumed parameters (beyond P4 allowlist) - Zero uncalled public engine methods (beyond test-only methods) - All event types have functional subscribers (or are in observation-only allowlist) - All EngagementType values routable and handled - All feedback loops functional (ammo→fire, fuel→move, posture→damage, checkpoint→state) - CalibrationSchema exercised fields audit (17 never-set fields either exercised in scenarios or removed) - Regression test suite for all new environmental and combat effects - Cross-doc audit and documentation sync - Block 7 postmortem
Tests: ~35-45
Test Count Estimate¶
| Phase | Focus | Tests | Cumulative (Python) |
|---|---|---|---|
| 58 | Structural Verification & Core Combat Wiring | ~60 | ~8,443 |
| 59 | Atmospheric & Ground Environment | ~50 | ~8,493 |
| 60 | Obscurants, Fire, & Visual Environment | ~50 | ~8,543 |
| 61 | Maritime, Acoustic, & EM Environment | ~55 | ~8,598 |
| 62 | Human Factors, CBRN, & Air Combat | ~45 | ~8,643 |
| 63 | Cross-Module Feedback Loops | ~45 | ~8,688 |
| 64 | C2 Friction & Command Delay | ~40 | ~8,728 |
| 65 | Space & EW Sub-Engine Activation | ~40 | ~8,768 |
| 66 | Unconventional, Naval, & Cleanup | ~30 | ~8,798 |
| 67 | Integration Validation & Recalibration | ~40 | ~8,838 |
| Block 7 total | ~455 | ~8,838 |
Design Decisions Needed¶
1. Opt-in vs Default for New Systems¶
Question: Should C2 friction, obscurants, space effects, etc. be on by default or opt-in per scenario?
Recommendation:
- Default-on: All environmental effects (seasons, obscurants, sea state, EM propagation, atmospheric corrections). These are passive modifiers — when conditions are benign (clear weather, no smoke, dry ground), they produce unity multipliers and don't change outcomes. When conditions are adverse, they add realism.
- Opt-in: C2 friction (enable_c2_friction: true). Dramatically changes battle pacing; existing scenarios assume instant C2.
- Opt-in: Human factors casualties (heat/cold stress). Can produce unexpected casualties in historical scenarios not calibrated for them.
- Gated by config presence: Space/EW sub-engines (only active when space_config or ew_config present).
2. ConditionsEngine: Wire or Remove?¶
Recommendation: Instantiate as optional convenience facade. Don't refactor existing code. Use for new Block 7 wiring where aggregated queries are cleaner.
3. Fire Spread Model Complexity¶
Options: - Simple: Fire zones persist, don't spread. Decays when fuel exhausted. - Medium: Fire spreads to adjacent vegetated cells at rate proportional to wind and vegetation density. Cellular automaton with wind bias. - Complex: Full wildfire model with firebreaks, slope effects, spotting (ember transport).
Recommendation: Start with medium — the cellular automaton with wind bias captures the key dynamic (fire moves downwind through dry vegetation) without the complexity of spotting/embers. The SeasonsEngine already computes vegetation_density and vegetation_moisture per cell; the WeatherEngine provides wind. The pieces are there.
4. Performance Budget¶
New environmental queries (obscurant opacity, seasonal trafficability, EM propagation, atmospheric corrections) add per-engagement computation. Current tick time is ~50-100ms.
Recommendation: Budget 30% overhead (15-30ms per tick). Profile after each phase. Key mitigations: - Environmental queries should be O(1) lookups with spatial caching (STRtree for obscurants, grid cache for seasons) - Radar horizon is constant per antenna height — cache per unit - EM ducting is constant per weather state — cache per tick - Thermal crossover timing changes slowly — cache per hour - Ice/mud/snow depth changes slowly — cache per tick
5. Backward Compatibility¶
All new systems must be backward-compatible. Existing scenarios that don't specify environment_config, enable_c2_friction, space_config, etc. should behave identically to Block 6.
Mechanism: Default values on all new config fields that produce unity modifiers (1.0 multiplier, 0.0 additive). New engines gated by config presence. ObscurantsEngine produces zero opacity when no smoke/dust/fog deployed. SeasonsEngine trafficability defaults to 1.0 when not explicitly set. Atmospheric corrections should produce negligible changes at sea level standard conditions.
6. Thermal Detection Model¶
Question: Should thermal detection switch from illumination-based modifier to physics-based ΔT model?
Recommendation: Yes. The ΔT model (target_temperature − background_temperature) is physically correct and uses values already computed by TimeOfDayEngine. The illumination-based modifier is a proxy that doesn't capture thermal crossover (dawn/dusk vulnerability windows where ΔT → 0 and thermal detection collapses). This is a real-world planning factor that should be represented.
7. Casualty Models for Environmental Effects¶
Question: Should heat/cold casualties use simple threshold models or continuous exposure models?
Recommendation: Continuous exposure. Heat casualties accumulate with WBGT × time × exertion_level. Cold casualties accumulate with wind_chill × exposure_time. Both produce casualties at a rate, not a threshold — this matches military medical data (heat/cold casualties are a function of cumulative exposure, not instant onset).
Risk Assessment¶
| Risk | Severity | Mitigation |
|---|---|---|
| Air combat routing changes every air engagement | High | Phase 58 (earliest); recalibrate immediately; expect all air-heavy scenarios affected |
| Posture protection makes defenders much harder to destroy | High | Calibrate protection values conservatively; DUG_IN ~50% not ~90% |
| Logistics gates stop combat in scenarios without supply units | High | Gate only when logistics system is active (supply units present); degrade gracefully |
| Damage detail extraction produces unexpected cascading losses | High | Secondary effects (fire, cookoff) opt-in via CalibrationSchema; disabled by default |
| Environmental corrections change outcomes in existing scenarios | High | Phase 67 dedicated to recalibration; run full eval after each environmental phase |
| Seasonal trafficability breaks movement in all scenarios | High | Default trafficability=1.0 for benign conditions; only penalizes mud/snow/saturated |
| Obscurant smoke from barrages degrades all engagement Pk | Medium | Smoke only at impact area, not global; 30min half-life; spectral: radar unaffected |
| Thermal ΔT model changes detection balance | Medium | Calibrate ΔT ranges to match existing detection behavior at nominal conditions |
| C2 friction makes AI unable to function | High | Opt-in flag; careful tuning of delay durations; INTUITIVE method for low echelon |
| Heat/cold casualty model produces unexpected losses | Medium | Opt-in flag for human factors; threshold calibrated to historical data |
| Radar horizon gate makes many ground radars useless | Medium | Only applies to detecting targets below geometric horizon; most engagements within horizon |
| Fire spread model creates runaway terrain destruction | Medium | Spread rate capped; fire decays when fuel exhausted; limited by vegetation moisture |
| EM ducting extends detection unrealistically | Low | Only activates in specific weather; factor capped at 3× range extension |
| Space sub-engines add per-tick overhead | Low | Gate by space_config presence; skip when null |
| Scenario recalibration cascade across 37 scenarios | High | Recalibrate one at a time; accept new baselines; environmental realism justifies changes |
| Performance degradation from 36 new per-engagement queries | Medium | O(1) lookups with caching; profile after each phase; budget 30% overhead |
| ECCM wiring changes EW balance in gulf_war_ew_1991 | Medium | Verify scenario still produces correct winner; recalibrate if needed |
Research Sources¶
Atmospheric Physics¶
- ISA (International Standard Atmosphere): Lapse rate, tropopause, pressure-altitude relationship
- MIL-STD-1474: Propellant temperature effects on muzzle velocity
- ITU-R P.838: Specific rain attenuation model (dB/km vs rain rate and frequency)
- ITU-R P.676: Atmospheric gaseous attenuation (O₂ at 60 GHz, H₂O at 22 GHz)
- Pasquill-Gifford: Atmospheric stability classification and dispersion parameters
Thermal & Optical¶
- FLIR Systems: Thermal contrast and NETD (Noise Equivalent Temperature Difference) modeling
- MIL-HDBK-141: Electro-optical systems atmospheric propagation
- FM 3-11.50 / ATP 3-11.50: Smoke/obscurant employment doctrine
- Mie scattering theory: Particulate (dust/fog/smoke) attenuation of optical/IR beams
Maritime & Acoustic¶
- Pierson-Moskowitz: Wave spectrum (already implemented)
- Mackenzie equation: Sound velocity profile (already implemented)
- Urick: Underwater acoustic propagation — convergence zones, shadow zones, surface duct
- NATO STANAG 1008: Sea state definitions and operational limits
- Beaufort scale: Operational limits for small craft, carrier operations, helicopter deck landing
Electromagnetic Propagation¶
- ITU-R P.453: Radio refractive index of the atmosphere (ducting conditions)
- ITU-R P.526: Propagation by diffraction (terrain LOS)
- Bean & Dutton: Radio refractivity (4/3 Earth model, super-refraction)
Terrain & Ground¶
- US Army FM 5-33: Terrain Analysis — trafficability by soil type and moisture
- NATO AEP-55: Vehicle mobility in snow, mud, sand
- Ice thickness bearing capacity: Gold formula for ice crossing loads
Human Factors¶
- TB MED 507: Heat stress control and heat casualty management (WBGT model)
- AR 40-501 / FM 4-25.12: Cold injury prevention (wind chill, frostbite times)
- IAM Report 313: Altitude effects on human performance
C2 Friction¶
- Clausewitz: Fog of war and friction as fundamental warfare concepts
- Boyd: OODA loop timing as competitive advantage
- US Army FM 5-0: The Operations Process — MDMP phases and timing
- van Creveld: Command in War — communications delay as historical constant
Space Warfare¶
- Kessler & Cour-Palais (1978): Collision frequency and cascade model
- DoD Space Policy: Orbital regime definitions and satellite vulnerability
- SBIRS/DSP: Early warning satellite detection timelines
CBRN-Environment Interaction¶
- FM 3-11: Chemical agent persistence tables (temperature/humidity dependent)
- Seinfeld & Pandis: Atmospheric Chemistry — washout coefficients for particulate scavenging
- Arrhenius kinetics: Temperature-dependent agent degradation rates
Dependencies on Block 8 (Scenario Expansion)¶
Block 7 creates the infrastructure that Block 8's scenarios will exercise:
| Block 7 Feature | Block 8 Scenario Need |
|---|---|
| Seasonal trafficability (mud/snow/ice) | Eastern Front (rasputitsa), Napoleonic Russia, Korean Winter, Finnish Winter War, Bulge |
| Smoke/obscurants | D-Day smoke screens, WW1 gas+smoke, Napoleonic battery smoke, 73 Easting dust |
| Dust from movement | North Africa (El Alamein), Gulf War desert, 73 Easting, Golan Heights |
| Fire zones + spread | Tokyo firebombing, Dresden, incendiary tactics, scorched earth |
| Sea state → operations | Falklands storms, D-Day Channel weather, Midway, Jutland |
| Radar horizon + EM ducting | Maritime radar scenarios, Persian Gulf ducting, air defense engagement ranges |
| Thermal ΔT + crossover | Dawn/dusk attack scenarios (Golan 1973, Yom Kippur), night operations |
| HF propagation day/night | WW2 naval (night comms skip), Atlantic convoy |
| Rain → radar + DEW | Gulf War (clear weather advantage), Falklands (frequent rain) |
| Heat/cold casualties | Chosin Reservoir, Stalingrad winter, North Africa summer, Vietnam humidity |
| CBRN rain washout + persistence | Halabja (hot, dry = persistent), WW1 gas (rain washout), Cold War scenarios |
| Acoustic layers (thermocline/CZ) | Atlantic ASW, Pacific submarine warfare, Falklands naval |
| C2 friction (order delays) | Any multi-echelon scenario (Kursk, Normandy, Bulge, Waterloo) |
| ATO sortie management | Air-centric scenarios (Bekaa Valley, Gulf War air campaign) |
| Stratagems | Austerlitz (concentration + deception), 73 Easting (envelopment), Cannae |
| Space ISR/ASAT | Modern near-peer (Taiwan, Korea, Suwalki with space denial) |
| SIGINT/ECCM | Cold War EW scenarios, Gulf War SEAD, Bekaa Valley |
| Mine warfare | Dardanelles, Persian Gulf, Baltic WW2, Falklands |
| Unconventional | Afghanistan, Iraq, Vietnam, Peninsular War guerrilla |
| Bridge capacity + fording | Rhine crossing, Arnhem, Remagen, Napoleonic river crossings |
| Ice crossing | Eastern Front (Don, Volga), Finnish Winter War, Chosin Reservoir |
| Density altitude | Afghan mountain warfare, Chosin Reservoir, Andes |
| Fog scenarios | Austerlitz morning fog, Falklands sea fog, English Channel |
| Air combat routing (proper Pk) | Every air-heavy scenario: Bekaa Valley, Gulf War, Korea, Taiwan, Midway, Battle of Britain |
| Posture protection (DUG_IN/FORTIFIED) | Every defensive scenario: Kursk, Stalingrad, Chosin, Verdun, trench warfare, sieges |
| Damage degradation (partial losses) | All scenarios benefit from graduated degradation vs binary destroy/disable |
| Logistics gates (fuel/ammo) | Operational-scale: Bulge (fuel crisis), North Africa (supply lines), Barbarossa (overextension) |
| Detection → FOW-based AI | Near-peer with contested sensor coverage: Taiwan, Suwalki, Korea, naval scenarios |
| Medical RTD + maintenance | Attrition scenarios: Stalingrad, Verdun, WW1 trench, Korean War |
| Checkpoint state | Any scenario requiring save/restore (campaign-length scenarios, multi-day operations) |
| MISSILE routing | Any guided missile scenario: Gulf War HARM, Taiwan anti-ship, Korean BMD |