Files
2026-05-27 23:29:53 +01:00

58 lines
5.0 KiB
Markdown

# Game-server enhanced infra: service-discovery + state-sync + timing
**Package**: `@suaveplan/game-server`
**Status**: PROPOSED
**Type**: feature
## Why
Wave C-4 lands the three "enhanced" subsystems that ride on top of the wave-A/B core: a heart-beating game-instance registry for multi-host
discovery + load-balancing, a binary delta state-sync layer driven by `@suaveplan/bitpacker` (complementary to the JSON-delta `state/state-sync`
shipped in wave B-3), and a vector-clock causality tracker for distributed event ordering. Without these, the higher-level orchestrator cannot
fan a session across processes, ship compact state updates over WebRTC, or reason about who-saw-what when two clients race a move.
## What changes
- ADDED: `GameInstanceRegistry` — TTL-evicting in-memory registry of live instances with four load-balancing strategies (`least-players`, `random`, `region-based`, `round-robin`), region-latency map, capacity / health updates, filter+select discovery API, and 6 lifecycle event keys wired through the existing `GameEventEmitter`.
- ADDED: `BitPackerStateSync<TState, TSchema>` — bitpacker-backed binary state-sync with client-side prediction, server reconciliation, and frame interpolation. Uses `@suaveplan/bitpacker`'s `BitPacker.pack/unpack` for the wire format. Coexists with the JSON-delta `state/state-sync` from wave B-3.
- ADDED: `VectorClockSync<TEventData>` — distributed event-ordering layer built over `@suaveplan/timing`'s `createVectorClock`. Records game actions per session, detects concurrent actions, runs `last-write-wins | merge | custom` conflict resolution, and supports request/response sync rounds against remote nodes.
- ADDED: 5 error codes — `REGISTRY_INSTANCE_NOT_FOUND`, `REGISTRY_HEARTBEAT_EXPIRED`, `BITPACK_ENCODE_FAILED`, `BITPACK_DECODE_FAILED`, `VECTOR_CLOCK_NODE_UNKNOWN` — appended to `GAME_SERVER_CODES`.
- ADDED: 3 OTel instruments — `game_server.registry.instance_lifecycle_total` (counter), `game_server.state.bitpack_bytes` (histogram), `game_server.vector_clock.actions_total` (counter).
- ADDED: 3 package subpath exports: `./enhanced/service-discovery/game-instance-registry`, `./enhanced/state-sync/bitpacker-state-sync`, `./enhanced/timing/vector-clock-sync`.
- ADDED: `@suaveplan/bitpacker` and `@suaveplan/timing` as `workspace:^` runtime deps.
## Out of scope
- Cross-process IPC for the registry (HTTP/gRPC façade) — the registry is the in-memory primitive; a transport façade is a separate package.
- Lamport-clock variant (only vector clocks ship; Lamport is the degenerate single-counter case).
- Bitpacker schema authoring helpers — callers supply their own `BitPackerSchema`.
## Source mapping
This change derives from `../suaveplan/packages/universal/game-server/src/enhanced/`.
| Requirement | Source lines | Notes |
|---|---|---|
| `GameInstanceRegistry` lifecycle (start/stop/register/deregister) | `service-discovery/game-instance-registry/game-instance-registry.ts` L33-L94 | Reworded; genesis injects `Clock` (no `Date.now`) and routes events through `GameEventEmitter`. |
| Heartbeat-TTL eviction | same file L340-L351 | Verbatim semantics; injectable `Clock` substituted for `Date.now`. |
| Load-balancing strategies | same file L258-L338 | All four strategies preserved; `Rng` injected for `random`. |
| Filter / select discovery | same file L138-L208 | Preserved. |
| `BitPackerStateSync` pack/unpack/prediction/reconciliation/interpolation | `state-sync/bitpacker-state-sync/bitpacker-state-sync.ts` L36-L307 | Reworded; logger dep dropped (genesis OTel-only); `enableDelta` flag plumbed via `BitPackerOptions`. |
| `VectorClockSync.recordAction` / `receiveAction` | `timing/vector-clock-sync/vector-clock-sync.ts` L86-L147 | Rewritten on top of genesis `createVectorClock` (no upstream `VectorClockManager`); causality compare uses `vectorClockCompare`. |
| Conflict resolution strategies | same file L320-L350 | Preserved (`last-write-wins`, `merge`, `custom`). |
| Causality chain + concurrent-group detection | same file L170-L205, L383-L414 | Preserved. |
### Requirements with no source line
| Requirement | Justification |
|---|---|
| Injectable `Clock` + `IdGenerator` everywhere a timestamp / id is minted | Genesis enterprise rule — no implicit `Date.now` or `Math.random`. |
| OTel counters / histogram on every public path | Genesis observability baseline. |
| Zod validation on `GameInstanceRegistration` and `BitPackerStateSyncConfig` input boundaries | Genesis rule: typed boundary at every public entry. |
| Five new error codes routed through `GameServerError` | Upstream throws plain `Error`; genesis policy is typed errors with the stable code registry. |
## Risks
- The genesis `timing` package exposes only `createVectorClock` (not the upstream `VectorClockManager`). The rewrite preserves the upstream public surface of `VectorClockSync` but is built on the simpler primitive — this is the documented divergence.
- Coverage target is 100/100/100/100; `BitPackerStateSync.interpolate` has multi-branch lerp logic that requires careful test design.