From e307db755dfaa32844997c4f1e61e050e068b0a5 Mon Sep 17 00:00:00 2001 From: Natalie Date: Sat, 27 Jun 2026 03:58:32 -0400 Subject: [PATCH] =?UTF-8?q?docs(@projects/@magic-civilization):=20?= =?UTF-8?q?=F0=9F=93=A1=20p3-29=20steps=201-2=20done=20=E2=80=94=20Rust=20?= =?UTF-8?q?turn=20emits=20+=20surfaces=20UI=20events;=20swap=20is=20render?= =?UTF-8?q?-gated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 1 (CityGrew/CityBordersExpanded/FloraSuccession) + step 2 (events in step result dict) complete + headless-safe. Latent siege-suppress bug fixed (7f4b69eac). Remaining: the live turn_manager swap (steps 3-5) — render-gated. Co-Authored-By: Claude Opus 4.8 (1M context) --- .project/objectives/README.md | 6 +-- .../p3-29-rail1-turn-unification.md | 9 +++- .../games/age-of-dwarves/data/objectives.json | 52 ++++++++++++++++--- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/.project/objectives/README.md b/.project/objectives/README.md index 33c2e39b..b5381ba4 100644 --- a/.project/objectives/README.md +++ b/.project/objectives/README.md @@ -17,8 +17,8 @@ | **P0** | 44 | 0 | 0 | 0 | 0 | 0 | 44 | | **P1** | 88 | 0 | 0 | 0 | 0 | 1 | 89 | | **P2** | 130 | 0 | 0 | 0 | 0 | 1 | 131 | -| **P3 (oos)** | 34 | 0 | 3 | 0 | 0 | 29 | 66 | -| **total** | **296** | **0** | **3** | **0** | **0** | **31** | **330** | +| **P3 (oos)** | 34 | 0 | 6 | 1 | 0 | 29 | 70 | +| **total** | **296** | **0** | **6** | **1** | **0** | **31** | **334** | @@ -26,7 +26,7 @@ | Team Lead | Remaining | |---|---| -| [warcouncil](../team-leads/warcouncil.md) | 3 | +| [warcouncil](../team-leads/warcouncil.md) | 7 | diff --git a/.project/objectives/p3-29-rail1-turn-unification.md b/.project/objectives/p3-29-rail1-turn-unification.md index 6885a87e..7831ffea 100644 --- a/.project/objectives/p3-29-rail1-turn-unification.md +++ b/.project/objectives/p3-29-rail1-turn-unification.md @@ -4,7 +4,7 @@ title: Rail-1 turn unification — live game calls the Rust turn, delete GDScrip priority: p3 scope: game1 owner: warcouncil -status: open +status: partial updated_at: 2026-06-27 --- @@ -26,6 +26,13 @@ The bridge already exists: `GdTurnProcessor::step(GdGameState)` (api-gdext/src/l ## Acceptance +**Steps 1-2 COMPLETE (headless-safe, 2026-06-27):** the Rust turn surfaces all granular UI +events (CityGrew 06c6e2547, CityBordersExpanded db808e477, FloraSuccession 7b6d24bde) AND +`GdTurnProcessor.step`'s result dict carries them as `result["events"]` (e165b4e6c, via +`replay::event_to_dict`). Also fixed a latent bug surfaced by the consolidation: B2 healing +healed besieged cities → siege-suppress (de68c9c10). All headless prep for the swap is done. + +**Remaining = the live swap (steps 3-5, render-gated):** - [ ] `turn_manager.gd` runs the turn via `GdTurnProcessor.step(GameState)` instead of the per-player `proc._process_*` loop. - [ ] The returned `TurnResult` is rendered to UI (EventBus signals: chronicle, combat log, diff --git a/public/games/age-of-dwarves/data/objectives.json b/public/games/age-of-dwarves/data/objectives.json index 91227a6a..62ef1542 100644 --- a/public/games/age-of-dwarves/data/objectives.json +++ b/public/games/age-of-dwarves/data/objectives.json @@ -1,13 +1,13 @@ { - "generated_at": "2026-06-26T18:57:51Z", + "generated_at": "2026-06-27T07:58:32Z", "totals": { - "partial": 3, - "missing": 0, - "done": 296, "in_progress": 0, - "stub": 0, + "partial": 6, + "stub": 1, + "missing": 0, "oos": 31, - "total": 330 + "done": 296, + "total": 334 }, "objectives": [ { @@ -3309,6 +3309,46 @@ "owner": "warcouncil", "updated_at": "2026-06-26", "summary": "> **Owner directive (2026-06-26):** the /loop \"continue until Game-1 done\" is **not\n> finished until the SIMULATOR is complete** — the headless Rust sim\n> (`mc-turn::TurnProcessor`, driven via `GdPlayerApi`/`magic_civ_*`) must play a full\n> self-play game with ALL systems, not the reduced subset shipped so far. See\n> [[project_loop_done_means_simulator_complete]].\n\nThe headless `step()` ([processor.rs:392+](../../src/simulator/crates/mc-turn/src/processor.rs))\ncurrently runs: trade (p3-25), economy, city_production (single queue), culture+border\nexpansion, tech/science, fauna encounters, combat/siege, diplomacy. Verified live via\n`magic_civ_view` (e.g. border expansion fired turn 0→1: `owned_tiles [[1,6]]→[[1,6],[0,6]]`).\n\n**Gaps (each verified absent from the headless turn):**" + }, + { + "id": "p3-27", + "title": "Biosphere in the headless sim — ecology population + flora succession + marine ecology", + "priority": "p3", + "status": "partial", + "scope": "game1", + "owner": "warcouncil", + "updated_at": "2026-06-26", + "summary": "Split from [[p3-26-complete-headless-simulator]]. The biological simulators exist as full\nRust crates — `mc-ecology` (`EcologyEngine`: per-tile fauna populations, predator/prey,\nevolution) and `mc-flora` (`FloraEngine`: per-tile vegetation + succession) — and the LIVE\ngame ticks them every turn (`EcologyState.tick` + `take_flora_transitions`,\nturn_manager.gd:315). But the **headless `mc-turn` step does NOT tick them** (verified: `0\nhits` for EcologyEngine/FloraEngine/flora in `processor.rs`). Only fauna *encounters*\n(combat) run headless. So the headless sim has no living biosphere for events/economy to\ninteract with." + }, + { + "id": "p3-28", + "title": "Modular turn architecture — break dep cycle, phase registry, boot-config DRY", + "priority": "p3", + "status": "partial", + "scope": "game1", + "owner": "warcouncil", + "updated_at": "2026-06-26", + "summary": "The per-subsystem sprawl noticed while porting climate/events/happiness/healing/ecology\nrevealed three SOLID/DRY/DIP debts. \"Foundation first\" tackled the layering + phase pieces." + }, + { + "id": "p3-29", + "title": "Rail-1 turn unification — live game calls the Rust turn, delete GDScript orchestration", + "priority": "p3", + "status": "partial", + "scope": "game1", + "owner": "warcouncil", + "updated_at": "2026-06-27", + "summary": "**The DRY / Rail-1 violation (verified 2026-06-27).** There are TWO turn orchestrations:\n- LIVE: `turn_manager.gd` → `turn_processor.gd::_process_*` (GDScript) + `EcologyState.tick` +\n `WorldsimState` — GDScript orchestrating the turn.\n- HEADLESS: `GdPlayerApi` → `mc_turn::TurnProcessor::step` (Rust).\n\nThe system *math* lives once in the Rust crates (DRY). The turn *orchestration* is duplicated —\nand the p3-26/p3-27 work this session added happiness/healing/improvements/recipes/equipment/\necology to `mc-turn` while the live game still runs its GDScript copies (e.g. `EcologyState.tick`\nduplicates the new Rust `ecology_phase`). This session BUILT `mc-turn::step` into the complete\nsingle source of truth; this objective is the capstone that makes it actually single.\n\nThe bridge already exists: `GdTurnProcessor::step(GdGameState)` (api-gdext/src/lib.rs:6354) runs\n`mc_turn::TurnProcessor::step` on the LIVE game's state. The live turn just doesn't call it." + }, + { + "id": "p3-30", + "title": "Port wild-creature AI from GDScript to Rust (Rail-1 compliance)", + "priority": "p3", + "status": "stub", + "scope": "game1", + "owner": "warcouncil", + "updated_at": "2026-06-27", + "summary": "**Rail-1 gap surfaced during the p3-29 logic sweep (2026-06-27).** The live turn runs\nwild-creature AI **decision logic in GDScript**: `turn_processor.gd::_process_wild_creatures`\n(line 459) calls `wild_ai.process_wild_turn(game_map)` →\n`src/game/engine/src/modules/ai/wild_creature_ai.gd` (302 LOC — a guard / attack / roam state\nmachine over `owner == -1` units).\n\nThis is sim logic, not presentation, so it violates Rail-1 (\"GDScript is presentation only\";\n\"AI decision-making lives in Rust\"). It is **distinct from [[p0-26-ai-tactical-rust-port]]**,\nwhich ported *player* tactical AI (`simple_heuristic_ai.gd` / `ai_tactical.gd` / `ai_military.gd`)\nand explicitly did not touch wild-creature behaviour. It is also distinct from the fauna\n*population/rendering/stats* objectives (`g2-08`, `p3-12`, `p1-49`, `p2-58a`) — those model\necology; this is the per-creature **combat behaviour AI**.\n\nThe combat *resolution* for wilds already lives in Rust (`mc-combat::wilds`); only the\n*decision* layer (who to attack, when to roam, leash enforcement) is still GDScript." } ] }