2.1 KiB
2.1 KiB
Issue #310 — Host transition idempotency and error catalog
Scope
This artifact hardens the two host-owned scoreboard exits in the canonical gameplay flow:
POST /lobby/sessions/{code}/rounds/nextPOST /lobby/sessions/{code}/finish
The goal is retry-safe host behavior when the scoreboard transition already succeeded server-side but the client retries because of a duplicate click, timeout, or lost response.
Transition contract
| Endpoint | First valid transition | Idempotent replay state | Replay result | Broadcast behavior | Still-invalid states |
|---|---|---|---|---|---|
POST /lobby/sessions/{code}/rounds/next |
scoreboard -> lie |
lie with persisted current-round bootstrap (RoundConfig + RoundQuestion) |
200 OK with the same canonical next-round payload shape |
phase.lie_started fires only on the first transition |
lobby, guess, reveal, finished → next_round_invalid_phase |
POST /lobby/sessions/{code}/finish |
scoreboard -> finished |
finished |
200 OK with the same final leaderboard payload shape |
phase.game_over fires only on the first transition |
lobby, lie, guess, reveal → finish_game_invalid_phase |
Error catalog notes
No new backend error codes were introduced for this slice.
The contract change is behavioral:
next_round_invalid_phasenow means the session is in a phase where the scoreboard → next-round transition has not already been completed, or the expected bootstrap artifact for the already-started round is missing.finish_game_invalid_phasenow means the session is in a phase where the scoreboard → finish transition has not already been completed.- Successful replays are returned as normal
200 OKcanonical responses instead of phase errors.
Acceptance evidence
- Repeated
rounds/nextcalls after a successful scoreboard exit return the same canonical lie/bootstrap payload without incrementing the round twice. - Repeated
finishcalls after a successful scoreboard exit return the same finished leaderboard payload without rebroadcasting game-over. - Wrong-phase calls outside those replay states still return the existing shared error codes.