Repository navigation
Switch player ratings from Elo to Glicko - #126
Merged
Merged
Conversation
Dice luck keeps skill gaps small, so Elo let a short lucky run top the board and never moved players who stopped playing. Ratings are now Glicko-1 with a starting deviation of 150, and players see and rank by the cautious end of their range (rating minus twice the deviation). The deviation grows while a player sits out, so idle players drift down the board until they play again. Repeat-opponent damping stays. A new guard stops rating games between a pair once either player has won 19 of their last 20, so games thrown to a second account stop counting. The migration resets ratings and replays every completed game; streaks and feats are untouched. The leaderboard, player card, and rankings keep their shapes, so the app and Edge Functions need no changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Sucker is luck-heavy, so the Elo board mostly ranked hot streaks and activity. A newcomer who went 5–0 on coin flips could land above a player with a real 60% edge. Leaders could also stop playing and keep their spot forever. This switches ratings to Glicko-1 and ranks players by a cautious score that reflects how sure we are of their rating.
rating_before/rating_after. New players start at 900 and climb as games build confidence.Changes
supabase/migrations/20261028120000_switch_ratings_to_glicko.sqlplayer_standings.rating_deviationandrated_at.ratingnow holds the Glicko estimate.peak_ratingtracks the highest shown rating and defaults to 900.rate_completed_game.apply_completed_game_standingscalls it, then updates streaks and milestone feats exactly as before.rating_deviation_atandconservative_ratinghelpers.ranked_leaderboard('rating')andget_player_cardcompute the shown rating as ofnow(). The card takes its rank straight from the board, so they can't disagree.supabase/schema.sql,shared/database.types.ts, anddocs/community-leaderboards.mdare updated to match.The RPC shapes don't change, so the app and the
game-actionEdge Function need no updates. Rollout: apply the migration.Known limitation
No rating formula can tell a thrown game from a real one. The guard stops a long farm against a second account. But with a 150 start, the 20 thrown games the guard still allows would put a fresh account's farmer at a shown ~1227, just above today's #1. Someone who throws only some games can also climb more slowly. A wider start (350) blunts this, at the cost of the loss-raises-rating problem above. Hiding the account from boards remains the backstop.
Testing
npm run typecheck,npm run typecheck:edge,npm run lint -- --max-warnings=0,npm run test(217 passed),npm run test:edge(44 passed), anddeno checkon the integration test.npm run test:integration:supabase, because it resets the shared local Supabase database. CI runs it.🤖 Generated with Claude Code