Verified findings from a code audit and fixed the legitimate, well-scoped
ones. Notable: crashed cluster workers were never respawned because
worker.process.env is undefined in the exit handler, so WORKER_ID was always
undefined (confirmed empirically).
Fixes:
- Master: respawn crashed workers via a worker.id -> WORKER_ID registry
instead of the always-undefined worker.process.env.WORKER_ID.
- GameServer: report Finished when _hasEnded so abandoned private lobbies are
cleaned up instead of lingering until max duration; remove sockets from the
websockets Set on close/rejoin; reset hasReachedMaxPlayerCount when a player
leaves before start (avoids premature under-capacity starts, e.g. ranked 1v1).
- Worker: reap WebSocket connections that upgrade but never authenticate
(30s join timeout) to prevent Slowloris-style FD exhaustion.
- ServerEnv: add a 1h TTL to the cached JWKS public key so IdP key rotation
doesn't break all logins until a restart.
- SpawnExecution: ignore a client-supplied tile in random-spawn mode so a
forged spawn intent can't pick its own coordinates (+ test).
- GameRenderer / MultiTabDetector: remove window listeners on teardown
(bind once so add/removeEventListener references match).
- LocalPersistantStats: guard localStorage access with try/catch so sandboxed
iframes / disabled-storage contexts don't crash game start.
- StructurePass: reuse per-frame uniform arrays instead of allocating each draw.
Also documents a known, intentionally-unfixed auth gap on
/api/archive_singleplayer_game (pending a product decision on logged-out users).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>