How skill rating works on Nightcycles
Nightcycles uses OpenSkill (Plackett-Luce model) to track player skill in completed matches. Ratings are calculated server-side only after a match is settled.
Core model and values
Every tracked rating snapshot stores three values:
- mu (skill estimate)
- sigma (uncertainty/confidence width)
- ordinal (conservative skill estimate shown in UI)
Nightcycles starts new rating snapshots at mu=25, sigma=8.333333333333334, and ordinal=0.
The OpenSkill model is configured with: tau=mu/300, beta=mu/6, kappa=0.0001, limitSigma=false, and balance=false.
What gets rated
Ratings are currently tracked by alignment scope only:
- ScopeType=Alignment
- ScopeKey=Town and ScopeKey=Mafia
This means each player has separate Town and Mafia ratings. A completed match updates only the alignment bucket a player occupied in that match.
Settlement flow
- Match settlement runs on the server after a match is completed.
- A guard row in MatchSkillSettlements prevents duplicate settlement per match.
-
Inputs are built from persisted match events:
- MatchCompleted payload supplies role assignments and seat-to-alignment mapping.
- GameEnded payload supplies the winning alignment.
- Only occupied seats with a resolved player and alignment become rating inputs.
- Teams are grouped by alignment and rated together via OpenSkill.
-
Win/loss is translated to team ranks:
- Winning alignment rank = 1
- Losing alignment rank = 2
- Draws map to rank 1 for both teams
-
For each affected player snapshot:
- mu/sigma/ordinal are replaced with newly rated values
- MatchesRated increments by 1
- LastRatedAtUtc and UpdatedAtUtc are set
- An append-only row is written to PlayerSkillRatingUpdates with before/after values, match id, seat metadata, and outcome.
How ratings appear in product UI
Profile pages display raw ordinal, which is the conservative OpenSkill score. Higher ordinal means stronger demonstrated performance with uncertainty accounted for.
Leaderboard pages display a converted rating number derived from ordinal: max(100, 1000 + ordinal * 20). This keeps ratings on a familiar scale while preserving ordinal ordering.
Profile pages also show mu, sigma, and match counts. A rating is currently marked provisional when either condition is true:
- MatchesRated < 10
- Sigma > 6
Consistency and replayability notes
- Skill updates are persisted in DB tables and can be audited per match via the update ledger.
- Settlement is idempotent per match through a dedicated marker table and transaction checks.
- Only canonical alignment values (Town/Mafia) participate in rating settlement.