feat(robot): shrink endgame think time when both sides pass #86

Merged
developer merged 1 commits from feature/robot-endgame-shrink into development 2026-06-19 14:00:59 +00:00
Owner

What

When the two most recent journal moves are both passes — the board and the robot's rack are frozen, so the robot is bound to pass again — the robot now answers on a shortened schedule instead of waiting out its long late-game think time (up to 90 min), so a decided game is not dragged out.

The shortened delay is a [0.8, 1.5]× band around the human's last-move think time (the gap between the last two journal entries), clamped to [30 s, 8 min] and taken as a min with the normal schedule, so the robot never moves slower than before. A slow human collapses to the 8-min cap; a fast human is tracked, with the floor keeping the robot from passing suspiciously instantly.

Why

In a dead-drawn endgame the next move is a forced pass; the long deliberation only stalls the game.

How

  • Trigger keys on last-two-moves-both-pass (a sound guarantee the robot passes again: selectMove passes only with no legal play and a bag that cannot refill the rack, and both persist once both sides pass) — no bag read, no engine replay.
  • RobotTurns carries new EndgamePass + OppLastMove, filled by one batched game_moves window query on the scan (mirrors analytics.go; reads the journal only, no schema change).
  • maybeMove shrinks the delay via the new deterministic endgamePassDelay. The sleep window is unchanged (honoured upstream in handle).
  • Honest-AI single-game trigger keeps the normal path (it moves at once); NextMoveAt (admin ETA) is left as the normal-schedule upper bound.

Tests

  • Unit: endgamePassDelay bounds/anchor/floor/cap/determinism, and that it is always shorter than the late-game schedule.
  • Integration: RobotTurns reports EndgamePass/OppLastMove for a manufactured two-pass state (and not for a single pass), and the driver acts on the shrunk schedule.
  • Full local gate green: build, vet, gofmt, all backend unit, full integration.

Docs updated in the same PR: ARCHITECTURE.md §7, FUNCTIONAL.md (+ _ru), backend/README.md.

## What When the two most recent journal moves are both passes — the board and the robot's rack are frozen, so the robot is bound to pass again — the robot now answers on a shortened schedule instead of waiting out its long late-game think time (up to 90 min), so a decided game is not dragged out. The shortened delay is a `[0.8, 1.5]×` band around the human's last-move think time (the gap between the last two journal entries), clamped to `[30 s, 8 min]` and taken as a **min** with the normal schedule, so the robot never moves slower than before. A slow human collapses to the 8-min cap; a fast human is tracked, with the floor keeping the robot from passing suspiciously instantly. ## Why In a dead-drawn endgame the next move is a forced pass; the long deliberation only stalls the game. ## How - Trigger keys on **last-two-moves-both-pass** (a sound guarantee the robot passes again: `selectMove` passes only with no legal play and a bag that cannot refill the rack, and both persist once both sides pass) — no bag read, no engine replay. - `RobotTurns` carries new `EndgamePass` + `OppLastMove`, filled by one batched `game_moves` window query on the scan (mirrors `analytics.go`; reads the journal only, **no schema change**). - `maybeMove` shrinks the delay via the new deterministic `endgamePassDelay`. The sleep window is unchanged (honoured upstream in `handle`). - Honest-AI single-game trigger keeps the normal path (it moves at once); `NextMoveAt` (admin ETA) is left as the normal-schedule upper bound. ## Tests - Unit: `endgamePassDelay` bounds/anchor/floor/cap/determinism, and that it is always shorter than the late-game schedule. - Integration: `RobotTurns` reports `EndgamePass`/`OppLastMove` for a manufactured two-pass state (and not for a single pass), and the driver acts on the shrunk schedule. - Full local gate green: build, vet, gofmt, all backend unit, full integration. Docs updated in the same PR: `ARCHITECTURE.md` §7, `FUNCTIONAL.md` (+ `_ru`), `backend/README.md`.
developer added 1 commit 2026-06-19 10:49:01 +00:00
feat(robot): shrink endgame think time when both sides pass
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m17s
f3768d20f2
In a dead-drawn endgame — the two most recent journal moves are both
passes, so the board and the robot's rack are frozen and the robot is
bound to pass again — the robot still waited out its long late-game think
time (up to 90 min) before passing, needlessly dragging out a decided game.

Shorten that delay to a [0.8, 1.5]x band around the human's last-move think
time (the gap between the last two journal entries), clamped to [30s, 8min]
and taken as a min with the normal schedule, so the robot never moves
slower. A slow human collapses to the 8-min cap; a fast human is tracked,
with the floor keeping the robot from passing suspiciously instantly. The
anchor reads the move journal only (no schema change), stays deterministic
from the seed, and still defers to the sleep window.

RobotTurns now carries EndgamePass + OppLastMove, filled by one batched
journal query on the scan; the honest-AI single-game trigger keeps the
normal path (it moves at once). NextMoveAt (admin ETA) is left as the
normal-schedule upper bound.
owner approved these changes 2026-06-19 14:00:30 +00:00
developer merged commit c67a5d51f1 into development 2026-06-19 14:00:59 +00:00
developer deleted branch feature/robot-endgame-shrink 2026-06-19 14:00:59 +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#86