feat(#60): nuclear/WMD — capability flag + strikes (region → no-man's-land, nation collapse + war capitulation, MAD retaliation) (v0.37.0) #71

Merged
kamilkrzywda merged 1 commits from feat/60-nuclear-wmd into master 2026-10-15 21:20:30 +02:00
Owner

Fixes #60

Nuclear / WMD (v0.37.0)

A per-nation nuclear capability flag plus a TurnResult.nuclear lever (arm + strikes) with deterministic strikes and MAD retaliation.

Capability

A nation is nuclear-capable when its nuclear flag is true or it owns a rocket marker (a launch site is an arsenal). isNuclearCapable(nation, markers) in shared/protocol.ts.

Lever — TurnResult.nuclear = { arm, strikes } (required, between industry and markers)

  • arm — grant nations the flag (idempotent; a newly-armed nation is capable the same turn).
  • strikes — { from, target }; the striker must be nuclear-capable (self-targets dropped).
    • Region target → released to no-man's land, its regionStats entry deleted, and its sole owner collapses (economy −40 / military −50 / stability −40).
    • Nation target → the target collapses, every active war it fights ends in capitulation, and the war relations it caused downgrade to hostile.
    • MAD — if the struck nation (or the struck region's owner) is itself nuclear-capable, it retaliates at half strength (−20/−25/−20) and the two relations are forced to hostile.

Determinism & safety

No hidden randomness — the LLM picks who strikes and what is targeted; the engine applies the fixed, clamped, mirrored, re-derived stat deltas (NUCLEAR_COLLAPSE / NUCLEAR_RETALIATION). Sole ownership is never broken (a region is released, not re-claimed); every op degrades to a no-op rather than throwing. db.ts needs no change (the flag is an optional Nation field — a pre-v0.37 row loads with it absent). The stub never arms/strikes, so the e2e (CI, LLM_STUB=1) is unaffected.

Tests

29 new unit tests (engine + db): capability, validation (incl. self-target drop), all strike outcomes, MAD, capability gating, dropped cases, isMeaningful, per-nation prompt stamping, and save/load round-trips.

typecheck ✓   lint ✓   470/470 unit tests ✓   build ✓
Fixes #60 ## Nuclear / WMD (v0.37.0) A per-nation `nuclear` capability flag plus a `TurnResult.nuclear` lever (`arm` + `strikes`) with **deterministic** strikes and MAD retaliation. ### Capability A nation is *nuclear-capable* when its `nuclear` flag is `true` **or** it owns a `rocket` marker (a launch site is an arsenal). `isNuclearCapable(nation, markers)` in `shared/protocol.ts`. ### Lever — `TurnResult.nuclear = { arm, strikes }` (required, between `industry` and `markers`) - **`arm`** — grant nations the flag (idempotent; a newly-armed nation is capable the same turn). - **`strikes`** — `{ from, target }`; the striker must be nuclear-capable (self-targets dropped). - **Region target** → released to no-man's land, its `regionStats` entry deleted, and its sole owner collapses (economy −40 / military −50 / stability −40). - **Nation target** → the target collapses, **every active war it fights ends in capitulation**, and the `war` relations it caused downgrade to `hostile`. - **MAD** — if the struck nation (or the struck region's owner) is itself nuclear-capable, it retaliates at half strength (−20/−25/−20) and the two relations are forced to `hostile`. ### Determinism & safety No hidden randomness — the LLM picks who strikes and what is targeted; the engine applies the fixed, clamped, mirrored, re-derived stat deltas (`NUCLEAR_COLLAPSE` / `NUCLEAR_RETALIATION`). Sole ownership is never broken (a region is released, not re-claimed); every op degrades to a no-op rather than throwing. `db.ts` needs no change (the flag is an optional `Nation` field — a pre-v0.37 row loads with it absent). The stub never arms/strikes, so the e2e (CI, `LLM_STUB=1`) is unaffected. ### Tests 29 new unit tests (engine + db): capability, validation (incl. self-target drop), all strike outcomes, MAD, capability gating, dropped cases, `isMeaningful`, per-nation prompt stamping, and save/load round-trips. ``` typecheck ✓ lint ✓ 470/470 unit tests ✓ build ✓ ```
kamilkrzywda added 1 commit 2026-10-15 21:17:54 +02:00
kamilkrzywda scheduled this pull request to auto merge when all checks succeed 2026-10-15 21:18:09 +02:00
kamilkrzywda merged commit b6dcd3f979 into master 2026-10-15 21:20:30 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OpenCode/History#71