Skip to content

MULTIPLAYER: resume server-hosted rooms after reload#5359

Merged
matthewevans merged 4 commits into
phase-rs:mainfrom
davidomil:fix/selfhost-host-reconnect
Jul 9, 2026
Merged

MULTIPLAYER: resume server-hosted rooms after reload#5359
matthewevans merged 4 commits into
phase-rs:mainfrom
davidomil:fix/selfhost-host-reconnect

Conversation

@davidomil

@davidomil davidomil commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Restores server-hosted pregame rooms after a browser reload by persisting host-session metadata with the WebSocket reconnect token. Also moves LAN HTTP crypto.randomUUID() support into client source and fixes the join flow so connection-scoped seat reservation tokens are not carried from a lobby lookup socket into a later game join socket.

Behavioral note

The reservation issue is easiest to hit on Full-mode servers. The official multiplayer deployment currently behaves as a LobbyOnly broker, so the pre-fix P2P join path resolved the guest over the same long-lived lobby socket that created the reservation. Full-mode self-hosted servers run the actual game on the server, so deck selection previously reserved a seat on the lobby socket, then the game route opened a new WebSocket and tried to use that token there. The server correctly rejected that as a foreign reservation.

Seat reservations are intentionally bound to the WebSocket connection that received them. This PR keeps the deck-selection lookup read-only and clears stale reservation handoff storage before opening the game WebSocket.

Implementation method (required)

How was the engine/parser logic in this PR produced? Check exactly one:

  • Produced via the /engine-implementer pipeline (plan → review-plan → implement → review-impl → commit)
  • Not /engine-implementer — explain why below

If you did not use /engine-implementer, state why (e.g. frontend-only
change, docs/CI/tooling change, release chore, or a fix too small to warrant
the pipeline):

Frontend/client-only multiplayer persistence, browser runtime, and join-flow fixes. This does not change crates/engine/ parser, effects, resolver, targeting, or rules behavior.

Note

Any change to crates/engine/ game logic — parser, effects, resolver,
targeting, rules behavior — is expected to go through /engine-implementer.
The "not used" box is for changes that genuinely fall outside that scope.

CR references

None.

Verification

  • ./node_modules/.bin/vitest run src/services/__tests__/multiplayerSession.test.ts src/polyfills/__tests__/cryptoRandomUUID.test.ts src/stores/__tests__/multiplayerStore.test.ts — passed, 25 tests.
  • ./node_modules/.bin/vitest run src/services/__tests__/brokerClient.test.ts src/stores/__tests__/multiplayerStore.test.ts src/services/__tests__/multiplayerSession.test.ts src/polyfills/__tests__/cryptoRandomUUID.test.ts — passed, 34 tests.
  • node ../scripts/check-protocol-version.mjs && ./node_modules/.bin/tsc -b --noEmit — passed.
  • ./node_modules/.bin/eslint src/pages/MultiplayerPage.tsx src/providers/GameProvider.tsx src/stores/multiplayerStore.ts src/services/__tests__/brokerClient.test.ts — passed.
  • cargo test -p lobby-broker foreign_ — passed, 2 tests.
  • Live ServerHello comparison confirmed the official multiplayer deployment is LobbyOnly while the affected self-hosted deployment was Full mode.
  • Self-hosted Full-mode deploy from a56056306301f60a2f53cbb078d513ac7ec41378 verified the expected build commit, protocol version, and Full mode in ServerHello.
  • Served bundle check in the self-hosted deployment confirmed join lookup calls the store without reservation options, and the online join path clears stale phase-join-reservation:* storage before navigation.
  • Post-deploy server log check found no You may only release or use a seat reservation issued to this connection errors after the fix.
  • Manual self-hosted Full-mode verification: a host room survived browser reload and a guest could join afterward.

@davidomil davidomil requested a review from matthewevans as a code owner July 8, 2026 04:52
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@davidomil davidomil marked this pull request as draft July 8, 2026 04:57
@davidomil davidomil force-pushed the fix/selfhost-host-reconnect branch from 91b03a4 to d56eaaf Compare July 8, 2026 04:57
@davidomil davidomil marked this pull request as ready for review July 8, 2026 04:58
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@davidomil davidomil marked this pull request as draft July 8, 2026 04:58
@matthewevans matthewevans added the defer-fe Frontend/client/UI PR deferred to Matt's direct review label Jul 8, 2026
@davidomil davidomil marked this pull request as ready for review July 8, 2026 05:54
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@davidomil davidomil force-pushed the fix/selfhost-host-reconnect branch from a560563 to 2247739 Compare July 9, 2026 00:27
@matthewevans

Copy link
Copy Markdown
Member

@davidomil is this something you had an opportunity to test?

@davidomil

Copy link
Copy Markdown
Contributor Author

Yes. Works on my local host. What I do is I have http reverse proxy with basic auth that goes into cloud flare zero trust tunnel. These changes were required for it to work reliably.

@matthewevans matthewevans added this pull request to the merge queue Jul 9, 2026
Merged via the queue into phase-rs:main with commit 4d5db0a Jul 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

defer-fe Frontend/client/UI PR deferred to Matt's direct review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants