Repository navigation
Cap each player's rows on the global list, scaled to the field - #71
Merged
Merged
Conversation
player_rank fixed the sentence under the list, but the list itself still let one enthusiast fill it: measured on 8x8 hard, 34 of the first 50 places belonged to one of three players, so a newcomer landed far down between one person's repeats. top_scores now shows each player at most ceil(p_limit / players) of their best rows — 17 each for three players on 50 places, 5 for ten, one row each from 50 players up. A fixed cap is right for exactly one population size; one row per player would take 20 of 22 buckets down to 1–3 rows. Deriving the number keeps the list full while few play and converges on one row per player by itself. It is display only: nothing is deleted, submit_score's rank and player_rank still count every row, and the player's own local list keeps them all. The player key is player_rank's (anonymous rows each their own player, so never merged or capped), and the p_since window counts its own players. The server also returns per_player and hidden; fetchTopScores lifts them onto the list, and renderScoreList adds one muted line after the rows when the cap held something back — otherwise a regular watches half their entries vanish and assumes they were lost. An un-migrated server sends neither and reads as "no cap". Verified against a throwaway PostgreSQL 16: tests/sql/top-scores-cap.sql (measured shape, name variants, anonymous rows, 60 players, a lone player, the window's own cap, best rows shown, nothing deleted), shown to fail with the cap removed; the three existing SQL suites; and the rollout itself — old schema, the workflow's rollback probe, --single-transaction apply, rows intact, anon's execute grant intact, second run a no-op. The browser test for the note was also shown to fail with the note removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019bNvb3PKt2h1XNZD5qGX7G
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.
Completes the consolidation idea from #63.
player_rankfixed the sentence ("Platz 3 von 3 Spielern"), but the list still let one enthusiast fill it — measured on 8×8 hard: 83 entries from three names, one of them on 34 of the first 50 places.The rule
top_scoresnow shows each player at mostof their best rows.
A fixed cap is right for exactly one population size; one row per player would take 20 of 22 buckets down to 1–3 rows. Deriving the number keeps the list full while few play and converges on one row per player by itself.
What it does and doesn't touch
submit_score's rank andplayer_rankstill count every row, and the player's own local list keeps them all.player_rank: anonymous rows are each their own player, so they are never merged and never capped; case/whitespace variants of a name are one player.per_playerandhidden; the client adds one muted line after the rows when the cap held something back („Höchstens 17 Einträge pro Spieler · 17 weitere ausgeblendet"), so a regular doesn't think entries were lost. New keyscore.capNotein all six packs.Testing
Against a throwaway PostgreSQL 16:
tests/sql/top-scores-cap.sql: the measured shape, name variants, anonymous rows, 60 players → one each, a lone player uncapped, the window's own cap, best rows shown, nothing deleted. Shown to fail with the cap removed (5 checks).rank-order.sql,player-rank.sql,play-stats.sqlstill green.BEGIN…ROLLBACKprobe →--single-transactionapply → all rows intact,anon's execute grant intact, cap applied (2 players → 25 each), second run a no-op.Client:
tests/logic/16/16 green;leaderboard-period.mjsextended for the metadata (including "absent ≠ 0").tests/browser/leaderboard-cap.mjs: note present/absent, after the rows, highlight and numbering untouched, fits 320 px in fr/ru/pt. Shown to fail with the note removed.win-feedback,leaderboard-period,player-rank,leaderboard-retry,i18n-layout,board-size-hintgreen.Rollout
The SQL change is applied automatically by SQL ausrollen on merge.
🤖 Generated with Claude Code
https://claude.ai/code/session_019bNvb3PKt2h1XNZD5qGX7G
Generated by Claude Code