Repository navigation
Online liveness: in-game disconnect grace, occupancy refresh, client ping - #23
Merged
Merged
Conversation
rotundtapir
force-pushed
the
feat/game-disconnect-grace
branch
from
August 22, 2026 11:38
87fbcd3 to
78fafa0
Compare
…ping Three fixes from cross-client field reports (Jack, flipping between the Android app and the web client mid-game): 1. An app-switch away long enough to drop the socket handed the seat to the bot INSTANTLY — the lobby has a 15-minute grace, the game had none, and substituteBot even wakes the parked turn. New gameDisconnectGraceMillis (default 3 min, GAME_GRACE_MILLIS env, 0 = old behaviour): the seat parks (SeatHost.awaitingReclaim — decide() waits rather than bot-falling-back while it's set), a reconnect inside the grace resumes as if nothing happened, expiry substitutes as before. A per-slot grace generation stops a stale timer from an earlier drop cutting a newer grace short. No status broadcast during the grace; the protocol is untouched. 2. A reclaimed player stayed '(bot)' on another client's screen forever: SeatStatus is a transient broadcast, so a client disconnected at announcement time resumes with a stale occupancy picture and nothing corrected it. onReconnect now refreshes the reconnector with every other human-owned seat's current status (refreshOccupancy). 3. The JVM/Android client had no WebSocket ping, so a socket Android killed in the background was undetectable — the receive loop waited on the zombie indefinitely and the app 'took a long time to receive moves' after foregrounding. CIO now pings every 20s, bounding dead- socket detection to ~two intervals. (The browser engine has no frame-ping API; tabs rely on the browser plus the client-side foreground nudge landing in 500.) Tests: grace holds the seat and reclaim resumes it; expiry hands to the bot; a reconnector receives the occupancy it missed. Fixture pins grace 0 so existing instant-substitution coverage keeps testing that branch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BiTsrURfRLtBDgyyt5s16K Signed-off-by: rotund_tapir <rotund_tapir@protonmail.com>
rotundtapir
force-pushed
the
feat/game-disconnect-grace
branch
from
August 22, 2026 11:38
78fafa0 to
ebaeb02
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three fixes from Jack's cross-client field reports:
gameDisconnectGraceMillis, default 3 min,GAME_GRACE_MILLISenv, 0 = today's instant substitution): the seat parks (SeatHost.awaitingReclaim) instead of botting on socket drop, reclaim inside the grace resumes seamlessly, expiry substitutes as before. Per-slot grace generation defeats stale timers from earlier drops. Protocol untouched.SeatStatusis transient, so a client disconnected at announcement time resumed with a stale picture (a reclaimed player showing "(bot)" forever).onReconnectnow sends the reconnector every other human seat's current status.Three new RoomTest cases; full
./gradlew buildgreen incl. detekt. Client-side follow-up (foreground nudge + backoff reset) lands in 500.🤖 Generated with Claude Code
https://claude.ai/code/session_01BiTsrURfRLtBDgyyt5s16K