Files
suaveplan/openspec/changes/enterprise-game-server-core/proposal.md
2026-05-27 23:29:53 +01:00

7.0 KiB

Enterprise migration: @suaveplan/game-server (core slice)

Package: @suaveplan/game-server Status: PROPOSED Type: new-package

Why

@suaveplan/game-server on the reference branch claude/review-game-engine-arch-Kaykr (main repo packages/universal/game-server/) is a 192-file framework with session lifecycle, plugin chain, networking, state-sync, matchmaking, and an "enhanced" variant (anti-cheat / lag-compensation / interest management / replay / tournament / persistence / leaderboard / state-sync / timing). The branch's last commit (2fb25cdb35) made the engine generic by removing all game-specific adapters (bingo / tic-tac-toe / gem-crush).

Genesis needs that engine, but porting all 192 files in one slice would either skip the genesis quality gates (100% test coverage, sibling .md per .ts, kebab-case + 5-file layout, typed errors, Zod boundaries, OTel) or land partially-built code. Six required workspace dependencies (controller, keys, network-webrtc, network-websockets, storage-browser, workflow) do not yet exist on genesis, blocking the network/, plugins/, and parts of state/.

This change ships the dependency-light foundation that every later slice depends on, behind the @suaveplan/game-server name at 0.1.0, and documents the remaining scope as explicitly deferred follow-on changes. The package is fully usable today by downstream code that wants typed errors, Zod-validated boundary types, or the DI container.

What changes

  • ADDED: @suaveplan/game-server package at packages/gaming/games/game-server/ (universal tier, sideEffects: false, version 0.1.0).
  • ADDED: GameServerError + GAME_SERVER_CODES registry via defineCodes — four initial codes: SERVICE_NOT_REGISTERED, INVALID_GAME_CONFIG, INVALID_SESSION_METADATA, INVALID_PLAYER_INFO.
  • ADDED: GameConfig, SessionMetadata, PlayerInfo, MoveValidationResult, GameResult, SessionType, DeepReadonly with Zod schemas (GameConfigSchema, SessionMetadataSchema, PlayerInfoSchema, MoveValidationResultSchema, GameResultSchema, SessionTypeSchema) and validators (parseGameConfig, parseSessionMetadata, parsePlayerInfo, tryParseMoveValidationResult, tryParseGameResult).
  • ADDED: DIContainer with singleton/transient lifecycles, typed error on miss, and re-register-invalidates-cache semantics (genesis improvement over upstream).
  • ADDED: Subpath exports ./errors, ./types, ./engine/di-container for tree-shaking.

Out of scope (deferred)

Surface area Why deferred Follow-up change
core/{AbstractGameLogic, interfaces/*, events/*} Each contract file needs its own 5-file layout + tests + docs; bundling all of them in one slice would force this PR over 30 files. enterprise-game-server-core-contracts
engine/{GameEngine 487, GameLoop 355, PlayerManager 345, PluginManager 340, SessionLifecycle 295, SessionNode 173, SessionStore 128, SessionTree 429} Six of eight files exceed the 300-line genesis hard limit and require splitting. Each needs Zod boundary schemas, OTel instruments, typed GAME_SERVER.* codes, 100% coverage, ≥200-word sibling .md. enterprise-game-server-engine
state/{DeltaCompressor 221, StateDiffer 280, StateManager 316, StateSync 375} StateManager and StateSync exceed the 300-line limit; StateSync also reaches into networking which is blocked. enterprise-game-server-state
matchmaking/{MatchmakingEngine 152, QueueManager 169, SpectatorManager 122, skill-matcher 40, winner-stays-on 56} Dependency-clean but still requires the engine/state slices to be useful end-to-end. enterprise-game-server-matchmaking
performance/{NetworkTierAdapter, ObjectPool, SessionPool} → telemetry/ Folds into engine slice (SessionPool consumes Session from engine). enterprise-game-server-engine
network/{NetworkAdapter, ReconnectionManager, WebRTCTransport, WebSocketTransport} BLOCKED on missing genesis deps @suaveplan/network-webrtc and @suaveplan/network-websockets. After transport packages land.
plugins/{ABTest, Analytics, BasePlugin, FeatureFlag, Logging, Persistence, Rules, Workflow} BLOCKED on missing genesis deps @suaveplan/workflow and @suaveplan/keys. After workflow/keys packages land.
enhanced/ (73 files: anti-cheat, components, interest-management, lag-compensation, leaderboard, persistence, replay, service-discovery, state-sync, timing, tournament) Priority 2 per migration brief; the enhanced variant sits above a stable engine. Several enhanced features have transitive deps on the blocked packages. enterprise-game-server-enhanced
integrations/components/game-lobby/* Priority 3 — React-coupled UI that belongs in a react-game-lobby package, not a universal-tier engine. enterprise-react-game-lobby
integrations/enhanced-server/* Bundles every enhanced feature; depends on enterprise-game-server-enhanced. enterprise-game-server-enhanced
stories/*, e2e/*, benchmarks/* Storybook/Playwright/bench tooling lands with the surfaces they exercise. per-slice.

Source mapping

This change derives from ../suaveplan/enterprise/game-server.md (not present in the worktree's parent repo — the reference is the branch claude/review-game-engine-arch-Kaykr itself, since the package was under active redesign).

Requirement Source lines Notes
Typed error registry GAME_SERVER.* src/engine/DIContainer.ts:30 (only throw site in the migrated slice; upstream used plain Error) reworded — typed error replaces plain throw.
GameConfig/SessionMetadata/PlayerInfo/MoveValidationResult/GameResult types src/core/types/index.ts:1-47 extended — added Zod schemas + validators (no source line).
DIContainer singleton/transient resolver src/engine/DIContainer.ts:1-61 extended — re-register-invalidates-cache is new in genesis.

Requirements with no source line

Requirement Justification
Zod schemas for every boundary type Genesis rule: every public boundary is Zod-validated.
Typed GameServerError instead of plain Error Genesis rule: every package throws via its own defineCodes registry.
readonly modifiers on every interface field Genesis lint profile rejects Record<string, any> and prefers immutable shapes.
Re-register-invalidates-cache on DIContainer Bug-class fix: upstream silently kept stale singletons after re-register.

Verification approach

  • src/errors/game-server-error.test.ts — registry shape, error construction, code discrimination.
  • src/types/common.test.ts — every schema accept-path, reject-path, and validator throw-path with the matching code.
  • src/engine/di-container/di-container.test.ts — singleton, transient, symbol identifiers, fluent chaining, miss-throws-typed-error, has/unregister/clear/getRegisteredServices, re-register cache invalidation.

Migration impact

None — additive only. No consumer on genesis currently imports @suaveplan/game-server.