docs(@projects/@magic-civilization): 🏛️ p3-29 — Rail-1 turn unification objective (the real DRY fix)

Owner flagged the duplication: live game runs GDScript turn orchestration (turn_processor.gd
_process_* + EcologyState.tick) while headless runs mc-turn::step — two turn orchestrations.
This session built mc-turn::step into the complete single source of truth; p3-29 is the capstone:
switch turn_manager to GdTurnProcessor.step (bridge already exists at lib.rs:6354), render the
TurnResult for UI, delete the GDScript orchestration. HIGH-STAKES live-game rewrite — needs a
render proof before merge.

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

View file

@ -0,0 +1,49 @@
---
id: p3-29
title: Rail-1 turn unification — live game calls the Rust turn, delete GDScript orchestration
priority: p3
scope: game1
owner: warcouncil
status: open
updated_at: 2026-06-27
---
## Summary
**The DRY / Rail-1 violation (verified 2026-06-27).** There are TWO turn orchestrations:
- LIVE: `turn_manager.gd``turn_processor.gd::_process_*` (GDScript) + `EcologyState.tick` +
`WorldsimState` — GDScript orchestrating the turn.
- HEADLESS: `GdPlayerApi``mc_turn::TurnProcessor::step` (Rust).
The system *math* lives once in the Rust crates (DRY). The turn *orchestration* is duplicated —
and the p3-26/p3-27 work this session added happiness/healing/improvements/recipes/equipment/
ecology to `mc-turn` while the live game still runs its GDScript copies (e.g. `EcologyState.tick`
duplicates the new Rust `ecology_phase`). This session BUILT `mc-turn::step` into the complete
single source of truth; this objective is the capstone that makes it actually single.
The bridge already exists: `GdTurnProcessor::step(GdGameState)` (api-gdext/src/lib.rs:6354) runs
`mc_turn::TurnProcessor::step` on the LIVE game's state. The live turn just doesn't call it.
## Acceptance
- [ ] `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,
flora succession, notifications) — GDScript translates the result, emits no sim logic.
- [ ] `turn_processor.gd::_process_*` orchestration + the duplicate `EcologyState.tick` deleted
(or reduced to UI-only translation).
- [ ] WorldsimState/terraform: either ported into `mc-turn` (preferred, completes Rail-1) or
kept as the one remaining GDScript-driven pass with a tracked carve-out.
- [ ] **Render proof**: a `scenes/tests/` proof scene + screenshot showing the live game plays
a turn correctly through the Rust step (UI parity with the old GDScript turn).
- [ ] GUT green; headless `mc-turn` already proven (it IS the step being adopted).
## Notes
Created 2026-06-27 after the owner flagged that "headless runs every system the live game does"
is duplication, not DRY. HIGH-STAKES: rewrites the playable game's turn loop — must not merge
without the render proof (Rail UI rule + phase-gate). Sequence: (1) audit what the GDScript loop
emits vs `TurnResult`; (2) wire turn_manager → GdTurnProcessor.step behind the result-render;
(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).