feat(ui): merge Exchange/Pass into one action; drop dead Tournaments tab #52

Merged
developer merged 1 commits from feature/ui-merge-exchange-pass into development 2026-06-13 19:58:37 +00:00
Owner

What

  • Lobby: remove the inert 🏆 Tournaments tab (it only raised a "coming soon" toast). The lobby is back to three tabs, matching docs/FUNCTIONAL.md.
  • Game: fold the separate 🥺 Skip (pass) tab into the 🔄 tab, now Exchange/Pass. The dialog passes when no tile is selected (button Pass without exchanging) and exchanges when tiles are (Exchange N).

Why a pass is NOT an exchange of zero (verified against the rules + GCG)

The merge is UI-only — pass and exchange stay distinct game actions end-to-end:

  • Rules / engine: an exchange is legal only with a full rack still in the bag (ErrNotEnoughTilesToExchange) and a zero-tile swap is forbidden (ErrNothingToExchange); a pass is always legal.
  • GCG (Poslfit dialect): a pass is a bare -, an exchange is -TILES — collapsing them would lose a real distinction at replay.

So the tab is no longer gated on an empty bag (a pass must stay reachable in the endgame); inside the dialog, tile selection is disabled while the bag is below a full rack (bagLen >= RACK_SIZE). The dialog dispatches the existing gateway.pass / gateway.exchange. No backend / wire / history / GCG change.

Verification

UI check (0 errors), unit (164), build, and e2e on Chromium + WebKit (108) — all green locally.

Docs

docs/UI_DESIGN.md, docs/FUNCTIONAL.md (+ _ru), and an ad-hoc UI entry in PRERELEASE.md recording the decision.

## What - **Lobby:** remove the inert 🏆 *Tournaments* tab (it only raised a "coming soon" toast). The lobby is back to three tabs, matching `docs/FUNCTIONAL.md`. - **Game:** fold the separate 🥺 *Skip* (pass) tab into the 🔄 tab, now **Exchange/Pass**. The dialog **passes** when no tile is selected (button *Pass without exchanging*) and **exchanges** when tiles are (*Exchange N*). ## Why a pass is NOT an exchange of zero (verified against the rules + GCG) The merge is **UI-only** — pass and exchange stay distinct game actions end-to-end: - **Rules / engine:** an exchange is legal only with a full rack still in the bag (`ErrNotEnoughTilesToExchange`) and a zero-tile swap is forbidden (`ErrNothingToExchange`); a pass is always legal. - **GCG (Poslfit dialect):** a pass is a bare `-`, an exchange is `-TILES` — collapsing them would lose a real distinction at replay. So the tab is no longer gated on an empty bag (a pass must stay reachable in the endgame); inside the dialog, tile selection is disabled while the bag is below a full rack (`bagLen >= RACK_SIZE`). The dialog dispatches the existing `gateway.pass` / `gateway.exchange`. **No backend / wire / history / GCG change.** ## Verification UI `check` (0 errors), unit (164), build, and e2e on Chromium + WebKit (108) — all green locally. ## Docs `docs/UI_DESIGN.md`, `docs/FUNCTIONAL.md` (+ `_ru`), and an ad-hoc UI entry in `PRERELEASE.md` recording the decision.
developer added 1 commit 2026-06-13 14:42:58 +00:00
feat(ui): merge Exchange/Pass into one action; drop dead Tournaments tab
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 47s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m0s
a4e6727c70
Lobby: remove the inert 🏆 Tournaments tab (it only raised a 'coming soon' toast); the lobby is back to three tabs, matching docs/FUNCTIONAL.md.

Game: fold the separate 🥺 Skip (pass) tab into the 🔄 tab, now Exchange/Pass. Its dialog passes when no tile is selected (button 'Pass without exchanging') and exchanges when tiles are ('Exchange N'). The tab is no longer gated on an empty bag (pass must stay reachable in the endgame); inside the dialog tile selection is disabled while the bag is below a full rack (bagLen >= RACK_SIZE).

The merge is UI-only. A pass is NOT an exchange of zero tiles: the rules allow an exchange only with a full rack left in the bag and forbid a zero-tile swap, while a pass is always legal; GCG (Poslfit) writes a pass as a bare '-' and an exchange as '-TILES'. Pass and exchange stay distinct end-to-end (wire, engine, history/GCG); the dialog dispatches the existing gateway.pass / gateway.exchange. No backend/wire/history/GCG change.

Docs: docs/UI_DESIGN.md, docs/FUNCTIONAL.md (+_ru), PRERELEASE.md. Tests: ui/e2e/game.spec.ts.
owner approved these changes 2026-06-13 19:56:44 +00:00
developer merged commit 5ff07da025 into development 2026-06-13 19:58:37 +00:00
developer deleted branch feature/ui-merge-exchange-pass 2026-06-13 19:58:37 +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#52