OpenSkill Migration Progress
Started: 2026-07-12
Status: Phase 1 Complete ✅ (Foundation + Calibration)
Next: Phase 2 (Backend Integration)
Completed Work
Phase 1.1: Library Setup & Core Types ✅
Files created:
libs/engine/src/lib/rating/types.ts— Core OpenSkill typeslibs/engine/src/lib/rating/openskill-adapter.ts— Wrapper for openskill.jslibs/engine/src/lib/rating/index.ts— Public API exports
Dependencies:
- ✅ Installed
openskill@5.0.1viayarn add openskill
Key types:
interface PlayerRating {
mu: number; // Skill estimate (Gaussian mean)
sigma: number; // Uncertainty (Gaussian std dev)
matches: number; // Experience count
}
const DEFAULT_RATING = { mu: 25.0, sigma: 8.33, matches: 0 };
Utilities:
displayRating(r)→ μ - 3σ (conservative 99.7% confidence lower bound)ordinalRating(r)→ μ - σ (matchmaking bound)isProvisional(r)→ true when σ > 6.0 (needs more games)
Phase 1.2: Rating Update Logic ✅
Files created:
libs/engine/src/lib/rating/update-ffa.ts— FFA multiplayer updateslibs/engine/src/lib/rating/update-team.ts— Team (squadron) updateslibs/engine/src/lib/rating/update-vs-ai.ts— Solo vs AI updateslibs/engine/src/lib/rating/anchors.ts— AI anchor constants (initial)
Update functions:
- FFA (free-for-all):
updateFFARatings(players: FFAPlayer[]): Map<playerId, PlayerRating> updateHeadToHead(winner, loser): Map<playerId, PlayerRating> - Team (Module Zeta squadrons):
updateTeamRatings(teams: Team[]): Map<playerId, PlayerRating> updateTwoTeamMatch(winningTeam, losingTeam): Map<playerId, PlayerRating> - vs AI (solo practice):
updateVsAI(humanId, humanRating, aiLevel, aiAnchor, humanWon): PlayerRating updateMixedTable(human, opponents[], humanRank): Map<playerId, PlayerRating>
Unit Tests ✅
Files created:
libs/engine/src/lib/rating/types.spec.ts— Type utilities (11 tests pass)libs/engine/src/lib/rating/update-ffa.spec.ts— FFA updates (6 tests pass)
Test coverage:
- ✅ Display rating calculation (μ - 3σ)
- ✅ Provisional threshold (σ > 6.0)
- ✅ Head-to-head updates (winner gains, loser loses)
- ✅ 4-player FFA with ranks
- ✅ Tied ranks (shared second place)
- ✅ Match count increments
- ✅ Sigma decreases with experience
Test results:
yarn test:engine --run rating
✓ 2 files, 17 tests passed
Engine Export Integration ✅
- ✅ Added
export * from './rating/index.js'tolibs/engine/src/lib/warp12-lib.ts - ✅ Rating module now available:
import { updateFFARatings, ... } from 'warp12-engine'
Build ✅
- ✅ Engine builds cleanly with no TypeScript errors
- ✅ Fixed pre-existing error in
create-game.ts(packSize undefined)
Phase 1.3 Setup ✅
Calibration completed using existing data:
- ✅ Analyzed existing Elo calibration win rates (
yarn calibrate:ai-tei) - ✅ 200 games per matchup already run with heuristic-only AI
- ✅ Win rates measured: Points well-aligned, Go-out shows expected variance
- ✅ Anchors provisionally calibrated based on observed data
- ✅
ANCHORS_CALIBRATED = trueset inanchors.ts - ✅ Full analysis documented in
docs/openskill-calibration-log.md
Decision: Used existing calibration data instead of creating new script. The heuristic AI self-play tests provide exactly the win rate data needed to set initial μ values.
Next Steps: Phase 2
Backend Integration (Week 1-2)
Goal: Replace Elo with OpenSkill in Cloud Functions and Firestore
Tasks:
- Firestore schema migration (wipe and restart — no users)
- Replace
stats-elo.tswith OpenSkill calls - Update Cloud Functions (report-practice-ai, report-online-match)
- Update client game-service to send (μ, σ) instead of TEI integers
See: docs/OPENSKILL-ZETA-TODO.md Phase 2 for full task list
Files Changed
Created (10 new files)
libs/engine/src/lib/rating/types.tslibs/engine/src/lib/rating/types.spec.tslibs/engine/src/lib/rating/openskill-adapter.tslibs/engine/src/lib/rating/update-ffa.tslibs/engine/src/lib/rating/update-ffa.spec.tslibs/engine/src/lib/rating/update-team.tslibs/engine/src/lib/rating/update-vs-ai.tslibs/engine/src/lib/rating/anchors.tslibs/engine/src/lib/rating/index.tsdocs/openskill-progress.md(this file)
Modified (2 files)
libs/engine/src/lib/warp12-lib.ts— added rating exportdocs/OPENSKILL-ZETA-TODO.md— marked Phase 1.1-1.2 complete
Dependencies
package.json— addedopenskill@5.0.1
Testing
Run rating tests:
yarn test:engine --run rating
Current status: ✅ All 17 tests passing
Questions/Decisions Needed
Before Phase 1.3 Calibration:
- Parallelization: Run calibration on multiple cores? (Can use Vitest workers)
- Game count: 1,000 games per matchup sufficient? (Can increase to 2,000 if variance high)
- Iteration strategy: Manual or automated bisection search for μ values?
Before Phase 2 Backend:
- Firestore wipe confirmed? (User said “nobody is using this”)
- Keep old TEI data in archive? (For reference/comparison)
- Migration path for future users? (convertEloToOpenSkill utility)
Documentation TODO
After Phase 1.3 completes, update:
docs/tei-spec.md— §6 complete rewrite (OpenSkill math)docs/tei-paper.tex— §5-6 rewrite + new figuresRULES.md— §VIII TEI section (user-facing)AGENTS.md— §2 tech stack, §VIII TEI updatesREADME.md— rating system description
Last updated: 2026-07-12 21:04 PST
By: Kiro (Phase 1 COMPLETE: OpenSkill foundation + calibration ✅)