Skip to content

feat(leaderboard): rebuild and restore the network leaderboard#1290

Open
Dexterity104 wants to merge 1 commit into
entrius:testfrom
Dexterity104:feat/leaderboard-rewrite
Open

feat(leaderboard): rebuild and restore the network leaderboard#1290
Dexterity104 wants to merge 1 commit into
entrius:testfrom
Dexterity104:feat/leaderboard-rewrite

Conversation

@Dexterity104
Copy link
Copy Markdown
Contributor

@Dexterity104 Dexterity104 commented May 28, 2026

Summary

Complete tear down and rebuild of the network Leaderboard, brought back at /leaderboard after the original page was deleted in #1220. The new surface feels like a control room rather than a long card list. The top of the page frames the entire network at a glance with a four zone insights card (daily pool, 90/10 split, eligibility mix, top scorers, hottest repos). The dense table below presents nine sortable columns, seven behavior driven status badges, dual track eligibility pills with per repo counts, a stacked OSS vs Discovery sparkline that opens into a 1D/7D/30D analytics modal, an open PR risk pill that mirrors the validator's slot formula, and rank movement captured locally on a UTC rotation. Every cell traces back to a concrete validator field, every tooltip carries a title, a body, and a green action hint, and every piece of UI state (cohort, repo, view mode, page) round trips through the URL.

The page is held to the bar set by #95 and grounded in the policy that has shipped since the old page came down: repository scoped emissions (gittensor#1235), per repo eligibility (gittensor#1293), per repo scoring config (gittensor#1300), the maintainer carve out and the penalized miner skip (gittensor#1292, gittensor#1329), collateral inside repo allocation (gittensor#1272), and per repo min_token_score on the PR scoring path (gittensor#1330).

Related Issues

Closes #1289
Refs #95

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Other (describe below)

Design Rationale

Information Architecture

The page is structured around three stages of attention. Glance, scan, drill. Each stage owns one component, and the components are wired so a click in one collapses the next.

  1. Glance — LeaderboardInsights. A single hero card with four zones, no chrome, no headers above it. DailyPoolZone shows the combined emissions pool in USD with live TAO and α74 spot prices, and a 90/10 split bar (miners vs issues treasury) driven by OSS_EMISSION_SHARE and ISSUES_TREASURY_EMISSION_SHARE. CompositionZone slices the network into five cohorts via cohortOf, with both the bar segments and the legend rows acting as filters into the table below. PodiumZone ranks the top three by total_score + issue_discovery_score, with avatar rails tinted in RANK_COLORS. HotRepoZone carries the hero repo plus three runners up over a rolling 30 day window, where the hero and runners up filter the table to that repo. The card is the entire "what is the network doing right now" answer.

  2. Scan — MinersLeaderTable. Dense table, list and card view modes. Nine sortable fields (score, USD/day, credibility, volume, recent activity, rank movement, review hits, open PR risk, watchlist). Debounced search, cohort and eligibility chip filters, URL backed pagination, page index reset on filter change so the user never lands on an empty page. Every row carries an accent rail in the cohort color, a status badge driven by validator state, dual track eligibility pills with per repo counts, a stacked OSS + Discovery sparkline, an open PR risk pill, and a watchlist toggle.

  3. Drill — SparklineDetailModal. Clicking a sparkline opens an ECharts modal in 1D, 7D, or 30D ranges, in stacked, bar, or line modes. 1D buckets hourly, 7D and 30D bucket daily. The modal reuses the same /commits query, so opening it costs nothing on the network.

Why This Beats A Simpler Approach

  • No policy gap. Every signal on the page maps to a validator field. The 90/10 bar is not a marketing diagram, it is OSS_EMISSION_SHARE and ISSUES_TREASURY_EMISSION_SHARE. The cohorts are not invented, they are the cross product of is_eligible and is_issue_eligible. The open PR risk pill computes its ceiling with the same formula the validator uses (min(base + floor(token_score / per_slot), max)). The page never invents a number it cannot trace.
  • One activity index, three consumers. useMinerActivityIndex builds the per miner activity map and the network roll up in a single pass over /commits. The insights card, the table, and the NetworkPulsePill share one round trip via React Query deduping. Adding a future consumer costs nothing.
  • No drift between cohort, pill, dim state, and filter. eligibilityCohort.ts is the single source of truth for "currently earning". Every component reads from isOssEligibleNow, isDiscoveryEligibleNow, isAnyEligibleNow, or cohortOf. There is no second helper that could disagree.
  • Local rank movement, no backend dependency. useRankSnapshot rotates today → prev on each new UTC day, gated on currentRanks.size > 0 so an empty load does not erase the next day's signal. Day over day deltas appear after the first 24 hours without any validator side change.
  • Status taxonomy that maps to behavior, not vibes. Seven status kinds, each tied to a concrete rule on MinerEvaluation and MinerActivity. Tooltip carries the rule verbatim, so a miner who sees Climbing can read the threshold that put them there.
  • State that survives a refresh. Cohort, repo, view mode, and page index all live in the URL. Reload the tab, paste the link, hit back, the table comes back exactly as it was.
  • Card sizes that divide cleanly. Card view rows are 12 / 24 / 48, list view rows are 10 / 25 / 50. Every grid row at every breakpoint is full so the last row is never partial.

Screenshots

Video:

1.webm
2.webm

Desktop 1:
1

Desktop 2:
2

Desktop 3:
3

Desktop 4:
4

Desktop 5:
5

Mobile 1:
m1

Mobile 2:
m2

Mobile 3:
m3

Mobile 4:
m4

Validator Policy Mapping

Every field on screen has a concrete source. The page never invents a number it cannot trace.

What the page shows Where it comes from
Daily emissions pool in USD parseNumber(m.usdPerDay) summed across EARNING_COHORTS
90/10 split bar OSS_EMISSION_SHARE, ISSUES_TREASURY_EMISSION_SHARE
TAO + α74 spot prices usePrices()
Eligibility cohort cohortOf(m) over is_eligible, is_issue_eligible, eligible_repo_count, issue_eligible_repo_count
Top scorers podium parseNumber(m.totalScore) + parseNumber(m.issueDiscoveryScore)
Hottest repos (30d) /commits grouped by commit.repository, sorted by count
Penalized badge m.failedReason (verbatim in tooltip)
Per track eligibility pills with repo count is_eligible, is_issue_eligible, eligible_repo_count, issue_eligible_repo_count
OSS vs Discovery split sparkline /commits + isDiscoveryCommit (mirrors isIssueDiscoveryContributionPr)
Open PR risk pill min(openPrSlotBase + floor(tokenScore / openPrSlotTokenScore), maxOpenPrSlots), defaults from ELIGIBILITY_FIELD_DEFS
Earnings split (OSS vs Discovery, tooltip) splitEarnings mirrors the validator OSS/Discovery share split
Review hit count N = round((1 − review_quality_multiplier) / 0.15), REVIEW_PENALTY_RATE = 0.15
Day over day rank movement useRankSnapshot, localStorage[gittensor.rank-snapshot.v1] rotated per UTC day
Network Pulse pill (7d vs prior 7d) Network roll up from useMinerActivityIndex

Status Taxonomy

Seven status kinds plus STATUS_NONE. Order of resolution matches deriveMinerStatus in MinerStatus.tsx.

Status Trigger Tone
Penalized failed_reason non empty MINER_STATUS_COLORS.penalized
Hot ≥ 3 merged in last 3d MINER_STATUS_COLORS.hot
Climbing Rank improved by ≥ 3 since the last UTC snapshot MINER_STATUS_COLORS.climbing
Rising Last 7d ≥ 3 merged and ≥ 1.5 × prior 7d MINER_STATUS_COLORS.rising
Dormant No merges in last 14d MINER_STATUS_COLORS.dormant
Specialist ≤ 2 unique repos and ≥ 5 merges MINER_STATUS_COLORS.specialist
Dual Eligible in both OSS and Discovery in at least one repo MINER_STATUS_COLORS.dual
Cooling Last 7d zero, prior 7d non zero MINER_STATUS_COLORS.cooling

URL Contract

Param Driver Behavior
?repo=<full_name> Hot repos card, repo column click Clears ?page= on change
?cohort=<dual|ossOnly|discoveryOnly|activeOnly|inactive> Eligibility mix bar + legend, cohort chip Validated via parseCohortParam, clears ?page=
?view=<list|cards> View mode toggle Mirrored to localStorage[leaderboard:viewMode]
?page=<n> Pagination Reset on any filter change
?sort=<field>:<dir> Sortable column headers Driven by the existing useDataTableParams hook

Testing

  • Manual testing performed against the test API
  • Tested on desktop viewport
  • Tested on mobile viewport (Chrome DevTools)
  • Empty network state checked (no scored miners, no merged PRs in the window)
  • Single miner state checked (podium collapses to one row, eligibility bar still renders)
  • Penalized row checked (badge present, tooltip carries failed_reason verbatim)
  • Cohort filter round trips through ?cohort=, repo filter through ?repo=, view mode through ?view=, pagination through ?page=
  • Rank snapshot rotates on a forced UTC day change (system clock advanced in dev)
  • Sparkline modal cycles 1D / 7D / 30D and stacked / bar / line without churn
  • Watchlist toggle keyboard focus state covered (WatchlistButton focus-visible outline)
  • Long tooltip body clamps to the viewport at xs (Network Pulse pill on a 320px wide screen)
  • npm run build passes
  • npm run lint:fix and npm run format clean

Checklist

  • New components are modularized/separated where sensible
  • Uses predefined theme (TOOLTIP_TONE_COLORS, LEADERBOARD_TRACK_COLORS, MINER_STATUS_COLORS, STATUS_COLORS, RANK_COLORS, no hardcoded colors)
  • Responsive/mobile checked (xs stacked hero card, sm two by two zones, lg four across, card view rows divide evenly by 1/2/3 so the last grid row is never partial)
  • Tested against the test API
  • npm run format and npm run lint:fix have been run
  • npm run build passes
  • Screenshots included for any UI/visual changes

Changes

New Pages

  • LeaderboardPage (src/pages/LeaderboardPage.tsx). Hosts the insights card and the table. Pipes ?repo= and ?cohort= into useSearchParams. Resets ?page= whenever a filter changes so the user never lands on an empty page after narrowing the view.

New Components

  • LeaderboardInsights (src/components/leaderboard/LeaderboardInsights.tsx). Four zone hero card. DailyPoolZone carries the USD pool, the TAO/α74 ticker, the 90/10 emission split bar, and the top earners avatar stack. CompositionZone is the cohort bar plus an interactive legend that doubles as a filter. PodiumZone is the top three by combined score with rank tinted avatar rails. HotRepoZone is the hero repo plus three runners up, all clickable into the table filter.
  • MinersLeaderTable (src/components/leaderboard/MinersLeaderTable.tsx). List and card view modes, nine sortable fields, cohort and eligibility chip filters, debounced search, URL backed pagination. Row accent rail in the cohort color, identity cell with status badge, dual track eligibility pills with repo counts, OSS and Discovery stat rows with a stacked sparkline trend, open PR risk pill, review hits cell, USD/day cell with a track split tooltip, watchlist toggle.
  • MinerStatus (src/components/leaderboard/MinerStatus.tsx). Seven status kinds plus STATUS_NONE. deriveMinerStatus resolves them in priority order against MinerEvaluation and MinerActivity. StatusBadge renders the pill in the tone palette from MINER_STATUS_COLORS.
  • Sparkline (src/components/leaderboard/Sparkline.tsx). Stacked bar sparkline (OSS bottom, Discovery on top), built from raw SVG to avoid pulling a chart library into the row hot path. Empty state collapses to a single dash so the row height stays stable.
  • SparklineDetailModal (src/components/leaderboard/SparklineDetailModal.tsx). ECharts modal with 1D, 7D, 30D ranges and stacked / bar / line modes. Hourly bucketing on 1D, daily bucketing on 7D and 30D. Uses the shared gittensor ECharts theme so the modal matches the rest of the app.
  • NetworkPulsePill (src/components/leaderboard/NetworkPulsePill.tsx). 7d vs prior 7d PR velocity. Low sample mode (prior7 < 5) renders raw counts instead of a misleading percentage.
  • GhIcons (src/components/leaderboard/GhIcons.tsx). Inline GitHub PR and Issue SVG icons, sized for the dense row layout.

New Modules

  • eligibilityCohort.ts (src/components/leaderboard/eligibilityCohort.ts). Single source of truth for "currently earning". Exports isOssEligibleNow, isDiscoveryEligibleNow, isAnyEligibleNow, isPenalized, cohortOf, the cohort palette, labels, descriptions, and the parseCohortParam URL guard.
  • scoring.ts (src/components/leaderboard/scoring.ts). Mirrors gittensor/constants.py and validator/oss_contributions/scoring.py. resolveRepoThresholds overlays ELIGIBILITY_FIELD_DEFS defaults. openPrSlotsAllowed mirrors calculate_open_pr_threshold. splitEarnings mirrors the OSS / Discovery share split.
  • useMinerActivityIndex.ts (src/components/leaderboard/useMinerActivityIndex.ts). One pass over /commits builds the per miner activity map and the network roll up. Per miner: dailyMerged, dailyOss, dailyDiscovery, topRepos, lastActiveAt, reviewHits. Network: dailyMerged, dailyOss, dailyDiscovery, last7, prior7, topRepos.
  • useRankSnapshot.ts (src/components/leaderboard/useRankSnapshot.ts). Rotates yesterday's ranks into prev on each new UTC day, gated on currentRanks.size > 0 so an empty load does not erase tomorrow's signal. Stored under localStorage[gittensor.rank-snapshot.v1].
  • leaderboardViewMode.ts (src/components/leaderboard/leaderboardViewMode.ts). List and card view modes, persisted to localStorage[leaderboard:viewMode], reflected in ?view=. List rows are 10 / 25 / 50, card rows are 12 / 24 / 48 so every grid row at every breakpoint is full.

Refactored Components

  • WatchlistButton (src/components/common/WatchlistButton.tsx). Picks up a focus-visible outline in the primary color so keyboard navigation has parity with hover. No regression on existing call sites.

Modified Wiring

  • routes.tsx. /leaderboard registered. /top-miners redirect repointed from /repositories to /leaderboard so existing external links land in the right place.
  • layout/Sidebar.tsx. leaderboard nav item with the MUI LeaderboardIcon, sandwiched between dashboard and repositories.
  • api/DashboardApi.ts. useRecentCommits(limit = 500) thin wrapper around the existing dashboard query helper, hits /commits?page=1&limit=500. React Query dedupes the request so the insights card and the table share one round trip.
  • theme.ts. New palette tokens (TOOLTIP_TONE_COLORS, LEADERBOARD_TRACK_COLORS, MINER_STATUS_COLORS) move the cohort, status, and tooltip tones to one place. tooltipSlotProps picks up a preventOverflow popper modifier so long tooltip bodies clamp to the viewport on narrow screens, and maxWidth becomes responsive (calc(100vw − 24px) on xs, 280px from sm).
  • leaderboard/index.ts. New barrel exports for LeaderboardInsights and MinersLeaderTable.
  • .gitignore. Adds .verify so local verification scratch directories do not get committed.

Removed Components

None. The old TopMinersPage and its sidecars were already removed in #1220 and are not resurrected.

Bug Fixes

  • None new. The rebuild starts from a clean slate, so there are no carryover bugs from the deleted page to chase.

Known Gaps (Documented, Not Fixed Here)

  • /commits represents OSS merges only. Discovery only activity is undercounted in the sparkline and in the Dormant / Cooling derivation until the activity feed includes solved issues. Cohort assignment itself is correct because it reads is_eligible and is_issue_eligible straight off MinerEvaluation.
  • Per track $/day split and the structural vs leaf score breakdown are not surfaced yet. Both are blocked on validator data that is not on the public API. The combined usdPerDay is used everywhere a per row earning is shown.

@xiao-xiao-mao xiao-xiao-mao Bot added the feature Net-new functionality label May 28, 2026
@Dexterity104
Copy link
Copy Markdown
Contributor Author

@e35ventura @anderdc
Could you please check this PR and give me any feedback?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bring back the network Leaderboard, rebuilt around per repository emissions and dual track eligibility

1 participant