docs(@projects/@magic-civilization): 🔎 p3-29 — audit: the DRY fix's bulk is event-surfacing for UI parity, not the call-swap

TurnResult.events_emitted is replay-thin (founded/captured/killed/created); live UI needs
city_grew/building_completed/border_expanded/culture_researched/flora_succession. Real p3-29
work: enrich Rust event surface (headless-safe) → surface in dict → GDScript translates →
swap+delete → render-proof. Steps 1-2 carry no live-game risk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Natalie 2026-06-27 02:16:39 -04:00
parent 1a4c9c7d36
commit dd31de9acb

View file

@ -47,3 +47,28 @@ emits vs `TurnResult`; (2) wire turn_manager → GdTurnProcessor.step behind the
(3) delete the GDScript orchestration; (4) render-proof on apricot/plum. This is the true
Rail-1 finish line — bigger than B7 (per-building queues), which becomes moot once the live
game runs the Rust turn (which has the model the unified turn will use).
## De-risking audit (2026-06-27) — the bulk is event-surfacing, not the call-swap
`GdTurnProcessor::step(GdGameState)` (the bridge) exists and the Rust step computes every
system. The blocker to switching the live game is **UI event parity**:
- `TurnResult.events_emitted: Vec<mc_replay::TurnEvent>` is REPLAY-focused — only
`CityFounded / CityCaptured / UnitKilled / UnitCreated / GameOver / AmbientEncounterFired`.
- The live GDScript turn emits far richer UI signals inline: `city_grew`,
`city_building_completed`, `city_unit_completed`, `city_border_expanded`,
`culture_researched`, `flora_succession`, `fauna_round_started/ended`, …
- `turn_result_to_dict` surfaces only a thin slice (lair/victory/fauna).
So the real p3-29 work, in order:
1. **Enrich the Rust turn's event surface** — emit the granular UI events (growth, building/unit
completion, border expansion, culture, flora succession) from the phases that cause them into
`TurnResult` (headless-verifiable, no live-game risk).
2. **Surface them through `turn_result_to_dict`** so GDScript receives them.
3. **`turn_manager` translates `TurnResult``EventBus` emits** (GDScript = pure render).
4. **Swap** turn_manager to `GdTurnProcessor.step`; **delete** `turn_processor.gd::_process_*`
+ the duplicate `EcologyState.tick`.
5. **Render-proof** on apricot/plum.
Steps 1-2 are the bulk and are safe (Rust + headless tests, live game untouched). Steps 3-5 are
the live-game swap (needs the render proof). This is why the simulation was buildable headless
this session but the live game still runs GDScript — the event-surface gap was never closed.