Files
suaveplan/openspec/specs/network-session/spec.md
2026-05-27 23:29:53 +01:00

4.7 KiB

Capability Spec: network-session

Capability ID

network-session

Status

PROPOSED

Description

Logical session overlay on top of the tiered mesh network. Sessions provide player visibility scopes, nested hierarchies (free-roam → mission → phase), per-session host nomination, capacity enforcement, and seamless join/leave transitions.

Interfaces

Session

interface Session {
  readonly id: SessionId;
  readonly parentId: SessionId | null;
  readonly hostId: string;
  readonly peers: ReadonlyArray<string>;
  readonly capacity: number;
  readonly rules: SessionRules;
  readonly state: SessionState;
  readonly depth: number;
}

SessionManager

interface SessionManager {
  createSession(parentId: SessionId, config: SessionConfig): Session;
  destroySession(sessionId: SessionId): void;
  join(sessionId: SessionId, peerId: string): Promise<void>;
  leave(sessionId: SessionId, peerId: string): Promise<void>;
  move(peerId: string, fromSessionId: SessionId, toSessionId: SessionId): Promise<void>;
  getSession(peerId: string): Session | undefined;
  getSessionPath(sessionId: SessionId): ReadonlyArray<SessionId>;
}

SessionRouter

interface SessionRouter {
  send(sessionId: SessionId, envelope: MessageEnvelope): void;
  broadcast(sessionId: SessionId, envelope: MessageEnvelope): void;
  sendToParent(sessionId: SessionId, envelope: MessageEnvelope): void;
}

SessionHostElection

interface SessionHostElection {
  nominate(sessionId: SessionId): Promise<string>;
  getHost(sessionId: SessionId): string | undefined;
}

Behaviors

NET-SESS-01 — Session tree

Sessions form a tree with exactly one root session per mesh. Each session has exactly one parent (except root). Cycles are impossible.

NET-SESS-02 — Leaf membership

A peer belongs to exactly one leaf session at any time. The peer implicitly belongs to all ancestor sessions for parent-state-bridge purposes.

NET-SESS-03 — Session-scoped routing

Messages sent within a session scope are delivered only to peers in that session or its descendants. Peers outside the scope do not receive the message.

NET-SESS-04 — Upward routing

Messages with scope: 'parent' are delivered only to the parent session's host. This is used for child-to-parent state reporting (e.g., "mission complete").

NET-SESS-05 — Broadcast within branch

Messages with scope: 'broadcast' are delivered to all peers in the target session and all descendant sessions.

NET-SESS-06 — Per-session host election

Each session nominates its own host independently. The election uses the same scoring algorithm as mesh governance but scoped to session peers. A peer can host multiple sessions simultaneously.

NET-SESS-07 — Host independence from mesh

The session host can be different from the mesh Tier 0 host. If the mesh host and session host are the same peer, that peer hosts both layers.

NET-SESS-08 — Join with state snapshot

When a peer joins a session, the session host provides a state snapshot. The peer transitions through requesting → syncing → active before receiving live messages.

NET-SESS-09 — Leave with cleanup

When a peer leaves a session, the session host cleans up peer state and notifies remaining peers. The leaving peer is moved to the parent session.

NET-SESS-10 — Move with forwarding tunnel

When a peer moves from session A to session B, a temporary forwarding tunnel routes in-flight messages from A's host to B's host until the peer is fully synced.

NET-SESS-11 — Capacity enforcement

join() is rejected when the session is at capacity. The rejection includes session:capacity-exceeded on the bus.

NET-SESS-12 — Parent state bridge

Child sessions optionally receive read-only state from parent sessions (e.g., world time, weather). Child peers cannot send messages to parent.

Error codes

  • NET_SESSION_NOT_FOUND — Session does not exist
  • NET_SESSION_PEER_NOT_FOUND — Peer not in session
  • NET_SESSION_CAPACITY_EXCEEDED — Session at capacity
  • NET_SESSION_CYCLE_DETECTED — Attempted to create session cycle
  • NET_SESSION_HOST_UNREACHABLE — Session host not responding
  • NET_SESSION_TRANSITION_TIMEOUT — Join/move/sync timed out
  • NET_SESSION_INVALID_SCOPE — Unknown message scope

Dependencies

  • @suaveplan/network
  • @suaveplan/error
  • @suaveplan/types
  • @suaveplan/events
  • @suaveplan/fsm
  • @suaveplan/timing
  • @opentelemetry/api
  • zod

Notes

  • Session depth should be bounded (suggested max: 4) to prevent routing overhead.
  • Session state is in-memory only; persistence is deferred to network-plugin-session-persistence.
  • The root session typically maps 1:1 with the mesh group.