| name | multiplayer-readiness |
| description | Audit SpawnForge code for changes that block future multiplayer networking. Use when modifying state management, entity systems, or the command pipeline — flags non-deterministic state, client-authoritative patterns, and unsyncable mutations. |
| user-invocable | true |
| allowed-tools | Read, Glob, Grep, Agent |
| argument-hint | [scope: pr|file <path>|store|commands|all] |
Multiplayer Readiness Reviewer
SpawnForge's multiplayer networking (Phase 25) was removed because no networking backend existed. It WILL be rebuilt. Every design decision today either makes that easier or harder.
Context
Multiplayer in a browser-based game engine means:
- Authoritative server or relay-based P2P — likely the former for anti-cheat
- State synchronization — entity transforms, components, and scene graph must replicate
- Command replication —
handle_command() JSON commands are the natural sync boundary
- Conflict resolution — two users editing the same entity simultaneously
- Bandwidth constraints — browser WebSocket/WebRTC, not TCP sockets
Red Flags to Check
When reviewing code changes, flag any of these patterns:
1. Global Mutable Singletons
Problem: Singletons can't distinguish between local and remote state.
grep -rn "thread_local!\|static mut\|lazy_static!\|OnceCell" engine/src/ --include="*.rs"
grep -rn "getState()\." web/src/stores/ --include="*.ts" | grep -v "test" | head -20
Multiplayer-safe alternative: All mutable state in ECS resources or Zustand slices with clear ownership semantics.
2. Implicit Local-Only Assumptions
Problem: Code that assumes a single user is editing.
grep -rn "selectedIds\|primary_id\|SelectionChanged" engine/src/ web/src/stores/ | head -20
grep -rn "UndoableAction\|HistoryStack" engine/src/ | head -10
Flags:
- Selection stored as a single global set (should be per-user/per-session)
- Undo history as a single stack (should be per-user)
- Camera state as singleton (should be per-viewport)
3. Non-Deterministic Command Handling
Problem: Commands that produce different results on different clients.
grep -rn "rand::\|thread_rng\|random()" engine/src/core/commands/ | head -10
grep -rn "Instant::now\|SystemTime\|elapsed" engine/src/core/commands/ | head -10
Multiplayer-safe: Commands must be deterministic given the same state + input. Randomness should use seeded RNG with seed in the command payload.
4. Direct State Mutation Bypassing Commands
Problem: State changes that can't be replicated because they don't go through the command pipeline.
grep -rn "\.insert(\|\.remove::<\|commands\.entity" engine/src/bridge/ | grep -v "// safe:" | head -20
Multiplayer-safe: ALL state mutations go through handle_command() → dispatch() chain. Bridge systems should only READ state and emit events.
5. Large State in Commands
Problem: Commands that embed full scene snapshots or large binary data.
grep -rn "serde_json::to_string\|JSON.stringify" engine/src/core/commands/ web/src/stores/slices/ | head -15
Multiplayer-safe: Commands should be delta-based (change X by Y) not absolute (set X to full-snapshot). Export/import can remain absolute.
6. Client-Side Authority Over Game State
Problem: Game logic running exclusively in the browser with no validation path.
grep -rn "postMessage\|onmessage" web/src/lib/scripting/ | head -10
grep -rn "deductTokens\|creditAddon" web/src/stores/ | head -10
Acceptable for now: Script execution is intentionally client-side (game scripting, not multiplayer). But flag if game-critical state (health, score, inventory) is only validated client-side.
Review Checklist
When reviewing a PR or designing a feature, check:
Running the Review
On a PR
gh pr diff <number> | grep -E "thread_local|static mut|getState\(\)\.|selectedIds|Math\.random|Date\.now"
On the full codebase
Run each section's grep commands above and report findings with file:line references.
Current Known Debt
These exist today and will need fixing for multiplayer:
SelectionChangedEvent is global (single selection set)
HistoryStack is a single undo chain
- Script worker runs client-side only (fine for single-player game scripting)
- Camera is a single entity (need per-viewport for split-screen / spectator)