fix: derive leaderboard stats from recorded activity instead of a seed (#671) - #676
Open
MOHITKOURAV01 wants to merge 2 commits into
Open
fix: derive leaderboard stats from recorded activity instead of a seed (#671)#676MOHITKOURAV01 wants to merge 2 commits into
MOHITKOURAV01 wants to merge 2 commits into
Conversation
A first-time visitor was told they had filed 2 reports, had 1 verified, answered
55 quizzes and earned 125 points. It was a hardcoded seed, presented in the first
person — "Your Rank", "(You)" — with nothing marking it as a placeholder, and
nothing a user could check it against.
The panel also invented a storage key of its own, pollution-hub-user-points, that
nothing else in the codebase writes to. Filing a real report in the Community Hub
did not move the total; nor did earning challenge points, nor answering quizzes.
src/utils/contributionStats.js derives the figures from the keys the rest of the
app already maintains — pollution-community-reports, pollution_hub_total_points —
plus a quiz-answer count it maintains itself from QUIZ_COMPLETED, since nothing
persisted one before. Derived rather than accumulated: a stored total can drift
from the activity it summarises, and there is no way to tell once it has.
The three "Simulate Action" buttons rendered unconditionally in production, so
any visitor could click +50 Verified Report and persist a verified report that
was never submitted. Between those and the seed, no number on this panel
corresponded to anything. What remains is dev-only and writes through the real
recording path.
Also:
- rows keyed on user.name, so a stored name matching a mock entry produced
duplicate React keys and one row silently won; keyed on id now
- "Your Rank #0" on first paint, from findIndex(...) + 1 on an empty list
- localStorage.setItem called inside a setState updater — unguarded against
quota errors, and impure, so StrictMode wrote twice
- mock contributors now carry a "sample" label, and the panel says plainly
that there is no shared backend behind the board yet
|
@MOHITKOURAV01 is attempting to deploy a commit to the Aditya Mahajan's projects Team on Vercel. A member of the Team first needs to authorize it. |
Thank You for Your Contribution! 🎉Hi @MOHITKOURAV01, Thank you for opening this Pull Request and contributing to our project. We truly appreciate your efforts.
The maintainer @Aditya8369 will review your PR shortly! Happy Contributing! 🚀 |
Owner
|
@MOHITKOURAV01 thanks for the contributions |
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.
Closes #671
The problem
Open the app for the first time and the Contributor Leaderboard tells you:
None of it happened.
It is presented in the first person — "Your Rank", "(You)", "Current User" — with nothing marking it as a placeholder, and ranked against five fictional people using those figures. This repo has consistently treated invented values shown as measurements as bugs rather than acceptable placeholders (#499, #544, #546, #496). This is the same thing pointed at the user's own contribution history, where they have nothing to check it against.
It ignored the activity the app actually records
Leaderboardinvented a storage key of its own,pollution-hub-user-points, that nothing else in the codebase ever writes to:pollution-community-reportspollution_hub_total_pointsQUIZ_COMPLETEDon the busFile a report in the Community Hub — total does not move. Earn 10 challenge points — does not move. The only thing that moved it was the simulator below.
The fix
src/utils/contributionStats.jsderives the stats from the keys the rest of the app maintains, weighted by thePOINT_SYSTEMthe component already declared at the top of the file. The weights now live in the scoring module and the table renders from them, so the "How to Earn Points" legend and the arithmetic cannot drift apart.Derived, not accumulated. A stored running total can drift from the activity it is meant to summarise, and once it has there is no way to tell.
One thing genuinely was not recorded anywhere: how many quiz questions have been answered.
QUIZ_COMPLETEDcarriesscoreandtotalbut nothing persisted a count —achievementsStoreonly keeps the set of perfect quiz ids. The module maintains that counter itself, and it countstotalrather thanscore: a 10-question quiz scored 3/10 is still 10 answers.It self-registers on import, matching
achievementsStore, andApp.jsximports it for the side effect — a quiz can be completed without the leaderboard ever having been mounted.The simulator
No
import.meta.env.DEVguard, no dev-mode check — these rendered for every visitor, at the bottom of the panel. Clicking one persisted a verified report that was never submitted. Between these and the seeded starting figures, no number on this panel corresponded to anything.What remains is dev-only and writes through the same recording path the app uses, rather than incrementing a display total directly.
Four smaller defects in the same component
key={user.name}. Names are not unique keys. A storeduserStats.namematching a mock entry ("Priya Singh") produced duplicate React keys and one row silently won. Keyed onid.findIndex(...) + 1on the empty array the state starts as. Renders—until there is a rank.localStorage.setIteminside asetStateupdater. Unguarded against quota errors, so the throw came from inside a React state update — and the updater was impure, so StrictMode ran it twice and wrote twice.samplechip now, and the panel says plainly that there is no shared backend behind the board yet ([Architecture]: Community Reports are localStorage-only — not actually shared between users; add backend + Hotspot Aggregation & Escalation #152).Tests
src/utils/contributionStats.test.js(22) — each source counted and weighted, the combined total,Verified-prefixed statuses as CommunityHub actually writes them, corrupt/NaN/negative storage in every key,localStoragethrowing, and the quiz listener counting questions rather than correct answers.src/components/Leaderboard.test.jsx(13) — zeros for a new visitor, explicit assertions that the old seeded figures are gone, the ranking moving with a real total, sample labelling, a stable-key row count, and that the simulator is absent from a production build.Suite status
Re-verified against current
main(575e33b), which now carries #672–#675: merges cleanly, 548 passed, 0 failed across 54 files.(The earlier note here referred to 6
Commute.test.jsxfailures inherited frommain. #672 has since merged and fixed them.)Migration
pollution-hub-user-pointsis no longer read or written, and is not migrated — the values in it were either the fabricated seed or simulator clicks, and there is no honest way to convert either into a real record. Existing reports and challenge points are picked up immediately. The quiz counter starts at zero, since nothing was ever stored to recover.