101 lines
5.7 KiB
Markdown
101 lines
5.7 KiB
Markdown
# OpenSpec Change: network-plugin-session
|
|
|
|
- **Change ID**: network-plugin-session
|
|
- **Package**: `@suaveplan/network-plugin-session` (new)
|
|
- **Status**: PROPOSED
|
|
- **Type**: new-package
|
|
- **Date**: 2026-04-29
|
|
|
|
## Why
|
|
|
|
The tiered mesh network provides peer-to-peer connectivity, but it has no concept of **logical player groupings** — sessions. A session is a scope within which peers see each other, exchange state, and interact. Sessions can be nested: a parent session (free-roam open world) contains child sessions (missions, heists, races), which may contain further nested sessions (mission phases, instanced interiors). This is the pattern used by GTA V Online, Destiny, The Division, and many other multiplayer games.
|
|
|
|
Without session management, every peer in the mesh receives every message from every other peer. Sessions provide:
|
|
|
|
- **Visibility isolation** — peers only receive state from peers in their session branch
|
|
- **Nested hierarchies** — missions inside free-roam, phases inside missions
|
|
- **Session-scoped host nomination** — each session elects its own host for state authority
|
|
- **Capacity enforcement** — hard caps per session type (free-roam: 30, mission: 4, race: 8)
|
|
- **Graceful transitions** — joining/leaving sessions without dropping mesh connection
|
|
- **Parent state inheritance** — sub-sessions can optionally receive read-only state from parent (weather, time, world events)
|
|
|
|
## What changes
|
|
|
|
- **ADDED**: `SessionPlugin` class implementing `NetworkPlugin`.
|
|
- **ADDED**: `SessionManager` — maintains the session tree, handles create/destroy/join/leave/move operations.
|
|
- **ADDED**: `Session` — represents one session node in the tree: `id`, `parentId`, `hostId`, `peers[]`, `capacity`, `rules`, `state`.
|
|
- **ADDED**: `SessionRouter` — intercepts outgoing messages and filters delivery to peers in the target session scope only.
|
|
- **ADDED**: `SessionHostElection` — per-session host nomination, independent of mesh Tier 0 host. A peer can be host of multiple sessions.
|
|
- **ADDED**: `SessionTransitionManager` — handles join/leave/move with state snapshot transfer and forwarding tunnel.
|
|
- **ADDED**: `ParentStateBridge` — optionally replicates read-only parent state into child sessions (e.g., world time, weather).
|
|
- **ADDED**: `SessionCapacityEnforcer` — rejects joins when capacity exceeded; can trigger session split.
|
|
- **ADDED**: `SessionRegistry` — tracks all known sessions in the mesh, their hosts, and their peer counts.
|
|
- **ADDED**: `NETWORK_SESSION_CODES` — frozen error registry.
|
|
|
|
## Session hierarchy model
|
|
|
|
```text
|
|
Mesh (all connected peers)
|
|
└── Session: "freeroam-01" (capacity: 30, host: Peer-A)
|
|
├── Peer-A (host)
|
|
├── Peer-B
|
|
├── Peer-C
|
|
├── Peer-D
|
|
└── Session: "mission-heist-01" (capacity: 4, host: Peer-B)
|
|
├── Peer-B (host)
|
|
├── Peer-C
|
|
├── Peer-D
|
|
└── Session: "phase-drill" (capacity: 2, host: Peer-C)
|
|
├── Peer-C (host)
|
|
└── Peer-D
|
|
```
|
|
|
|
**Rules**:
|
|
|
|
- A peer can be in **exactly one leaf session** at a time.
|
|
- A peer implicitly belongs to all ancestor sessions (for parent state bridge).
|
|
- Messages sent within a session are delivered **only to peers in that session or its descendants**.
|
|
- Messages sent "upward" (to parent) are delivered to the parent session host only.
|
|
- Each session has its own host, elected independently via the same governance scoring.
|
|
|
|
## Out of scope
|
|
|
|
- Game-specific state replication (entities, physics, AI) → gaming packages (`gaming-ecs`, `gaming-r3f-networking`).
|
|
- Matchmaking (finding which session to join) → `gaming-lobby`, `gaming-matchmaking`.
|
|
- Party system (persistent friend group) → `gaming-party`.
|
|
- Persistence (saving session state to disk) → future `network-plugin-session-persistence`.
|
|
|
|
## Source mapping
|
|
|
|
This change derives from the session concepts in `../suaveplan/enterprise/game-server.md` (§sessions) and `../suaveplan/enterprise/lobby.md`, but is a **new design** — suaveplan has no equivalent network-layer session plugin.
|
|
|
|
| Requirement | Source lines | Notes |
|
|
|---|---|---|
|
|
| Session management | `game-server/README.md` §Sessions | reworded; suaveplan had session stubs in game-server, not network layer |
|
|
| Session host | `game-server/README.md` §Sessions | reworded; host per session, not per mesh |
|
|
| Capacity limits | `lobby/README.md` §Capacity | reworded; per-session, not per-lobby |
|
|
|
|
### Requirements with no source line
|
|
|
|
| Requirement | Justification |
|
|
|---|---|
|
|
| Session-scoped message routing | Defensive — prevents free-roam state flooding mission peers |
|
|
| Nested session hierarchies | Required for GTA V-style missions-within-free-roam |
|
|
| Parent state bridge | Required so mission players still see world time/weather |
|
|
| Per-session host election | Required so mission host can be closest to mission peers, not free-roam host |
|
|
| Session transition with snapshot | Required for seamless join/leave without mesh disconnect |
|
|
|
|
## Verification approach
|
|
|
|
- `src/session/session.spec-conformance.test.ts` — pins create, destroy, join, leave, move.
|
|
- `src/router/router.spec-conformance.test.ts` — pins message delivery scope, upward routing, parent bridge.
|
|
- `src/election/election.spec-conformance.test.ts` — pins per-session host election, independent of mesh host.
|
|
- `src/transition/transition.spec-conformance.test.ts` — pins join/leave/move with state snapshot.
|
|
- `src/capacity/capacity.spec-conformance.test.ts` — pins capacity enforcement, rejection, split trigger.
|
|
- `src/registry/session-registry.spec-conformance.test.ts` — pins session tree tracking, peer counts.
|
|
- `tests/dep-graph.test.ts` — pins no direct import of webrtc or gaming packages.
|
|
|
|
## Migration impact
|
|
|
|
None — additive only.
|