diff --git a/.project/objectives/p2-67-claude-player-api.md b/.project/objectives/p2-67-claude-player-api.md index a0110118..eee4313f 100644 --- a/.project/objectives/p2-67-claude-player-api.md +++ b/.project/objectives/p2-67-claude-player-api.md @@ -639,11 +639,41 @@ that cite the precise schema mismatch blocking them. - `src/simulator/api-gdext/src/lib.rs` — `GdGameState::init` updated for new `trade_ledger` field. -## 2026-05-12 — Phase 13 STOP (demo would surface degenerate AI; render path absent) +## 2026-05-12 — Phase 13 STOP (render bridge from GdPlayerApi state does not exist) -Per brief hard-stop rule: "Claude-vs-AI demo produces no AI activity in -any 5-turn block → STOP, document, exit (signals a regression somewhere -in the AI driver)." +Two independent hard-stop conditions. Leading with the structural one +because it doesn't depend on any AI-behaviour debate. + +### Primary blocker — render path + +Phase 13 requires "Capture screenshots every 5 turns". The current +headless harness (`claude_player_main.gd`) is JSON-Lines only — no +scene tree, no TileMap, no camera. Production proof scenes +(`gameplay_arc_proof.tscn`, `world_map.tscn`, etc.) render from the +`GameState` autoload, not from a `GdPlayerApi`-held state. There is +NO path today that takes the JSON state held by +`GdPlayerApi.load_state_json` and renders it visually. + +Wiring this requires either: + +1. **Render bridge** — extract the proof-scene rendering pipeline into + a function that takes a `GdGameState` instance (not the + autoload), so the harness can pass its bootstrapped + ticked state + for capture. +2. **Two-process orchestration** — one process drives the JSON pump, + another reads its events and replays them into a renderable scene + on the side. + +Either is its own objective with its own surface area. Neither was +specced in p2-67 Phase 0-9 because Phase 13 was scoped as "use the +existing render path" without verifying one existed for this state +shape. + +### Secondary blocker — degenerate AI behaviour + +Per brief hard-stop rule: "Claude-vs-AI demo produces no AI activity +in any 5-turn block → STOP, document, exit (signals a regression +somewhere in the AI driver)." ### Evidence @@ -658,31 +688,10 @@ turn 4 → slot 1 actions_applied=0, slot 2 actions_applied=0 ``` A 25-turn run would produce identical zero-activity blocks for turns -5-9, 10-14, 15-19, 20-24. The hard-stop fires multiple times. Driving -the demo would produce a video of Claude playing solitaire while the -AI sits motionless — not the "Claude vs production AI" promise. - -### Independent blocker — render path - -Phase 13 also requires "Capture screenshots every 5 turns". The -current headless harness (`claude_player_main.gd`) is JSON-Lines only -— no scene tree, no TileMap, no camera. Production proof scenes -(`gameplay_arc_proof.tscn` etc.) render from `GameState` autoload, -not from a `GdPlayerApi`-held state. There is no path today that -takes the JSON state held by `GdPlayerApi.load_state_json` and renders -it visually. - -Wiring this requires either: - -1. **Render bridge** — extract the proof-scene rendering pipeline into - a function that takes a `GdGameState` instance (not the - autoload), so the harness can pass its bootstrapped + ticked state - for capture. -2. **Two-process orchestration** — one process drives the JSON pump, - another reads its events and replays them into a renderable scene - on the side. - -Either is its own objective with its own surface area. +5-9, 10-14, 15-19, 20-24. The hard-stop fires multiple times. Even +with the render bridge in place, the resulting video would be Claude +playing solitaire while the AI sits motionless — not the "Claude vs +production AI" promise. ### What WAS validated this session @@ -725,6 +734,21 @@ with a parallel observation store in mc-player-api)." "is tile (col, row) visible to player P at the current turn?" so the projector can mark each `TileView` as visible / fogged / hidden. +### What's actually missing + +**Not** "ObservationStore is the wrong shape" — `ObservationStore` is +fine as a *query surface*: `get_turn(turn).tile_indices.contains(idx)` +answers "was tile X visible to player P at turn T", which is exactly +what a fog projector needs for "Visible / Fogged / Hidden" classification. + +What's **missing** is the Rust-side visibility *producer*. Today +`record_turn(turn, grid, visible_tile_indices: &[u16])` takes +pre-computed visibility — the caller (presumably GDScript `Vision.gd` +or an equivalent Rust port that hasn't been ported yet) owns the +"compute which tiles are visible to player P right now" calculation. +There is no `mc-observation` API that takes `(GameState, PlayerId)` +and returns a visible-tile set. + ### What `ObservationStore` actually is A per-player CLIMATE / WEATHER observation history for the Chronicle