Continuous delta ladders
Player-created correspondence ladders: one canonical board per meta game + variant series, continuous point totals (not seasons), matchmaking pool, direct challenges, and tournament-style Fischer clocks on ladder games.
Overview
| Topic | Behavior |
|---|---|
| Series key | Same as single-leg TOURNAMENTSCOUNTER sk (metaGame + sorted variants) |
| Eligibility | Meta games that support 2-player rated play (same guard as automated tournaments) |
| Activation | forming until minActiveMembers (default 4) join; then active |
| Clocks | 120h max, 36h inc per move (shared with automated tournaments) |
| Ratings | Ladder games are rated Glicko; ladder points are separate from Glicko |
| Vacation | Correspondence vacation does not block ladder pool or challenges |
Correspondence challenges and async play are unchanged. Ladder games are tagged with ladderId on GAME and settled through applyLadderGameEnd on decisive game end.
Record types
See Database schema (Ladders section). Main families:
| pk | Purpose |
|---|---|
LADDER |
Board definition, status, tuning, member counts |
LADDERSERIES |
Series key → ladderId |
LADDERPLAYER |
Member points, caps, decay timestamps |
LADDERBYUSER#<userid> |
Dashboard index of active memberships |
LADDERGAME |
Link game → ladder; settled after Δ applied |
LADDERPOOL |
Matchmaking queue |
LADDERPAIR |
Rematch cooldown between two members |
LADDERCOMMENTS |
Hub chat log |
CHALLENGE rows may include ladderId. CURRENTGAMES# projects ladderId when present.
Lifecycle
- Create — auth
new_laddercreatesformingladder and joins creator. Duplicate series returns 409 withexistingLadderId. - Join / leave —
join_ladder/leave_ladder. Rejoin afterleftkeeps prior points. Leave blocked whileactiveLadderGameCount > 0. - Play —
join_ladder_pool,new_ladder_challenge+respond_ladder_challenge, or pool pairing creates rated games viacreateLadderGame. - Settle — On win/loss/draw end,
runLadderGameEndHookupdates points (draw: no Δ), decrements active counts, enqueuesladderPointsChangewhen Δ ≠ 0. - Decay — Daily
ladder-decaycron applies inactivity decay andladderDecaynotifications.
Point deltas
Constants and formulas live in lib/ladders/delta.ts and per-ladder tuning on the LADDER row (copied at creation). Pace multiplier uses game duration and move count (paceMultiplier.ts).
Auth queries
Documented in Auth queries (Ladders section): new_ladder, join_ladder, leave_ladder, get_ladder, pool/challenge/comment RPCs. me_dashboard exposes ladderMemberships, currentLadderGames, and ladderId on active games.
WebSockets
Clients use watchLadders (see WebSockets) for hub refresh; game boards use existing game watch channels.
Notifications
| Type | When |
|---|---|
ladderJoin / ladderLeave |
Member joins or leaves (join_ladder / leave_ladder) |
ladderPointsChange |
Decisive settlement (applyLadderGameEnd); prefs ladderPointsGain / ladderPointsLoss |
ladderChat |
submit_ladder_comment |
ladderDecay |
Daily decay cron |
Details: Notifications.
Scheduled jobs
| Cron | Schedule (UTC) | Role |
|---|---|---|
ladder-decay |
00:00 daily | Inactivity decay + notify |
ladder-reconcile-counts |
00:01 daily | Fix activeLadderGameCount drift; ops S3 reports |
See Live crons and crons/docs/functions.md.
Records site
Completed ladder metadata is published under records event/{ladderId}.json (crons records pipeline).
Operations runbook
Set ABSTRACT_PLAY_TABLE (or use --stage where supported). Prefer scripts/ CLIs over ad-hoc bin/ scratch.
| Script | Purpose |
|---|---|
npx tsx scripts/reconcile-ladder-active-counts.ts --dry-run |
Compare/fix activeLadderGameCount vs open ladder games (--live, optional --ladderId) |
npm run backfill-ladder-by-user -- --stage dev [--live] |
Rebuild LADDERBYUSER# from active LADDERPLAYER rows |
npm run replay-ladder-member -- <ladderId> <userid> |
Replay Δ from startingPoints + settled games; exit 2 on mismatch (decay excluded) |
npx tsx scripts/audit-ladder-snapshot.ts <ladderId> |
Read-only health snapshot (members, pool, drift) |
Daily reconcile JSON: private ops S3 ladders/reconcile/daily/YYYY-MM-DD.json and latest.json. Alert on non-zero driftCorrections or overCapIncidents (LadderActiveCountDrift / LadderActiveCountOverCap metrics from the cron).
Launch checklist (prod):
- Deploy API + crons; staging exercised end-to-end.
reconcile-ladder-active-counts --dry-runclean (or fixes applied with--live).- Published
/backend/subsystems/ladders/anddocs:checkgreen. - Front: remove
VITE_LADDER_UI_DISABLEDand deploy (see front CHANGELOG).
Related
- Tournaments — shared series key and clock constants
- Challenges — ladder challenges reuse
CHALLENGE - Games and moves — play and timeloss hooks