# Tasks: Wave B-5a game-server matchmaking ## 0. Pre-flight - [x] `pwd && git worktree list && git status` — confirm isolated worktree. - [x] Confirm worktree HEAD is descended from genesis tip (Wave A + B-1/3/4 merged). - [x] Read `CLAUDE.md`, `openspec/AGENTS.md`, existing `src/core`, `src/errors`, `src/types`. - [x] Read upstream reference: `/mnt/s/web/suaveplan/packages/universal/game-server/src/matchmaking/{MatchmakingEngine,QueueManager,SpectatorManager,skill-matcher,winner-stays-on}.ts`. ## 1. Error registry - [x] Append eight matchmaking codes to `GAME_SERVER_CODES` (`MATCHMAKING_QUEUE_FULL`, `INVALID_QUEUE_REQUEST`, `INVALID_MATCH_CRITERIA`, `NO_MATCH_FOUND`, `INVALID_SKILL_SCORE`, `SPECTATOR_LIMIT_REACHED`, `INVALID_SPECTATOR_REQUEST`, `UNKNOWN_MATCHING_ALGORITHM`). - [x] Extend `game-server-error.test.ts` with assertions on the new codes. - [x] Update `game-server-error.md` to enumerate the new codes. ## 2. `winner-stays-on` - [x] `winner-stays-on.types.ts` — `WinnerStaysOnConfig`, `WinnerStaysOnStats`, Zod config schema. - [x] `winner-stays-on.ts` — `recordResult`/`addChallenger`/ `nextChallenger`/`forceRotateChampion`/`reset`/`getStats`, two OTel counters, typed-error boundary. - [x] `winner-stays-on.test.ts` — 100% coverage incl. error paths. - [x] `winner-stays-on.md` — six sections, ≥200 words. - [x] `index.ts` barrel. ## 3. `skill-matcher` - [x] `skill-matcher.types.ts` — `SkillEntry`, `SkillMatcherConfig`, `SkillScoringFn`, Zod schemas. - [x] `skill-matcher.ts` — `findMatch`/`effectiveRange`, pluggable scoring, injectable `Clock`/`Rng`, OTel counter + histogram. - [x] `skill-matcher.test.ts` — 100% coverage incl. tie-break paths. - [x] `skill-matcher.md` — six sections, ≥200 words. - [x] `index.ts` barrel. ## 4. `queue-manager` - [x] `queue-manager.types.ts` — `QueueRequest`, `QueueConfig`, `QueueStats`, Zod schemas. - [x] `queue-manager.ts` — `addToQueue`/`removeFromQueue`/`findMatch`/ `getQueueSize`/`getQueuePosition`/`getStats`/`clear`, four OTel instruments, typed-error boundary. - [x] `queue-manager.test.ts` — 100% coverage incl. cap rejection + wait-time priority. - [x] `queue-manager.md` — six sections, ≥200 words. - [x] `index.ts` barrel. ## 5. `spectator-manager` - [x] `spectator-manager.types.ts` — `Spectator`, `SpectatorPermissions`, `SpectatorManagerConfig`, Zod schemas. - [x] `spectator-manager.ts` — `addSpectator`/`removeSpectator`/ `removeAllSpectators`/getters, three OTel counters, typed-error boundary, optional join/leave listeners. - [x] `spectator-manager.test.ts` — 100% coverage incl. cap rejection + duplicate spectator rejection. - [x] `spectator-manager.md` — six sections, ≥200 words. - [x] `index.ts` barrel. ## 6. `matchmaking-engine` - [x] `matchmaking-engine.types.ts` — `Match`, `MatchCriteria`, `MatchingAlgorithm`, Zod schemas. - [x] `matchmaking-engine.ts` — `createMatch` (quick / skill-based) + `createMatchFromQueue` (drain with max→min fallback) + `getMatch` / `removeMatch` / `dispose`, three OTel instruments, injectable `IdGenerator`/`Clock`/`Rng`, optional `onMatchFound` callback. - [x] `matchmaking-engine.test.ts` — 100% coverage incl. unknown algorithm + invalid criteria + skill-range edge cases. - [x] `matchmaking-engine.md` — six sections, ≥200 words. - [x] `index.ts` barrel. ## 7. Wiring - [x] Re-export every public surface from `src/index.ts`. - [x] Add subpath exports to `package.json` for each module. ## 8. Verification - [x] `bunx turbo lint typecheck test --filter=@suaveplan/game-server` green. - [x] `bunx turbo test:coverage --filter=@suaveplan/game-server` = 100/100/100/100. - [x] `grep -rnE "from ['\"](vitest|bun:test)['\"]" packages/gaming/games/game-server/src/` → zero output. - [x] `grep -rn "biome-ignore|TODO|FIXME|XXX" packages/gaming/games/game-server/src/matchmaking` → zero output. - [x] All source files ≤300 lines; all test files ≤500 lines. - [x] `bun run docs:check` reports 100% coverage.