fix(server): populate games_v2 metadata on game start
update_game_started (started_at, num_players, num_rounds, player_ids) was defined in event_store but had zero callers. 289/289 staging games had those fields NULL — queries that joined on them returned garbage, and the denormalized player_ids GIN index was dead weight. log_game_start now calls create_game THEN update_game_started in one async task. If create fails, update is skipped (row doesn't exist). handlers.py passes num_rounds and player_ids through at call time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,22 +63,20 @@ class GameLogger:
|
||||
self,
|
||||
room_code: str,
|
||||
num_players: int,
|
||||
num_rounds: int,
|
||||
player_ids: list[str],
|
||||
options: "GameOptions",
|
||||
game_id: Optional[str] = None,
|
||||
) -> str:
|
||||
"""
|
||||
Log game start, return game_id.
|
||||
Log game start. Writes the row via create_game and then populates
|
||||
started_at/num_players/num_rounds/player_ids via update_game_started
|
||||
so downstream queries don't see a half-initialized games_v2 row.
|
||||
|
||||
Creates a game record in games_v2 table.
|
||||
|
||||
Args:
|
||||
room_code: Room code for the game.
|
||||
num_players: Number of players.
|
||||
options: Game options/house rules.
|
||||
|
||||
Returns:
|
||||
Generated game UUID.
|
||||
If create_game fails the update is skipped — the row doesn't exist.
|
||||
"""
|
||||
game_id = str(uuid.uuid4())
|
||||
if game_id is None:
|
||||
game_id = str(uuid.uuid4())
|
||||
|
||||
try:
|
||||
await self.event_store.create_game(
|
||||
@@ -87,9 +85,20 @@ class GameLogger:
|
||||
host_id="system",
|
||||
options=self._options_to_dict(options),
|
||||
)
|
||||
except Exception as e:
|
||||
log.error(f"Failed to log game start (create): {e}")
|
||||
return game_id
|
||||
|
||||
try:
|
||||
await self.event_store.update_game_started(
|
||||
game_id,
|
||||
num_players,
|
||||
num_rounds,
|
||||
player_ids,
|
||||
)
|
||||
log.debug(f"Logged game start: {game_id} room={room_code}")
|
||||
except Exception as e:
|
||||
log.error(f"Failed to log game start: {e}")
|
||||
log.error(f"Failed to log game start (update): {e}")
|
||||
|
||||
return game_id
|
||||
|
||||
@@ -97,6 +106,8 @@ class GameLogger:
|
||||
self,
|
||||
room_code: str,
|
||||
num_players: int,
|
||||
num_rounds: int,
|
||||
player_ids: list[str],
|
||||
options: "GameOptions",
|
||||
) -> str:
|
||||
"""
|
||||
@@ -108,32 +119,29 @@ class GameLogger:
|
||||
game_id = str(uuid.uuid4())
|
||||
|
||||
try:
|
||||
loop = asyncio.get_running_loop()
|
||||
# Already in async context - fire task, return ID immediately
|
||||
asyncio.create_task(self._log_game_start_with_id(game_id, room_code, num_players, options))
|
||||
asyncio.get_running_loop()
|
||||
asyncio.create_task(
|
||||
self.log_game_start_async(
|
||||
room_code=room_code,
|
||||
num_players=num_players,
|
||||
num_rounds=num_rounds,
|
||||
player_ids=player_ids,
|
||||
options=options,
|
||||
game_id=game_id,
|
||||
)
|
||||
)
|
||||
return game_id
|
||||
except RuntimeError:
|
||||
# Not in async context - run synchronously
|
||||
return asyncio.run(self.log_game_start_async(room_code, num_players, options))
|
||||
|
||||
async def _log_game_start_with_id(
|
||||
self,
|
||||
game_id: str,
|
||||
room_code: str,
|
||||
num_players: int,
|
||||
options: "GameOptions",
|
||||
) -> None:
|
||||
"""Helper to log game start with pre-generated ID."""
|
||||
try:
|
||||
await self.event_store.create_game(
|
||||
game_id=game_id,
|
||||
room_code=room_code,
|
||||
host_id="system",
|
||||
options=self._options_to_dict(options),
|
||||
return asyncio.run(
|
||||
self.log_game_start_async(
|
||||
room_code=room_code,
|
||||
num_players=num_players,
|
||||
num_rounds=num_rounds,
|
||||
player_ids=player_ids,
|
||||
options=options,
|
||||
game_id=game_id,
|
||||
)
|
||||
)
|
||||
log.debug(f"Logged game start: {game_id} room={room_code}")
|
||||
except Exception as e:
|
||||
log.error(f"Failed to log game start: {e}")
|
||||
|
||||
async def log_game_end_async(self, game_id: str) -> None:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user