# Changelog — Шашки Рояль

## 2026-05-21 — v1.1.0 "Production-ready multi-capture"

### 🔴 P0 — Critical fix: Multi-capture (двойное/мультивзятие) UI block
**Bug**: The UI exposed only the FINAL destination of a chain capture as a single
click target. Players couldn't continue the chain because the intermediate
hop wasn't actionable.

**Fix**: Step-by-step capture chains.
- `game/rules.ts` — added `toSingleHopMoves()` helper that converts multi-step
  chain `Move` objects into UI-displayable single-hop Moves.
- `game/gameLogic.ts` — refactored `applyMoveToState()` to apply ONE hop at a
  time, detect continuation captures via `getContinuationCaptures()`, and set
  `captureChain` state when more captures are available (turn does NOT flip).
  When chain completes (no more captures OR promotion), turn flips.
- `game/types.ts` — `captureChain` type is now an object: `{ pieceRow, pieceCol,
  startRow, startCol, alreadyCaptured }`.
- `pages/LocalGame.tsx` & `pages/OnlineGame.tsx` — `handleCellClick` respects
  `captureChain` lock (cannot deselect or select another piece mid-chain).
- `pages/OnlineGame.tsx` — defers Supabase sync until the chain completes.
- **Tests**: 4 new vitest cases in `game/__tests__/gameLogic.test.ts` covering
  step-by-step double captures, mid-chain piece-lock, and promotion-terminated
  chains. All 27 existing `rules.test.ts` tests still pass (59 total).

### 🟠 P1 — UI cleanup
- **Removed "Срубл." (captured count)** from `components/PlayerCard.tsx` and
  both player chips in `pages/LocalGame.tsx`.
- **Removed "Рейтинг: X" text** from `PlayerCard.tsx` and stake-lobby cards.
  Subtitle now shows color label "Белые"/"Чёрные".

### 🟠 P1 — Auto-guest profile naming
- `services/profiles.ts` — new `generateGuestNickname(playerId)` produces a
  stable 4-digit "Player NNNN" name from a hash of the playerId. Same device =
  same name forever. `getOrCreateProfile()` injects it on profile creation and
  auto-renames legacy "Player"/"Игрок" plain defaults.
- 4 new vitest cases in `services/__tests__/profiles.test.ts`.

### 🟠 P1 — Custom stake input
- `pages/StakeLobbyPage.tsx → CreateTableModal`:
  - Kept the 6 quick buttons 1/2/5/10/25/50 Coin (testids
    `stake-quick-{fee}`).
  - Added "Своя ставка" numeric input (`data-testid="stake-custom-input"`),
    digits-only, min=1, max=available balance, integers only.
  - Breakdown panel (`stake-breakdown`) shows 4 lines: Ставка, Банк (×2),
    Комиссия 5% (−amount), Победитель получит.
- `services/stakes.ts` — relaxed cap from 1000 → 1_000_000; enforces integer.

### 🟠 P1 — Turn-status indicators
- LocalGame: banner shows `Ход белых` / `Ход чёрных` / `Взятие обязательно!`.
- OnlineGame: banner shows `Ваш ход` / `Ход соперника` / `Взятие обязательно!`
  / `Отправка хода...`.
- (Both already existed; verified still working with the new chain logic.)

### Removed dead code
- `services/profiles.ts` — duplicate `createStakeGame`/`joinStakeGame`/
  `fetchStakeTables` functions with stale validation removed (the active
  versions live in `services/stakes.ts`).

### Build / Release
- Production build OK (614 kB main bundle / 178 kB gzipped).
- TypeScript strict-mode clean.
- ESLint clean across all 9 modified files.
- Android debug APK rebuilt with the new bundled web assets:
  `/app/shashki-royale-v1.1.0-debug.apk` (17 MB).
- Version bumped to `v1.1.0 · build 20260521 · Coin v2`.

### Testing
- vitest: 4 files, 59 tests, all passing.
- testing_agent_v3_fork iteration_5: all structural checks ✅,
  multi-capture verified.
- Playwright smoke: home + /local + /stake-lobby load cleanly, no "Срубл."
  or "Рейтинг:" text present, modal renders all 4 breakdown lines, custom
  input strips non-digits.
