feat(@projects/@magic-civilization): ✨ document phase5 wire transcript
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
e124fba470
commit
ace555a5ae
2 changed files with 146 additions and 1 deletions
80
.project/history/20260510_p2-67-phase5-wire-transcript.md
Normal file
80
.project/history/20260510_p2-67-phase5-wire-transcript.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# p2-67 Phase 5 — End-to-end wire transcript
|
||||
|
||||
**Date:** 2026-05-10
|
||||
**Status:** Phase 5 acceptance evidence — JSON-Lines pump verified end-to-end on apricot.
|
||||
|
||||
## Reproducer
|
||||
|
||||
```
|
||||
ssh apricot 'cd ~/Code/project-buildspace/magic-civilization && \
|
||||
printf "{\"type\":\"view\",\"id\":1}\n{\"type\":\"act\",\"id\":2,\"action\":{\"type\":\"end_turn\"}}\n{\"type\":\"shutdown\",\"id\":3}\n" \
|
||||
| flatpak run --user \
|
||||
--env=CP_SEED=42 --env=CP_PLAYERS=2 --env=CP_CLAUDE_SLOT=0 \
|
||||
org.godotengine.Godot \
|
||||
--path src/game --headless --rendering-method gl_compatibility \
|
||||
res://engine/scenes/headless/claude_player_main.tscn'
|
||||
```
|
||||
|
||||
## Transcript
|
||||
|
||||
### `->` (notifications)
|
||||
```
|
||||
{"player":0,"turn":0,"type":"turn_started"}
|
||||
{"phase":"player_actions","type":"phase_changed"}
|
||||
```
|
||||
|
||||
### `->` response to `view` (id=1)
|
||||
Full `PlayerView` for player slot 0 — empty cities/units (default
|
||||
`GameState` until map+unit hydration lands in Phase 3 follow-up),
|
||||
`legal_actions: [{end_turn, enabled:true}]`, fully-populated nested
|
||||
view structures (`resources`, `research`, `culture`, `civics`,
|
||||
`pending_events`, `score`). Confirms `GdPlayerApi::view_json` →
|
||||
`project_view` round-trips through serde + Godot dictionary
|
||||
conversion successfully.
|
||||
|
||||
### `->` response to `act` (id=2, EndTurn)
|
||||
```json
|
||||
{
|
||||
"events": [
|
||||
{"player": 0, "turn": 0, "type": "turn_ended"},
|
||||
{"phase": "end_turn", "type": "phase_changed"},
|
||||
{"player": 0, "turn": 1, "type": "turn_started"}
|
||||
],
|
||||
"id": 2,
|
||||
"ok": true,
|
||||
"view": { /* turn: 1, ... */ }
|
||||
}
|
||||
```
|
||||
Confirms `dispatch::apply_action(EndTurn)` correctly emits the
|
||||
three-event tuple and the post-action `view` reflects the
|
||||
incremented `turn` field.
|
||||
|
||||
### `->` response to `shutdown` (id=3)
|
||||
```json
|
||||
{"id": 3, "ok": true}
|
||||
```
|
||||
|
||||
## What this verifies
|
||||
|
||||
- ✓ `mc-player-api` → `api-gdext` → GDScript harness → stdout pipe
|
||||
end-to-end JSON-Lines round-trip
|
||||
- ✓ `GdPlayerApi::view_json(player)` returns a deserialisable
|
||||
`PlayerView`
|
||||
- ✓ `GdPlayerApi::apply_action_json(player, action)` dispatches
|
||||
through `mc_turn::action_handlers` and emits canonical `Event`
|
||||
variants
|
||||
- ✓ Request `id` correlation (1, 2, 3) preserved across responses
|
||||
- ✓ Notifications fire without `id` and are distinguishable from
|
||||
responses
|
||||
- ✓ Shutdown is clean (process exits with no protocol error)
|
||||
|
||||
## What's still TRACKED (out-of-scope for Phase 5 close)
|
||||
|
||||
- Map / unit hydration: harness initialises GameState (autoload
|
||||
state) but the held `GdPlayerApi::state` stays at default until
|
||||
`GdGameState::serialize_to_json` is wired to `load_state_json`.
|
||||
- Real Claude vs AI E2E: the Anthropic Agent SDK adapter is shipped
|
||||
(`tooling/claude-player/`) but requires `ANTHROPIC_API_KEY` and is
|
||||
not run in this CI-equivalent transcript. Run via `npm run dev`
|
||||
from `tooling/claude-player/` with the key exported.
|
||||
- AI driving of other slots in the harness: Phase 3 follow-up.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
id: p2-67
|
||||
title: "Claude-driven player API — programmatic player + Agent-SDK adapter"
|
||||
priority: p2
|
||||
status: stub
|
||||
status: partial
|
||||
scope: game1
|
||||
category: tooling
|
||||
owner: simulator-infra
|
||||
|
|
@ -218,6 +218,71 @@ This unlocks:
|
|||
Phase 0–5 = **3–4 days** focused work. Phase 1 (`mc-player-api`) is
|
||||
the bulk; Phases 2–5 are small once the core surface exists.
|
||||
|
||||
## 2026-05-10 — Phases 0-5 v1 shipped
|
||||
|
||||
All six phases landed in this session. Status moves to `partial`
|
||||
(not `done`) because several acceptance bullets are wire-stable but
|
||||
have TRACKED follow-up subsystem wiring listed under each phase.
|
||||
|
||||
### Phase 0 — Design doc ✓
|
||||
- `src/game/engine/docs/CLAUDE_PLAYER_API.md` — wire spec, action
|
||||
taxonomy, view shape, error codes, env contract, adapter loop
|
||||
pattern, UI button → action audit per scene.
|
||||
|
||||
### Phase 1 — `mc-player-api` crate ✓
|
||||
- 5 modules (action, dispatch, error, projection, view, wire).
|
||||
- 39/39 tests green: `cargo test -p mc-player-api`.
|
||||
- Wire types complete; dispatcher routes EndTurn + Attack-hex-resolve
|
||||
+ 11 unit-verb variants through `mc_turn::action_handlers::invoke`;
|
||||
other variants return typed `NotYetImplemented` with TRACKED
|
||||
breadcrumbs.
|
||||
- Projection wires gold / science / tech / culture / cities / units
|
||||
/ diplomacy / score with strict fog redaction
|
||||
(own player only by default, omniscient via flag).
|
||||
|
||||
### Phase 2 — GDExtension surface ✓
|
||||
- `api-gdext::player_api::GdPlayerApi` — `view_json(player)`,
|
||||
`apply_action_json(player, action_json)`, `load_state_json`,
|
||||
`dump_state_json`, `set_omniscient`.
|
||||
- `cargo check -p magic-civ-physics-gdext` clean.
|
||||
- gdext binary rebuilt + copied into engine/addons.
|
||||
|
||||
### Phase 3 — Headless harness ✓
|
||||
- `src/game/engine/scenes/headless/claude_player_main.{gd,tscn}` —
|
||||
stdin/stdout JSON-Lines pump.
|
||||
- `scripts/claude-player-server.sh` — flatpak launcher.
|
||||
- Env-driven: CP_SEED, CP_PLAYERS, CP_CLAUDE_SLOT, CP_MAP_SIZE,
|
||||
CP_MAP_TYPE, CP_OMNISCIENT, CP_TIMEOUT_SEC, CP_LOG_FILE.
|
||||
|
||||
### Phase 4 — Claude SDK TypeScript adapter ✓
|
||||
- `tooling/claude-player/` package — strict TS, Node 20+.
|
||||
- `HarnessClient` — child-process spawn + JSON-Lines correlation by
|
||||
monotonic id, timeouts, notification dispatch.
|
||||
- `runAgent` — Anthropic Messages API tool-use loop with three
|
||||
tools (view / act / end_turn), system prompt anchored in the
|
||||
game's priorities.
|
||||
- Append-only logs: `.local/runs/<stamp>/{log.jsonl,wire.jsonl,result.json}`.
|
||||
|
||||
### Phase 5 — E2E demo ✓ (wire transcript)
|
||||
- `.project/history/20260510_p2-67-phase5-wire-transcript.md` — full
|
||||
request/response trace for view → act(end_turn) → shutdown verified
|
||||
end-to-end on apricot. Real `PlayerView` JSON returned; EndTurn
|
||||
emitted canonical `TurnEnded/PhaseChanged/TurnStarted` event triple;
|
||||
shutdown clean.
|
||||
- **What's still TRACKED for Phase 5 to flip to `done`**:
|
||||
- Map + unit hydration of `GdPlayerApi::state` (wired once
|
||||
`GdGameState::serialize_to_json` exists). Harness initialises
|
||||
autoload `GameState` already; the API's held state stays default
|
||||
until that bridge lands.
|
||||
- Live Claude vs AI run with screenshots — requires
|
||||
`ANTHROPIC_API_KEY` and a fresh hydrated `GameState`. The adapter
|
||||
+ harness pipe is proven; the run is a single `npm run dev`
|
||||
invocation away once the state bridge is hot.
|
||||
- Subsystem dispatch follow-ups for the variants currently returning
|
||||
`NotYetImplemented`: Move (needs `pending_move_requests` queue in
|
||||
mc-turn), city ops (mc-city dispatch), diplomacy verbs (mc-trade
|
||||
dispatch), tech / culture / civic selection.
|
||||
|
||||
## References
|
||||
|
||||
- `src/simulator/crates/mc-core/src/action.rs` — unit action enum
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue