feat(#56): War as a first-class state — declare/end ops, mutual-defense drag-in, relation sync
CI / build + unit + e2e (pull_request) Successful in 2m32s

Promote the bare 'war' relation to a named War entity in GameState.wars:
- War: { id, sides[], declaredTurn, declaredDate?, aims?, status, front? }
- TurnResult.wars: { declare: WarDeclareOp[], end: WarEndOp[] }
- syncWarRelations: derive 'war' from active wars, fallback to 'hostile' on end
- Mutual-defense drag-in: belligerent allies added to sides (one level)
- Bare 'war' back-compat: never downgraded, never force-created
- Stub: empty wars (e2e unaffected); ~30 new unit tests

v0.33.0
This commit is contained in:
2026-10-15 15:47:06 +00:00
parent 38d3202472
commit b5e2229ee2
15 changed files with 947 additions and 25 deletions
+4
View File
@@ -178,6 +178,10 @@ app.post('/api/games', (req: Request, res) => {
// real region keys — each region starts as a copy of its owner's initial
// stats, so the derived aggregate equals the nation's stats on turn 1.
regionStats: {},
// (v0.33.0, #56) No wars on a fresh game; the LLM declares them over time
// (any preset-level `war` relation stays a bare/implicit one, not an
// entity — see syncWarRelations).
wars: [],
};
// v0.19 (#16 P1): expand each nation's ISO_A3 country list to the region keys
// of all its sub-regions, so ownership (and the choropleth) is at region