mc-state crate created + GameState moved into it (green @0ed21945c). Records the 3 green-between commits (0bace0e6c/45e9adea9/0ed21945c), the save-format + parity evidence, the honest ~5/9 acceptance recount (bullet 6 still 20+ shim leaks → status stays partial, NOT done), and the precise Phase-4 path: sweep all mc_turn::game_state/GameState sites (external + mc-turn internals + the lib.rs:62 re-export) to mc_state::, delete both shims, with the dev-dep rule for mc-core/derived_stats (the one upstream-of-mc-state consumer). FINISH_GAME1_PLAN Wave-D row 1 updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.6 KiB
Finish Game 1 — Plan of Record
Generated: 2026-06-04, from the true-state gap analysis appended to all 28 open objectives.
Definition of done (operator, 2026-06-04): every open objective reaches done EXCEPT the two accepted-open items:
- Audio sign-off (
p2-16) — functionally complete & plays in-game; needs a human ear. - Artist-paid final sprites (
p2-23…p2-27) — placeholder coverage ships the build (commercial-safe game-icons baseline + Wesnoth demo layer); final art is a paid-artist commission.
Out of scope for "Game 1 complete": the web guide (p2-18) is a companion app on its own track, not the game.
Index snapshot: done 241 · partial 19 · stub 8 · missing 1 · in_progress 1 (of 303; rest oos/superseded). The base 4X game is functionally ROADMAP-complete and playable today (131 UI scenes, MCTS AI, full turn loop). The work below is completion polish + one hard AI problem + an architecture refactor.
The one real risk: AI convergence (not a checkbox)
p1-29h Phase 1 built the decisiveness capability (army target-lock + commitment hysteresis + press-on-capture, 278 tests green). Phase 2 built the fair measurement surface and measured: 20 captures → 0 eliminations → 38 refounds over 160 turns. The army takes cities; the loser always refounds and recovers. Diagnosis is precise (refound-suppression), but the fix is unsolved and likely needs balance-design iteration (suppress refounding hard enough to converge without breaking 4X feel). This is the only item I cannot promise lands clean — budget several iterations. Everything else is mechanical.
Waves (dependency-ordered)
Wave A — wiring & quick wins (S–M · highest value/effort)
Built logic that's dead-ended on a missing thin wrapper, plus cheap unblocks.
| Task | Objective | Detail |
|---|---|---|
statistics.tscn wrapper |
p2-47 | 709-line statistics.gd + mc-score exist; world_map.gd:1001 & ingame_menu.gd:80 push a missing .tscn → F9/info-button/Stats menu dead-end. Author the one-node wrapper. (bug fix) |
end_game_summary.tscn wrapper + game-over wiring + GUT |
p2-48a (+ p2-48) | end_game_summary.gd orphaned (no .tscn, nothing instantiates). Logic/tests largely done; author wrapper, wire all 4 GameOverReason, GUT + apricot proof. |
| processor live-loop hookup | p2-57b + p2-57c | Wire tick_and_stamp/apply_quality into mc-turn::processor::process_city_production (zero quality calls today). One M task closes both — unit quality is inert in-game until it lands. Rephrase p2-57b bullet-4 (global default covers all units; per-unit optional). |
_pick_research regression batch |
p0-26b | Run 10-seed T300 on apricot vs main; flip done if tier_peak ≥ baseline. |
| 3 missing unit JSONs | (data) | dwarf_master_engineer, master_surgeon, saga_writer referenced by buildings but absent. |
Wave B — lairs (M)
| Task | Objective | Detail |
|---|---|---|
GdLair::assault bridge + Assault/Siege/Raid picker UI |
p3-10a | Resolver + loot all done (4/5); only the GDExt bridge + picker remain. |
Wire SiegeState into dispatch + turn loop |
p3-10b | tick_siege/SiegeState landed but dead code (LairCombatMode::Siege → NotImplemented). Add dispatch branch, per-turn integration, siege_resistance JSON, tests, bridge. |
Wave C — AI convergence (L · AT RISK — see risk box)
| Task | Objective | Detail |
|---|---|---|
| Refound-suppression lever (new objective p1-29i) | p1-29h, p1-29d | Suppress/delay enemy refound after city loss (or make captures sticky). Re-measure ≥1 elimination on the existing gridded harness. |
| Re-score convergence + trained-vs-scripted | p1-29d, p1-29g | Once eliminations occur, re-run the gridded surface; p1-29g (unblocked, p1-29f done) drives trained vs scripted. |
| Production-posture short-circuit | p1-29e | Smaller lever; re-evaluate after refound-suppression. |
| Upstream prereqs (NOT in the 28) | p0-08, ecology | p0-08 luxury-tempo must land in main → unblocks p1-05-fu. Flip ecology_yields.json off static_terrain → unblocks p1-38-fu. Then run both balance batches. |
Wave D — architecture stack (L · the heavy refactor, multi-session)
Rail-1 hygiene: make the existing UI read game state from Rust. Game renders fine via GDScript today — this is post-demo correctness, but required for "complete." Chain order:
| Order | Objective | Detail |
|---|---|---|
| 1 | p2-65 | 🟡 partial (~5/9, green @ 6de3c67a8) — mc-state crate created + GameState moved into it behind pub use shims (Phases 1/3a/3b landed 2026-06-04; save-format round-trip byte-identical + parity trio green). Remaining: Phase 4 (sweep 20+ mc_turn::game_state consumer sites + mc-turn internals + the lib.rs:62 re-export to mc_state::, delete shims — bullet 6 must hit zero hits), Phase 5 (Cargo downgrades), Phase 7 (p2-55f SimConfig). See p2-65 resume note. |
| 2 | p2-72a-building-entity-port | Rust surface done (5/11); remove the parallel npc_buildings array + spatial index from game_state.gd, route 6 readers through GdGameState. |
| 3 | p2-72a (canonical render source) | The 5–8 day milestone: convert PlayerScript/UnitScript/GameMap fat classes → thin views over GdGameState. |
| 4 | p2-72b — Path 2 | Vec<Vec<mc_city::City>> on GdGameState (operator-chosen; blocker cleared). |
| 5 | p2-72a-save-format-migration | GDScript SaveManager rewrite (Rust backend SaveEnvelope done; fix CURRENT_VERSION doc drift 2 vs 1). |
| 6 | p2-72 | GdPlayerApi → GdGameState render bridge — ~1hr tail once the stack lands. |
Wave E — CI hygiene (S)
| Task | Objective | Detail |
|---|---|---|
| Choose + apply max-file-lines policy | p2-10k-followup | 11 files >500 lines; game_state.gd now 718 (split into subdirs per the <500 rule — naturally folds into Wave D's game_state.gd refactor). |
Critical path & sequencing
- Wave A and B are independent, parallel-safe in concept but all touch Rust/GDScript source → one serialized source lane (single shared workspace, no worktrees). Asset/run/doc work parallelizes; source does not.
- Wave D is the long pole by wall-clock (the p2-72a render-source milestone, 5–8 days). It can run as its own multi-session lane in parallel with A/B/C only if file-disjoint — in practice it churns
game_state.gd+ api-gdext, so it largely serializes with A's processor hookup and B's bridges. Recommend: A → (B ∥ start of D) → C in the background → finish D. - Wave C is research-paced; start the refound-suppression lever early and iterate while A/B/D mechanical work proceeds.
Accepted-open at "Game 1 complete"
p2-16audio — human listen-test only.p2-23…p2-27— paid final art (placeholders ship).p2-18web guide — separate track (needs WASM build + operator publish-approval).
Integration / commits
All work lands as atomic commits on the worktree-bridge-cse_* submodule branch; the live commits.service + claire-agent daemons propagate to main automatically (do NOT manually merge — it races the daemons). Proof screenshots capture on apricot (plum down).
Wave F — Design-system fidelity (NEW 2026-06-04 · L · the "Godot UI ≠ design guides" gap)
Gap (quantified): the design system (design-tokens.json + UI_DESIGN_SYSTEM.md + HTML sketches + React gallery) drives the web guide (fantasy-theme.ts) but not the Godot game. ui_theme.tres exists yet is never applied as the root theme, and 45 scene scripts hardcode 973 raw Color() + 307 add_theme_*_override calls, hand-rolling visuals that diverge from the spec. The scenes are GUT-green but visually plain — a real "missing UI side" beyond wiring.
| Task | Objective | Detail |
|---|---|---|
Token→theme pipeline + global apply + ThemeAssets.color() accessor |
p2-73 | Generate ui_theme.tres from design-tokens.json (tokens = SoT); apply it as the root Control theme; add a semantic token-color accessor. Foundation — in progress. |
| De-hardcode 45 scene scripts | p2-74 (blocked_by p2-73) | Route 973 inline Color() + 307 overrides onto the theme / ThemeAssets.color() tokens, per-screen-cluster, always-green. The bulk of the visual-fidelity work — L, multi-session. |
Why it matters / honest framing: the web feels "easier" because tokens flow straight to CSS; Godot's Control/Theme/StyleBox + programmatic tree-building threw that away. The fix is the missing tokens → .tres plumbing + a de-hardcode pass — not shipping HTML (Godot is the Steam target). Polish-tier, not demo-blocking, but required if "Game 1 complete" means fidelity to the design guides.