Skip to content

Keep shared membership per client session and add helpers.ensureJoined - #1856

Merged
Noisemaker111 merged 1 commit into
mainfrom
claude/host-command-membership
Sep 25, 2026
Merged

Noisemaker111 merged 1 commit into
mainfrom
claude/host-command-membership

Conversation

@Noisemaker111

Copy link
Copy Markdown
Owner

An LLMville player reported "it says I can place, but it fails". Shared-world membership is stored per user, but clients join and leave per session. Closing a second tab, or a join that resolves after a remount (StrictMode, quick route changes), evicted the user while the open tab still showed "joined". Every host mutation then failed with "Not a member of this server".

  • The core transport's joinServer/leaveServer take an optional sessionId, and createTransportSessionId() generates one.
  • Convex shared topology:
    • Each member row keeps up to 16 live sessionIds.
    • A session leave removes only its own id, and the full leave runs only when the last id goes.
    • A leave for an id that isn't live does nothing.
    • A leave with no id, and legacy rows, behave as before.
  • helpers.ensureJoined(ctx, { gameId, userId, serverId? }) runs the join path for an actor host code has already authorized. With serverId set and the user already a member, it returns without extra work. runCommand docs now point to it.
  • useServerSession, the Convex transport's pagehide leave, and the shell sync each pass one id per session.
  • ws: join and leave messages carry sessionId. A user is only removed when no other connection of theirs still holds the server.
  • The jgengine-multiplayer skill covers sessions and ensureJoined.

Bugfix notes

  • Root cause: membership was per user while join and leave were per session.
  • Any game on the shared Convex topology, or on ws with singleSession: false, can hit this.
  • Still open: rooms topology still leaves per user. Fixing it needs a new field on jgGameServers.

Verification

  • bun test packages/convex packages/core/src/runtime packages/react packages/ws packages/shell: 1355 pass, 0 fail.
  • New tests cover two sessions, stale leaves, legacy rows, the 16-id bound, ensureJoined idempotence, the pagehide transport, and ws multi-connection.
  • check-types for core, convex, react, ws and shell: pass.
  • bun run gen: done; ship:preflight: ok.
  • There's no rendered surface to screenshot.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GvRbbu8yG1WYz7wQnZUpC8


Generated by Claude Code

joinServer/leaveServer take an optional sessionId; a member leaves only
when its last live session does. ensureJoined lets host mutations join a
trusted actor before helpers.runCommand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GvRbbu8yG1WYz7wQnZUpC8
@Noisemaker111
Noisemaker111 enabled auto-merge (squash) September 25, 2026 20:45
@Noisemaker111
Noisemaker111 merged commit c4f979f into main Sep 25, 2026
6 checks passed
@Noisemaker111
Noisemaker111 deleted the claude/host-command-membership branch September 25, 2026 20:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants