Skip to content

Expand /leaderboards/stats overview — players, picks, winning archetypes#265

Open
ptrlrd wants to merge 1 commit into
mainfrom
feat/leaderboards-stats-overview
Open

Expand /leaderboards/stats overview — players, picks, winning archetypes#265
ptrlrd wants to merge 1 commit into
mainfrom
feat/leaderboards-stats-overview

Conversation

@ptrlrd
Copy link
Copy Markdown
Owner

@ptrlrd ptrlrd commented May 14, 2026

Re-created after the 2026-05-14 12:42 UTC repo rollback closed the original #250.

Roadmap #4. Adds 2 totals tiles (Named players via COUNT(DISTINCT username), Cards picked via SUM(was_picked)) plus a new 'Top winning cards by character' panel (5 mini-decks, one per character, top 5 winning-deck cards each, via SQLite window function ROW_NUMBER OVER PARTITION BY character). get_stats() now returns unique_players, total_cards_picked, winning_cards_by_character. No schema change.

Roadmap #4 (post-Codex-Score). Three additions to the Overview tab:

1. Two new tiles in the totals strip:
   - Named players (DISTINCT username, excluding anonymous submissions)
   - Cards picked (SUM was_picked across run_card_choices)

2. New "Top winning cards by character" panel — five mini-decks below
   the ascension breakdown, one per character (Ironclad/Silent/Defect/
   Necrobinder/Regent), showing the five most-frequent cards in winning
   runs. Always unfiltered: the per-character grid collapses to a
   tautology if the user narrows to one character, so the panel is
   hidden when stats.filters.character is set.

3. Strip expanded from 4 to 6 tiles (Runs / Wins / Losses / Win % /
   Players / Picks). Numbers now use .toLocaleString() for thousands
   separators which become readable past 10k runs.

### Backend
get_stats() returns three new fields:
  unique_players                  — distinct non-NULL usernames
  total_cards_picked              — SUM(was_picked) from run_card_choices
  winning_cards_by_character      — { CHAR: [{card_id, count}, ...] }

The winning-cards-per-character query uses SQLite's window function:

    ROW_NUMBER() OVER (PARTITION BY character ORDER BY COUNT(*) DESC)

to pick the top 5 per character in a single query rather than 5
follow-up queries. SQLite 3.25+; the prod container is well past that.

Computed on-demand alongside the rest of get_stats — same query
budget. The aggregate ignores all WHERE filters intentionally; the
panel is a community-meta overview and the rest of the response
already gives the filtered slice.

### Frontend
StatsClient interface gains unique_players, total_cards_picked, and
optional winning_cards_by_character. OverviewTab threads `lp`
(language prefix) through props so the new card links route through
the i18n landing pages correctly.
@ptrlrd ptrlrd force-pushed the feat/leaderboards-stats-overview branch from e0c652f to 04bf8f7 Compare May 18, 2026 04:10
@ptrlrd ptrlrd added the triage label May 21, 2026
@spire-bookmark
Copy link
Copy Markdown

Pull Request Review: Expand /leaderboards/stats Overview

Summary of Changes

This PR enhances the /leaderboards/stats overview dashboard by adding two new high-level metrics and a character-specific meta-analysis panel:

  • New Metrics: Adds unique_players (count of distinct, non-anonymous usernames) and total_cards_picked (total sum of was_picked from run_card_choices).
  • Archetype Analysis: Introduces a "Top winning cards by character" panel using a SQLite window function (ROW_NUMBER() OVER PARTITION BY character) to display the top 5 most common cards in winning decks for each character.
  • UI/UX Updates:
    • Updates the OverviewTab layout to accommodate new metrics in a responsive grid.
    • Adds toLocaleString() formatting for better readability of large numbers.
    • Adds conditional rendering to hide the new meta-analysis panel when a specific character filter is active.

Technical Assessment

  • Correctness: The SQL implementation for the new metrics is sound. Using COALESCE and OR 0 prevents potential null/undefined issues in the frontend. The ROW_NUMBER() window function is an efficient way to achieve the "Top N per category" requirement in a single query.
  • Performance: The queries are well-structured. By intentionally ignoring existing filters for the "Top winning cards" section, the developer avoids creating overly complex or slow queries that might collapse into tautologies when filtered.
  • Maintainability: The changes are surgical and follow existing patterns within runs_db.py and StatsClient.tsx.

Feedback & Recommendations

  • UI Polish: The use of tabular-nums for numeric displays is an excellent detail for dashboard readability.
  • Minor Suggestion: In StatsClient.tsx, you use (stats.unique_players ?? 0).toLocaleString(). Since the backend already defaults this value to 0, the nullish coalescing operator is safe, though technically redundant if the API contract is strictly followed.
  • Verification: Ensure that CHARACTERS and CHAR_COLORS constants remain in sync with potential future character additions to avoid the "Top winning cards" grid silently excluding newer characters if they are not explicitly handled in the mapping.

Verdict: Approved. This is a clean, well-implemented enhancement that provides significant value to the community-meta tracking without introducing significant complexity or performance regressions.

@spire-bookmark spire-bookmark Bot removed the triage label May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant