Skip to content

games_hub: chess, first variant king and pawn against king - #1620

Merged
aaylward merged 5 commits into
mainfrom
claude/chess-kpk
Sep 30, 2026
Merged

aaylward merged 5 commits into
mainfrom
claude/chess-kpk

Conversation

@aaylward

@aaylward aaylward commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Adds chess as a game in games_hub, with one variant so far: king and pawn against king (kpk), starting from a random position.

  • Rules engine (libs/chess_play): the start position plus the moves played, in UCI, over the vendored chess-library.
    • Mate, stalemate, insufficient material, the 50-move rule and threefold repetition all end the game automatically, with no claim needed.
    • Resignation ends it, and so does a player leaving (the leaver loses, and is credited a game played and not won).
  • Clock: Fischer increment, running from the start of the game. A player who runs out of time loses, unless the opponent has only a bare king, in which case it's a draw.
    • A move that arrives after the mover's time ran out isn't played; the game ends on time instead. A leave after that point also ends on time.
    • A move's time is read under the hub lock, and no turn starts before the one it follows.
  • Wire (model/chess.smithy): a chess envelope on the Play stream.
    • startGame sets the clock in seconds (30–1800 per side, 0–30 increment, default 3+2).
    • The view lists every legal move, so the client needs no chess rules of its own.
  • Hub (golf_hub):
    • Chess tables seat 2.
    • SweepChessClocksOnce runs every 250 ms on each instance and ends games whose clock has run out. It goes through the same conditional commit as a move, so when several instances hold the room only one flag lands.
    • The sweep takes the lock once per game. If the store refuses a flag as unavailable, that game waits kChessFlagRetry (5 s) before the next attempt, so a database outage can't stall the hub on every tick.
    • SetClock and SetChessOpener let tests fix the time and the start position.
  • Other places that list game names: chess is added to the prom_proxy tiles, the stats variant list and deja's VARIANTS.

What a reviewer won't see from the diff:

  • TableEngineMove's commit loop is now ApplyTableEngineMoveLocked, so the sweep can reuse it without sending a rejection to a player who sent nothing. Castle and rummy go through it unchanged.
  • bazel/3p/chess_library visibility now includes chess_play, whose headers expose no chess-library types.
  • The stored row holds wall-clock epoch ms, so instances must agree on the time (NTP).

Tests:

  • Engine and serde.
  • A chess e2e suite with a fixed clock and start position. It covers every ending, the sweep, the clock thread, store-outage backoff, stats after a draw and after a leave, and the event-log lines.
  • A raw-JSON wire test, which pins the decoder's bound refusals on a full table.
  • The counter-vs-model pin.
  • Postgres row and jsonb tests, plus a two-instance sweep that ends the game once.
  • Go and Rust vocabulary tests.

Local runs:

  • Every affected suite passed, including the Postgres-gated ones against a local PG 16 (they ran, not skipped).
  • The chess e2e suite passed 15 runs.
  • Hub and engine behaviors were mutation-checked.

Review panel: four read-only agents covering correctness, concurrency/storage, tests/docs, and altitude. Their fixes are in b1d0fc4.

Follow-ups:

Not covered here:

  • Draw offers.
  • Lag compensation.

UI: muchq/muchq.github.io#394.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
iili 01d7d0c Commit Preview URL

Branch Preview URL
Sep 30 2026, 08:29 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ast-lol 01d7d0c Commit Preview URL

Branch Preview URL
Sep 30 2026, 08:29 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
1d4-web 01d7d0c Commit Preview URL

Branch Preview URL
Sep 30 2026, 08:28 PM

@cursor

cursor Bot commented Sep 30, 2026

Copy link
Copy Markdown

Review panel — #1620 @ b1d0fc4c

Four lenses + Bugbot on the chess/kpk tip (incl. prior panel fold-ins). CI green. Bugbot clean. Altitude: kpk-first, legalMoves as accept-set, 250 ms sweep, and ApplyTableEngineMoveLocked are the right shapes. Clock/flag/leave/sweep races from the earlier panel look held.

Requested fold-ins

  1. resign ignores an already-fallen flag — move and removePlayer both end on time first when remainingMs(side_to_move) == 0; resign does not. In the sweep gap, a flagged pawn side can resign into a loss and erase the bare-king timeout draw; the waiting side can resign into a loss instead of the flag win/draw. Mirror ALeaveAfterTheFlagIsTheFlag for resign. (line comment)

  2. chess_flag_retry_at_ not erased when the game is already over — after an unavailable sets a key, a later ending elsewhere makes the scan hit isOver and continue without erase (:2818), and the re-lock path does the same (:2844). Small entries, but they live for the process. Erase on isOver in both places. (line comment)

  3. restore accepts any player-ending Result on an open board — board endings are checked; resignation / timeout / abandoned are not. A hostile row can invent a timeout winner for the side that flagged, or a bare-king timeout win instead of a draw. Serde’s own contract says DB bytes are untrusted; the open-board resignation restore test currently pins the hole. At least refuse a timeout whose winner/nullopt disagrees with timeoutResult() at the stored clock, and refuse a resignation whose winner is the resigner. (optional harden; top-level)

Mild / optional

  • README Observability still lists golf_* / castle_* / rummy_* / … without chess_* (hub emits chess_commands / chess_events; not in an active diff hunk for that bullet).
  • Board-automatic ending spellings (stalemate / insufficientMaterial / fiftyMoves / repetition) are never string-pinned — only enums / player endings. A rename in EndingName keeps engine CI green and drifts wire + smithy together.
  • Draw offers / lag are named “Not covered” with no durable follow-up (bots have #1618). File one ordered issue if you want the deferrals to survive the squash; for kpk, draw offers outrank lag.

Checked and not raised

Fischer increment, move-after-expiry, bare-king timeout draw, leave-after-flag, sweep vs move conditional commit / two-instance pin, NowMs under lock, turn_started skew clamp, unavailable backoff, castle/rummy through ApplyTableEngineMoveLocked, BUILD srcs, clock bounds wire goldens, stats/prom_proxy/deja/otel pins.

Comment thread domains/games/libs/chess_play/game_state.cc
Comment thread domains/games/apis/games_hub/golf_hub.cc Outdated

Copy link
Copy Markdown
Collaborator Author

Addressed in 024443f:

  • Resign after the flag, and the retry-map leak: fixed; see the replies on the line comments.
  • Timeout in a stored row: restore now refuses a timeout the stored clock contradicts: time still left on the side to move, or a result other than the one a flag gives (RestoreRefusesATimeoutTheClockContradicts). The resignation half can't be checked, because the row doesn't record who resigned, and either color can win by resignation. That stays accepted.
  • README: Observability now lists chess_*.
  • Ending spellings: all eight are pinned both ways (EveryEndingIsSpelledAsTheWireSaysIt).
  • Draw offers and lag: filed as games_hub chess: draw offers, then lag compensation #1622, in that order.

Generated by Claude Code

@cursor

cursor Bot commented Sep 30, 2026

Copy link
Copy Markdown

Recheck @ 024443f: panel items closed.

  • Resign after flag → timeout first; AResignationAfterTheFlagIsTheFlag pins both seats + control.
  • Flag-retry map: erase on isOver at re-lock, plus per-sweep erase_if for gone/over games; AGameThatEndsWhileItsFlagWaitsLeavesNoRetryBehind.
  • restore refuses a timeout the clock contradicts; resignation left open (no resigner on the row) — agreed.
  • README Observability lists chess_*; all eight EndingName spellings pinned both ways; draw offers / lag filed as games_hub chess: draw offers, then lag compensation #1622.

Nothing further from the panel. Watching CI on this tip.

@github-actions github-actions Bot added the service:unknown Impacted services could not be computed label Sep 30, 2026
@cursor

cursor Bot commented Sep 30, 2026

Copy link
Copy Markdown

Recheck @ 01d7d0c5: leaver stats credit both seats from state.players() (chess keeps them; no engine compact), so the leaver gets played+loss and the stayer the win. ALeaverLosesByAbandonment pins (1,0) / (1,1). Matches the README. No new panel findings.

@aaylward
aaylward merged commit 90c7ad6 into main Sep 30, 2026
24 checks passed
@aaylward
aaylward deleted the claude/chess-kpk branch September 30, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

service:deja Changes the deja image service:games_hub Changes the games_hub image service:prom_proxy Changes the prom_proxy image service:stats Changes the stats image service:unknown Impacted services could not be computed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants