Follow-up to #9984. That issue was closed, but it only patched the UI — the underlying data is still broken.
What's wrong
The Longest Visit Streak → Active list on https://roadmap.sh/leaderboard is meant to show the top 10 users. But two of those 10 rows are duplicates of users who already appear higher up. So the list shows 10 rows but only 8 distinct people.
API: GET https://api.roadmap.sh/v1-list-leaderboard-stats → streaks.active
Why the duplicates happen
Some streaks are frozen: the streak ended, but its row stays in the list with its last value and never changes. The same user also has a second, live row. That duplicate user.id is exactly what #9984 spotted — but #9984 only fixed the React key in the UI. The dead rows are still in the data, so they still take up slots and still push real users out of the top 10.
Proof — 3 snapshots
A live streak grows by +1 every day. A frozen one doesn't move at all. Brofy is the control (single row, no duplicate).
| User |
May 18 |
Jun 10 |
Jun 11 |
Verdict |
| Brofy (control) |
152 |
175 |
176 |
live (+1/day) |
| Lost (live) |
151 |
175 |
176 |
live |
| IgorLutiy (live) |
— |
175 |
176 |
live |
| Lost (ghost) |
158 |
158 |
158 |
frozen |
| IgorLutiy (ghost) |
379 |
379 |
379 |
frozen |
Both ghost rows haven't moved across 3 snapshots / 24 days, while every live row grew by exactly +1/day. Note: the current #1 in Active is IgorLutiy 379 — a dead streak.
Raw streaks.active — 2026-06-11T09:35:20Z (10 rows, 8 unique users)
379 IgorLutiy (6712dee6791f57dd60d309cd) <- frozen, ghost
221 Allano Alberto (6588a30a54b577105138fe61)
209 Kishore Y (65026ae83ee87ab4ca51b71e)
192 Mark Nassef (692b0cf8bd486ea4602db1d7)
176 Lost (679b590f31e842a9fc848267) <- live
176 Brofy (6761b41e8fe51199dac494b4) <- control
176 IgorLutiy (6712dee6791f57dd60d309cd) <- live (dup of row 1)
171 Sandesh Hegde (6583013d5145316d2533c340)
158 Lost (679b590f31e842a9fc848267) <- frozen, ghost (dup of row 5)
156 Niuempai_oficial (668d9eff8896c6f50b2e1034)
Raw streaks.active — 2026-06-10T17:50:41Z
379 IgorLutiy 379 (frozen)
220 Allano Alberto
208 Kishore Y
192 Mark Nassef
175 Lost (live)
175 Brofy (control)
175 IgorLutiy (live, dup)
170 Sandesh Hegde
158 Lost (frozen, dup)
155 Niuempai_oficial
Suggested fix (backend)
When building active, drop any streak whose last visit is older than today (minus a grace day), and pick the current row per user_id — not the one with the max count. That removes the frozen rows and the duplicates in one go, and the list goes back to 10 real users.
A naive dedup by max count would make it worse: it would keep the frozen 158 over the live 176 for Lost, and the dead 379 over the live 176 for IgorLutiy.
UPD 2026-07-07 — the "slot theft" framing is wrong; the real bug is missing dedup by user_id
Fresh streaks.active: 10 rows, 9 unique users. Only one duplicate left — IgorLutiy (379 frozen + 201 live). The Lost 158 ghost is gone.
Why it's gone: it wasn't fixed. Over 26 days live streaks grew ~+1/day, the top-10 cutoff rose to exactly 158 (now Jinx at #10), and Lost's frozen 158 fell below the boundary and dropped out. So frozen rows self-eject once live streaks climb past their value — they don't steal slots forever. Only an anomalously high frozen value persists (IgorLutiy 379 stays #1 regardless).
| User |
Jun 11 |
Jul 07 |
|
| IgorLutiy (ghost) |
379 |
379 |
still #1 |
| IgorLutiy (live) |
176 |
201 |
+1/day |
| Lost (live) |
176 |
201 |
+1/day |
| Lost (ghost) |
158 |
— |
dropped past cutoff 158 |
Takeaway: the persistent defect isn't "frozen rows linger" — it's that the top-10 is selected without GROUP BY user_id, so one user takes two slots. 379 provably isn't the current streak (unchanged across 3 snapshots while an active streak must grow +1/day; current is 201). The fix stands — dedup by user_id, keep the current row (not max(count)) — but the lever is the grouping, not a last-visit date filter.
Follow-up to #9984. That issue was closed, but it only patched the UI — the underlying data is still broken.
What's wrong
The Longest Visit Streak → Active list on https://roadmap.sh/leaderboard is meant to show the top 10 users. But two of those 10 rows are duplicates of users who already appear higher up. So the list shows 10 rows but only 8 distinct people.
API:
GET https://api.roadmap.sh/v1-list-leaderboard-stats→streaks.activeWhy the duplicates happen
Some streaks are frozen: the streak ended, but its row stays in the list with its last value and never changes. The same user also has a second, live row. That duplicate
user.idis exactly what #9984 spotted — but #9984 only fixed the Reactkeyin the UI. The dead rows are still in the data, so they still take up slots and still push real users out of the top 10.Proof — 3 snapshots
A live streak grows by +1 every day. A frozen one doesn't move at all. Brofy is the control (single row, no duplicate).
Both ghost rows haven't moved across 3 snapshots / 24 days, while every live row grew by exactly +1/day. Note: the current #1 in Active is
IgorLutiy 379— a dead streak.Raw
streaks.active— 2026-06-11T09:35:20Z (10 rows, 8 unique users)Raw
streaks.active— 2026-06-10T17:50:41ZSuggested fix (backend)
When building
active, drop any streak whose last visit is older than today (minus a grace day), and pick the current row peruser_id— not the one with the maxcount. That removes the frozen rows and the duplicates in one go, and the list goes back to 10 real users.A naive dedup by max
countwould make it worse: it would keep the frozen158over the live176for Lost, and the dead379over the live176for IgorLutiy.UPD 2026-07-07 — the "slot theft" framing is wrong; the real bug is missing dedup by
user_idFresh
streaks.active: 10 rows, 9 unique users. Only one duplicate left — IgorLutiy (379frozen +201live). The Lost158ghost is gone.Why it's gone: it wasn't fixed. Over 26 days live streaks grew ~+1/day, the top-10 cutoff rose to exactly 158 (now Jinx at #10), and Lost's frozen
158fell below the boundary and dropped out. So frozen rows self-eject once live streaks climb past their value — they don't steal slots forever. Only an anomalously high frozen value persists (IgorLutiy379stays #1 regardless).Takeaway: the persistent defect isn't "frozen rows linger" — it's that the top-10 is selected without
GROUP BY user_id, so one user takes two slots.379provably isn't the current streak (unchanged across 3 snapshots while an active streak must grow +1/day; current is201). The fix stands — dedup byuser_id, keep the current row (notmax(count)) — but the lever is the grouping, not a last-visit date filter.