feat(game): official first-move tile draw + admin step-by-step replay #89

Merged
developer merged 2 commits from feature/first-move-draw into development 2026-06-20 08:42:51 +00:00
Owner

What

Official first-move selection by tile draw, recorded with the game, plus a step-by-step admin board replay.

First-move draw (docs/ARCHITECTURE.md §6)

  • Each seated player draws one tile; the one closest to "A" leads (a blank beats every letter); ties re-draw until a single leader.
  • Honest per-draw crypto/rand entropy — not the deterministic bag seed — so the recorded draw, not a seed, is the only account of the outcome.
  • The leader takes seat 0, so the engine and journal replay are unchanged.
  • Recorded in game_setup_draws (migration 00013) for future tournaments; modelled as a discrete "player N draws a tile" step.
  • Friend/AI draw at create. Auto-match draws at open against a synthetic uuid.Nil opponent whose draw rows (NULL account_id) are back-filled on join — so the opener's seat is fixed up front and the existing open-game pre-move is preserved (no reseating, no play-gating). (This replaced an earlier "reseat at fill" approach that conflicted with the open-game pre-move — see the design-spec Update note.)

Admin replay (/_gm/games/:id)

  • New game.ReplayTimeline rebuilds the game from seed+journal, snapshotting racks/scores/turn/bag and the tiles drawn per move.
  • Server-rendered board + a small vanilla-JS stepper: A–O / 1–15 headers, highlighted premium squares, placed letters with the tile value as a subscript, rack panels (seat 0 top / 1 bottom / 2 left / 3 right) with the current player highlighted, a per-move log with the drawn tiles + bag remainder, and the first-move draw as a flat list.

Tests

  • Unit: seeding (ranking, blank-wins, tie chains, rotation, cap), drawnTiles/usedTiles, SetupBag.
  • Integration: draw recorded + seat 0 = winner (Create); synthetic NULL → back-filled on join (auto-match); ReplayTimeline deal+move; the admin page renders the draw + replay sections. Open-match tests reworked for the draw-at-open behaviour.

Docs

ARCHITECTURE §6/§9, FUNCTIONAL (+ _ru), PRERELEASE (FM row), and a design spec under docs/superpowers/specs/ (say if you'd rather not keep that file).

## What Official first-move selection by tile draw, recorded with the game, plus a step-by-step admin board replay. ## First-move draw (docs/ARCHITECTURE.md §6) - Each seated player draws one tile; the one closest to "A" leads (a blank beats every letter); ties re-draw until a single leader. - Honest per-draw `crypto/rand` entropy — **not** the deterministic bag seed — so the recorded draw, not a seed, is the only account of the outcome. - The leader takes **seat 0**, so the engine and journal replay are unchanged. - Recorded in `game_setup_draws` (migration `00013`) for future tournaments; modelled as a discrete "player N draws a tile" step. - Friend/AI draw at create. **Auto-match draws at open** against a synthetic `uuid.Nil` opponent whose draw rows (NULL `account_id`) are back-filled on join — so the opener's seat is fixed up front and the existing open-game pre-move is preserved (no reseating, no play-gating). *(This replaced an earlier "reseat at fill" approach that conflicted with the open-game pre-move — see the design-spec Update note.)* ## Admin replay (`/_gm/games/:id`) - New `game.ReplayTimeline` rebuilds the game from seed+journal, snapshotting racks/scores/turn/bag and the tiles drawn per move. - Server-rendered board + a small vanilla-JS stepper: A–O / 1–15 headers, highlighted premium squares, placed letters with the tile value as a subscript, rack panels (seat 0 top / 1 bottom / 2 left / 3 right) with the current player highlighted, a per-move log with the drawn tiles + bag remainder, and the first-move draw as a flat list. ## Tests - Unit: seeding (ranking, blank-wins, tie chains, rotation, cap), `drawnTiles`/`usedTiles`, `SetupBag`. - Integration: draw recorded + seat 0 = winner (Create); synthetic NULL → back-filled on join (auto-match); `ReplayTimeline` deal+move; the admin page renders the draw + replay sections. Open-match tests reworked for the draw-at-open behaviour. ## Docs ARCHITECTURE §6/§9, FUNCTIONAL (+ _ru), PRERELEASE (FM row), and a design spec under `docs/superpowers/specs/` (say if you'd rather not keep that file).
developer added 1 commit 2026-06-20 06:48:11 +00:00
feat(game): official first-move tile draw + admin step-by-step replay
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 17s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m19s
caefc8f579
Decide who moves first by the official rule: each seated player draws one
tile, the one closest to "A" leads (a blank beats every letter), ties
re-drawing until a single leader remains. Each draw uses honest per-draw
crypto/rand entropy (not the deterministic bag seed), so the recorded draw —
not a seed — is the only account of the outcome. The leader takes seat 0, so
the engine and journal replay are unchanged.

The draw is recorded with the game (game_setup_draws, migration 00013) for
future tournaments, designed as a discrete "player N draws a tile" step.
Friend/AI games draw at creation. Auto-match draws when the game opens,
against a synthetic uuid.Nil opponent whose draw rows (NULL account_id) are
back-filled to the real opponent on join — so the opener's seat is fixed up
front and the existing open-game pre-move is preserved with no reseating.

Admin /_gm/games/:id gains the recorded draw list and a simple step-by-step
board replay (game.ReplayTimeline + a vanilla-JS stepper): a board with
A-O/1-15 headers and highlighted premium squares, placed letters with their
tile value as a subscript, rack panels around the board (seat 0 top, 1
bottom, 2 left, 3 right) with the current player highlighted, and a per-move
log with the tiles drawn and the bag remainder.

Docs: ARCHITECTURE §6/§9, FUNCTIONAL (+_ru), PRERELEASE (FM row), design spec.
owner approved these changes 2026-06-20 08:21:22 +00:00
Dismissed
developer added 1 commit 2026-06-20 08:40:38 +00:00
docs: drop the design-spec artifact (content lives in ARCHITECTURE/FUNCTIONAL/PRERELEASE)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 14s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m2s
e06c6ff67f
owner approved these changes 2026-06-20 08:41:03 +00:00
developer merged commit 1933849dba into development 2026-06-20 08:42:51 +00:00
developer deleted branch feature/first-move-draw 2026-06-20 08:42:51 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#89