magicciv/.project/objectives/p3-29-rail1-turn-unification.md
Natalie 1a4c9c7d36 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>
2026-06-27 02:13:36 -04:00

2.7 KiB

id title priority scope owner status updated_at
p3-29 Rail-1 turn unification — live game calls the Rust turn, delete GDScript orchestration p3 game1 warcouncil open 2026-06-27

Summary

The DRY / Rail-1 violation (verified 2026-06-27). There are TWO turn orchestrations:

  • LIVE: turn_manager.gdturn_processor.gd::_process_* (GDScript) + EcologyState.tick + WorldsimState — GDScript orchestrating the turn.
  • HEADLESS: GdPlayerApimc_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).