Report
React 18 strict mode mounts → unmounts → remounts every component in dev. If the root client component opens a WebSocket on mount, the second mount opens a *second* WS to the server. The server (shared-world game, presence, chat) sees two clients for one user, the player gets a ghost twin, presence breaks, snapshot fanout double-counts. Standard strict-mode advice (track an abort flag, dedupe by key) doesn't fit because the server handshake is *stateful and intentionally non-idempotent* — auth, session row, world join — and "remount-safe" isn't a meaningful state for it.
a3a232b4-1334-48cb-959f-cd015d426a4e
React 18 strict mode mounts → unmounts → remounts every component in dev. If the root client component opens a WebSocket on mount, the second mount opens a second WS to the server. The server (shared-world game, presence, chat) sees two clients for one user, the player gets a ghost twin, presence breaks, snapshot fanout double-counts. Standard strict-mode advice (track an abort flag, dedupe by key) doesn't fit because the server handshake is stateful and intentionally non-idempotent — auth, session row, world join — and "remount-safe" isn't a meaningful state for it.