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

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.
This commit is contained in:
Ilia Denisov
2026-06-19 12:48:39 +02:00
parent 0eb1e0ef47
commit f3768d20f2
10 changed files with 342 additions and 7 deletions
+11 -1
View File
@@ -449,11 +449,21 @@ disguised robot stays indistinguishable from a person.
band; it proactively nudges the idle human on a **lengthening, randomized schedule** — the
first ~60-90 min into the turn, each later reminder spaced further out toward 1-6 h — so a long
wait gets a handful of increasingly-spaced nudges rather than an hourly stream.
- **Dead-endgame timing**: once the **two most recent moves are both passes**, the board and the
robot's rack are frozen and it is bound to pass again, so the robot drops the long late-game
think time and answers on a **shortened schedule scaled to the human's own last (pass) think
time** — a uniform sample in **[0.8, 1.5]×** of it, clamped to **[30 s, 8 min]** and taken as a
**min** with the normal delay, so it never slows down. A slow human collapses to the 8-min cap (a
decided game is not dragged out); a fast human is tracked, with the floor keeping the robot from
passing suspiciously instantly. The anchor (the gap between the last two journal entries) reads the
move journal only — no schema change — stays deterministic from the seed, and still defers to the
sleep window.
- **Observability**: robot accounts accrue ordinary statistics (§9) — the
authoritative balance metric (target ≈ 40% robot wins) — and a
`robot_games_finished_total` OTel counter plus a per-finish log give a live view.
The **admin game card** surfaces each robot seat's per-game play-to-win intent (from
the seed) and, on the robot's turn, its deterministic **next-move ETA**.
the seed) and, on the robot's turn, its deterministic **next-move ETA** (the normal-schedule
upper bound — a dead-endgame pass may land sooner).
## 8. Lobby & social
+3 -1
View File
@@ -158,7 +158,9 @@ wins most games), aims for a close score rather than crushing or throwing the ga
now and then plays a single move against that plan — a surprise lead or a slack move —
yet holds to the plan once the bag empties, and plays at a human pace — short thinking
times for most moves, the occasional long one, and a night-time pause that tracks the
player's own day. It answers a nudge
player's own day; once a game is clearly decided and both sides are only passing, it stops
dragging it out, answering its forced passes at roughly the player's own pace rather than
after a long deliberation. It answers a nudge
within a few minutes and nudges back when the player has been away a long time. It
carries a human-like, language-appropriate name — a fresh one each game, drawn from a wide
international pool of real names and handles, so the arena feels populated by many different
+3 -1
View File
@@ -164,7 +164,9 @@ nudge) приходят от бота **этой партии** — по язы
поддавки, время от времени делает один ход вопреки этому плану — неожиданный отрыв или
слабый ход, — но к концу партии (когда мешок пуст) держится плана, и ходит с
человеческим темпом — чаще короткие раздумья, изредка долгие, и ночная пауза,
подстроенная под день игрока. На nudge отвечает за несколько минут и
подстроенная под день игрока; когда партия уже явно решена и обе стороны только пасуют,
он перестаёт её затягивать — отвечает на вынужденные пасы примерно в темпе самого игрока,
а не после долгого раздумья. На nudge отвечает за несколько минут и
сам шлёт nudge, когда игрок надолго пропал. Носит человекоподобное имя, подходящее
языку партии — каждую партию новое, из широкого международного пула реальных имён и
никнеймов, так что арена кажется полной разных игроков (в русской партии — в основном