docs(objective): record p3-29 live-swap landed behind RUST_TURN flag (7475daa7)

Steps 3-5 now implemented (default OFF): turn_manager runs whole-round
GdTurnProcessor.step at round boundary under RUST_TURN=1, events[] -> EventBus.
Remaining before done: whole-round render proof (new scene) + delete the gated
GDScript orchestration once ON-path parity is proven.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Natalie 2026-06-28 10:04:40 -04:00
parent 7475daa7f8
commit 8bf06decf3

View file

@ -5,9 +5,25 @@ priority: p3
scope: game1
owner: warcouncil
status: partial
updated_at: 2026-06-27
updated_at: 2026-06-28
---
## Progress 2026-06-28 — live swap implemented behind `RUST_TURN` flag (7475daa7)
The render-gated steps 3-5 are now **implemented** (default OFF). `turn_manager.gd::end_turn` runs
the whole-round `GdTurnProcessor.step` on live state at the round boundary under `RUST_TURN=1`
(`_run_rust_round` + `_emit_rust_turn_events`), with the GDScript per-player `_process_*` loop and
the `next_player()` round-end sim glue gated off to avoid double-processing. Default path is
byte-for-byte the existing turn. Verified pre-commit: clean headless project load (no parse/script
errors, autoload registers); all referenced gdext methods/signals confirmed present
(`GdTurnProcessor.{step,load_authored_encounter_rates}`, `GdGameState.sync_{presentation_to_inner,
inner_to_presentation}`, EventBus `{tech,culture}_researched`/`golden_age_{started,ended}`/
`worldsim_updated`). **Two acceptance items remain before `done`:** (1) the whole-round-`RUST_TURN`
render proof (a new proof scene — the existing 7k proof is the older fauna flag); (2) deleting the
gated GDScript orchestration once the proof confirms ON-path parity. The GDScript path is gated,
not deleted, so the fallback survives until the replacement is proven. Carve-out (worldsim/terraform)
documented + retained.
## Summary
**The DRY / Rail-1 violation (verified 2026-06-27).** There are TWO turn orchestrations:
@ -124,17 +140,38 @@ events (CityGrew 06c6e2547, CityBordersExpanded db808e477, FloraSuccession 7b6d2
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,
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).
- [x] `turn_manager.gd` runs the turn via `GdTurnProcessor.step(GameState)` instead of the
per-player `proc._process_*` loop. **DONE behind a flag (7475daa7, 2026-06-28).** Under
`RUST_TURN=1`, `end_turn()` runs `_run_rust_round()` at the round boundary
(`is_last_in_round()`): `sync_presentation_to_inner``GdTurnProcessor.step` (whole round, all
players + sim glue, `state.turn` increment) → `sync_inner_to_presentation`; the per-player
`_process_*` loop and the `next_player()` round-end ecology/climate/wild/diplomacy passes are
gated OFF to avoid double-processing.
- [x] The returned `TurnResult` is rendered to UI (EventBus signals). **DONE (7475daa7):**
`_emit_rust_turn_events` translates `step`'s `events[]` (kind-tagged dicts from
`replay::event_to_dict`) into EventBus signals — `TechResearched`/`CultureResearched`/
`GoldenAgeStarted`/`GoldenAgeEnded` now; entity-payload kinds (CityGrew/UnitCreated/…) deferred
(need a live entity lookup) — the board is already correct via the synced presentation slots,
so only the per-event signal is deferred. `worldsim_updated` emitted to nudge the fauna overlay.
- [~] `turn_processor.gd::_process_*` orchestration + the duplicate `EcologyState.tick` deleted
(or reduced to UI-only translation). **NOT deleted — GATED instead.** Deliberate: the swap ships
behind a default-OFF flag so both paths coexist for safe rollout + A/B parity verification. The
GDScript orchestration is gated off under `RUST_TURN=1` but not yet removed; deletion follows
once the render proof confirms ON-path parity (else we'd lose the fallback before proving the
replacement).
- [ ] 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.
kept as the one remaining GDScript-driven pass with a tracked carve-out. **Carve-out kept (and
documented in `next_player()`):** world-event dispatch / terraform drain / contamination tick /
`worldsim_updated` render hook stay GDScript-driven — `step` does NOT cover them (p3-26/p3-27
boundary). The grid is still resolved across turns so this pass keeps running under the flag.
- [ ] **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).
a turn correctly through the Rust step (UI parity with the old GDScript turn). **STILL OPEN —
the blocker to `done`.** The existing `iter_7k_turn_processor_gated_proof` covers the older
`RUST_FAUNA_ENCOUNTERS` flag, not the whole-round `RUST_TURN` path — a NEW proof scene is needed
that drives `end_turn()` through a full round with `RUST_TURN=1` and shows state advancing +
rendering. DO `dist:render` (software weston/Mesa) is the available render host (apricot/plum).
- [ ] GUT green; headless `mc-turn` already proven (it IS the step being adopted). Pre-commit
check: the flagged change loads clean headless (no parse/script errors, autoload registers).
## Notes