feat(game): canonical gameId in POST /api/v1/admin/init #72
Reference in New Issue
Block a user
Delete Branch "feature/canonical-game-id-init"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
POST /api/v1/admin/initтеперь принимает обязательное полеgameId. Движок больше не генерирует свой собственный UUID — каноническую идентичность партии выдаёт оркестратор (бэкенд), который и так использует её для имени контейнера, host-bind-mount-директории иgames.game_idв БД.gameId == uuid.Nil→ 400, попыткаinitповерх существующегоstate.json(с любымgameId) → 409. Идемпотентный повтор пока не поддерживается — это вне scope-а PR.gameIDвrest.InitRequest{GameID: gameID, Races: races}; engine-clientInitне меняется (шлёт DTO как есть).state.jsonвсегда содержит тот же UUID, что иgames.game_idбэкенда.Затронутые контракты
game/openapi.yaml—gameIdобязателен вInitRequest, новый response409 ConflictErrorдляadminInitGame.pkg/model/rest/init.go— полеGameID uuid.UUIDсbinding:"required".Чего нет в этом PR (намеренно)
raceIDvs бэкендныйEnginePlayerUUID) — отдельная история; backend/engine сегодня сравниваются поRaceName, расхождения UUID-ов не ломают рантайм.init— нужен сценарий-обоснование.state.jsonили миграция формата — не требуется, полеidтам и так есть.Test plan
go test ./game/...локально — зелёныйgo test ./backend/internal/{engineclient,runtime,lobby,server}/...локально — зелёныйgo-unit.yamlна gitea (run #528) — зелёныйui-test.yamlна gitea — должен запуститься на PR (правки только в Go, должен быть нерелевантен)integration.yamlна gitea — testcontainers-сюита;runtime_lifecycle_testподнимает реальный движок и бэкенд, должен пройти без правокcurl POST /api/v1/admin/initс тем же storage-путём, но другимgameId→ 409; сgameId = 00000000-…→ 400Engine no longer mints its own game UUID. The orchestrator (backend) generates the game UUID at game-create time and passes it in the admin/init request body as the required `gameId` field, so the value that names the engine container and host bind-mount directory also ends up inside the engine's state.json. The engine rejects the zero UUID with 400 and any init that conflicts with an existing state.json with 409 (a second init on the same gameId is also a conflict; full idempotency is not part of the contract). Updates rest.InitRequest, openapi.yaml (schema + 409 response), controller.GenerateGame/NewGame/buildGameOnMap signatures, the engine HTTP handler/executor, the backend runtime worker, and the relevant unit and contract tests. Documentation in game/README.md, docs/ARCHITECTURE.md, backend/README.md, and backend/docs/{runtime,flows}.md is updated in the same patch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>