From 72148dd7c2e7249a90dd5e31e1e1d48339be658e Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Wed, 26 Aug 2026 14:00:30 -0400 Subject: [PATCH] A missing room must not burn the seat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client deleted its saved seat credentials on "no such room" — but that error proves nothing about the seat: a restarting server, a stale restore, or a wrong backend all say it, and burning the token on a transient locked a live player out of a live game (room 22EC, after this session's server-squatting incident). Now only "name is taken" — this exact token tried and refused — clears the credential; a not-found shows its error and keeps the key for the reconnect that finds the room home again. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF --- packages/web/src/net.svelte.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/web/src/net.svelte.ts b/packages/web/src/net.svelte.ts index 1121c72..cd6cb30 100644 --- a/packages/web/src/net.svelte.ts +++ b/packages/web/src/net.svelte.ts @@ -507,8 +507,17 @@ class Net { break; } case "error": - if (this.roomIdPending && /no such room|name is taken/.test(msg.message)) { + // "Name is taken" means THIS token was tried and refused: the + // credential itself is dead, and holding it helps nobody. But + // "no such room" proves nothing about the seat — a restarting + // server, a stale restore, or the wrong backend all say it — + // and burning credentials on a transient locked a real player + // out of a live game. The seat stays; the error shows; a later + // reconnect against the right server walks back in. + if (this.roomIdPending && /name is taken/.test(msg.message)) { localStorage.removeItem(SEAT_KEY); + } + if (this.roomIdPending && /no such room|name is taken/.test(msg.message)) { this.roomIdPending = null; } this.error = msg.message;