Skip to content

Spike: Leaderboard SVG rendering strategy #1

@Z-M-Huang

Description

@Z-M-Huang

Context

The leaderboard feature (v0.3.0) stores a registry of users in a public gist and each user's public profile in their own public gist. The CLI cc-proficiency leaderboard command fetches N+1 gists (1 registry + N profiles) and displays a text table.

We want to render a leaderboard SVG that can be embedded in READMEs, hosted in the registry gist alongside cc-proficiency-registry.json.

Open Questions

1. GitHub API Rate Limits

  • Unauthenticated: 60 requests/hour
  • Authenticated (PAT): 5,000 requests/hour
  • With 50 users, each render = 51 API calls
  • At 30-min intervals: 102 calls/hour (within PAT limit, but scales poorly)
  • At what user count does this break? ~98 users hits the 5k/hour limit at 30-min intervals

2. Rendering Options

Option How Pros Cons
A. N+1 gist reads Scheduled Action fetches each profile gist, renders SVG Simple, uses existing infrastructure O(N) API calls per render, rate limit ceiling
B. Pre-aggregated leaderboard.json Each user's mergeAndPush also pushes their scores to a central "scores" gist (append-only) 1 API call to read all scores Requires write access to central gist from every user (not possible without shared token)
C. Webhook on public gist update GitHub doesn't support gist webhooks N/A Not possible
D. Users push scores to registry via Issue Extend join Issue to include scores, or add periodic "update" Issues Central aggregation, no N reads More Issues, more Action runs, complex parsing
E. Static site (GitHub Pages) Action builds HTML page with embedded data, deploys to Pages Rich interactivity, no SVG size limits Needs a separate repo or branch, more infra
F. Single aggregated JSON in registry gist The registration Action also reads the user's profile and stores scores inline in registry.json 1 API call for leaderboard render (just read registry) Registration Action becomes heavier, scores stale until next join/leave
G. Scheduled Action aggregates into registry gist Every 30 min, Action reads N profiles, writes leaderboard.json + SVG to registry gist Decouples aggregation from rendering Still O(N) reads, but only in the Action

3. Recommended Investigation

  1. Confirm exact GitHub API rate limits for gist reads via PAT on self-hosted runner
  2. Prototype Option G (simplest v1) with 5-10 test users
  3. Measure actual latency and API call count
  4. If rate limits become an issue, migrate to Option F (inline scores in registry.json, updated by the registration Action + a periodic "refresh" Action that reads profiles in batches)

4. SVG Design Questions

  • Top 20 users, dark theme matching badge style
  • Dimensions: ~600px wide, ~500px tall (20 rows)
  • Show: rank, username, average score, 5 domain scores
  • Highlight: streaks, achievement counts?
  • Update frequency: every 30 minutes (or on registry change + scheduled)

Acceptance Criteria

  • Research confirmed: GitHub API rate limits documented for our use case
  • Recommended rendering strategy chosen with justification
  • Prototype SVG renderer (src/renderer/leaderboard-svg.ts)
  • Scheduled workflow (.github/workflows/leaderboard-render.yml)
  • Embeddable URL documented

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions