diff --git a/docs/architecture/networking.md b/docs/architecture/networking.md
index ca523a5..c313ad8 100644
--- a/docs/architecture/networking.md
+++ b/docs/architecture/networking.md
@@ -237,6 +237,62 @@ snapshot_state:
---
+## 7a. Server Orchestration (implemented, PC3 Phase 2)
+
+**One dedicated server process per world**, spawned on demand.
+
+```
+client backend (single worker) host
+ │ POST /api/worlds/{id}/join (bearer JWT) │
+ │ ───────────────────────────▶ GameServerSupervisor │
+ │ ensure_server(world_id): │
+ │ if none running for world ─── spawn:
+ │ godot --headless
+ │ res://scenes/server.tscn --
+ │ --port
--world
+ │ --status-file
+ │ ◀─────────────────────────── { host, port, world_id } │
+ │ │
+ │ ENet connect host:port ───────────────────────────────────▶ dedicated server
+```
+
+- **Supervisor** (`backend/app/services/game_servers.py`): in-process singleton,
+ so the backend MUST run single-worker. Keys servers by `world_id`. Allocates
+ ports from `GAME_SERVER_PORT_MIN..MAX`. A background reaper kills a world's
+ server once its **status file** (`{players, tick, updated}`, rewritten by the
+ server ~1×/s) reports `players == 0` for `GAME_SERVER_IDLE_TIMEOUT_SECONDS`.
+ No crash-restart — the next join respawns.
+- **Enable flag:** `GAME_SERVERS_ENABLED` (default off). The checkpoint/playtest
+ launcher (`pm/checkpoint_ops.py`) turns it on, passes `GODOT_BIN`,
+ `GAME_PROJECT_DIR`, and `GAME_SERVER_HOST` (the LAN IP baked into the `.exe`).
+ A backend with it off returns **503** from `/join`, and the client falls back
+ to local single-player.
+- **Per-world content:** all worlds currently load the same test level (M2/M7
+ work). `world_id` still scopes a distinct process + session.
+
+### 7b. Client play path
+
+`world_list.gd` → `POST /join` → `Session.begin(world_id, host, port)` →
+load `game.tscn`. `game.gd` sees `Session.active` and connects a
+`NetworkClient`:
+
+- **Local player** keeps predicting with its own collision-aware
+ `CharacterBody3D` (`player.gd`) — that *is* the prediction. Its input frame
+ (`player.net_input`) is forwarded to the server every physics tick.
+- **Correction backstop:** if the local position drifts from the server's by
+ more than `CORRECTION_THRESHOLD` (1.5 m — generous; catches teleport / a wall
+ walked through / real desync, not prediction noise) it snaps.
+- **Remote players:** rendered from snapshots, position lerped. *Appearance sync
+ is a follow-up* — remotes currently show as labelled capsules; the server
+ does not yet replicate avatar loadouts.
+- **Disconnect** → status message → back to the world list.
+
+The `NetworkClient`'s own flat-plane prediction + input-replay reconciliation
+(§5) is exercised by `smoke_test_network_client.gd`; the collision-aware game
+path above uses the lighter `send_input()` + drift-snap instead.
+
+---
+
## 8. Security & Anti-Cheat
- **No client-authoritative gameplay values.** Clients only send *inputs* and