Repository navigation
[LOW] Points are monotonically increasing with no decay or penalty — the leaderboard is a permanent, stale ranking #24
Description
Activity
- addeddesign-flawArchitectural design flawArchitectural design flawleaderboardLeaderboard contractLeaderboard contract
on Aug 16, 2026 - addedGrantFox OSSIssue tracked in GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignCampaign: Third Campaign
on Aug 16, 2026 Dayz-tech-co commented
on Aug 16, 2026 ContributorMore actionsApplication for SPulse Issue #24
I’d like to take on this issue because I understand that the underlying problem is not simply that points need to be decremented. The current points model is fundamentally cumulative, which makes the leaderboard represent historical activity rather than a player’s current performance.
My approach would therefore be to redesign the ranking semantics around a rating model that can change in both directions, while preserving the integrity of the existing leaderboard and reward flows.
Proposed approach
I would first trace the complete lifecycle of the current points system, particularly:
- "s.points += points"
- "reward"
- "add_pts"
- "reward_bonus"
- "add_bonus_pts"
- "LOSE_POINTS"
- the existing "upsert_top" logic and its min-cache invariant
- all leaderboard read/write paths and any assumptions that points are monotonically increasing.
From there, I would introduce a rating model rather than attempting to patch the existing cumulative counter.
The exact model should be selected based on the game's existing mechanics and available player/match data. If the existing data supports meaningful head-to-head outcomes, an ELO-style rating would be appropriate. If the system's existing events are better represented by activity over time, a time-decayed rating can be used instead.
The important property is that a player's effective rating must be allowed to increase or decrease, while the leaderboard calculation must always be derived from the current rating rather than historical cumulative points.
Leaderboard/cache redesign
I would also address the issue's "upsert_top" constraint rather than bypassing it.
Because the current implementation assumes scores only increase, allowing ratings to decrease means the existing min-cache approach can no longer be treated as authoritative.
I would therefore redesign the leaderboard update/recompute path so that:
- A player's rating can move in either direction.
- A rating decrease cannot leave stale entries in the top-ranking cache.
- Rankings are recomputed or invalidated when an update can affect the cached top set.
- Ranking order remains deterministic for equal ratings.
- Existing state is migrated safely without silently converting historical points into an invalid rating.
Migration and backwards compatibility
I would avoid destructively changing the existing points field without understanding every consumer of it.
Where necessary, I would separate the concepts of:
- historical/cumulative points
- current competitive rating
- leaderboard rank
This allows historical rewards/activity to remain meaningful while the leaderboard reflects current performance.
For existing users, I would define and test a deterministic migration/initial-rating strategy rather than arbitrarily assigning new ratings.
Testing
I would add tests covering the actual failure mode described in the issue, including:
- a player gaining rating;
- a player losing rating;
- repeated losses;
- repeated wins;
- inactive players and time-based decay, if decay is selected;
- players overtaking previously active players;
- equal ratings/tie handling;
- leaderboard updates when a player falls out of the cached top set;
- leaderboard updates when a previously lower-ranked player rises into the top set;
- stale-cache prevention;
- migration of existing player data;
- preservation of unrelated reward functionality.
I would also verify that the new implementation does not accidentally reintroduce the monotonic-score assumption elsewhere in the contract/application.
Delivery
I would work incrementally: first understanding and documenting the existing ranking flow, then implementing the rating model, then replacing the incompatible cache assumptions, followed by migration and comprehensive tests.
I would keep the changes focused on the issue and avoid unrelated refactors so the resulting PR remains reviewable.
The main goal is not simply to make points decrease. It is to make the leaderboard actually represent current competitive performance, which is the root problem identified in this issue.
grantfox-oss commented
on Aug 16, 2026 grantfox-ossboton Aug 16, 2026 – with GrantFox OSSMore actions🦊 GrantFox — @Dayz-tech-co has been assigned to this issue as part of the Third Campaign campaign!
Next steps:
- Open a Pull Request referencing this issue (e.g.,
Closes #24) - Your PR will be reviewed by the SPulse-Org maintainers
Good luck! Track your progress on GrantFox.
- Open a Pull Request referencing this issue (e.g.,
- added a commit that references this issue
on Aug 24, 2026 Status update from PR #185:
- Decay (the "permanent, monotonic ranking" complaint) was fixed by PR feat(leaderboard): time-weight points so a ranking reflects activity (#69) #150 (issue [LOW] Points are monotonically increasing with no decay or penalty — the leaderboard is a permanent, stale ranking #69), merged 2026-08-22 — already on
main. Seeleaderboard/src/decay_tests.rs, e.g.test_idle_leader_is_overtaken_by_a_newer_player_who_earned_far_less. - A real way to reduce points / penalize a loss: added in fix(leaderboard+prediction_market): repair builds, add penalize() + CI (#24, blocked on referral_registry) #185 —
penalize(caller, user, pts)on the leaderboard contract. Market-gated, decay-aware, saturates at zero, 14 tests, safe against the top-list invariants (can't be used to insert an unranked player or evict a ranked one on their behalf). - Not yet done: wiring that into
prediction_market's actual loss-settlement path (LOSE_POINTS), so losers still gain positive points fromprediction_markettoday. Blocked onprediction_marketitself, which currently does not compile onmain— I found three separate, unrelated defects while investigating (an unclosedget_governor_countbody, four undefined-variable errors near aconfig_changedevent at line 476, and aget_ttlcall that doesn't exist on this SDK'sPersistentstorage type). That's independent of this issue and too large/risky to fold into fix(leaderboard+prediction_market): repair builds, add penalize() + CI (#24, blocked on referral_registry) #185.
Leaving this issue open rather than closing it via #185 — closing it should wait until
prediction_marketis repaired and actually wired topenalize(). Happy to pick up theprediction_marketbuild repair as a separate PR if that's useful; the tokenomics decision (does the existing 2-token consolation prize for losing stay as-is?) is a maintainer call either way.- Decay (the "permanent, monotonic ranking" complaint) was fixed by PR feat(leaderboard): time-weight points so a ranking reflects activity (#69) #150 (issue [LOW] Points are monotonically increasing with no decay or penalty — the leaderboard is a permanent, stale ranking #69), merged 2026-08-22 — already on
- added 4 commits that reference this issue
on Aug 27, 2026 - added a commit that references this issue
on Aug 31, 2026 grantfox-oss commented
on Aug 31, 2026 grantfox-ossboton Aug 31, 2026 – with GrantFox OSSMore actions🎉 This issue has been marked as completed on GrantFox!
@Dayz-tech-co's PR #185 was approved and merged by @Muyideen-js.
🏆 @Dayz-tech-co: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (357 total points). Track your full progress on GrantFox.
👏 Great work, @Dayz-tech-co! Keep contributing to SPulse-Org.
- added a commit that references this issue
on Aug 31, 2026
[LOW] Points are monotonically increasing with no decay or penalty — the leaderboard is a permanent, stale ranking
Summary
Points in the leaderboard only ever increase (
s.points += pointsinreward,add_pts,reward_bonus,add_bonus_pts). There is:LOSE_POINTS).This means the leaderboard is a monotonic, permanent ranking — early adopters who accumulated points long ago can never be overtaken by newer, more active players unless the newer players out-earn them in absolute terms forever. The ranking does not reflect current skill or activity, only cumulative historical points.
Why it's unsolvable by a localized patch
upsert_toplogic (issue Systemic accounting & state-invariant violation across prediction_market ↔ referral_registry ↔ leaderboard — fee theft, leaderboard displacement, and unbounded inflation #1) assumes points only increase; any decay/penalty breaks the min-cache invariant and would require a full recompute.The root problem is the points model is a cumulative counter, not a skill rating. A correct fix requires a decayed or Elo-style rating system — a fundamental redesign of the leaderboard semantics.