profile aggregation
Almost all of this is comments in ProfilePage.tsx. Those comments are the spec.
Split worlds#
GitHub stats.totalSolved is commits. Coding cards drive “problems solved.” Dev cards never enter that sum. UI copy: commits and pull requests are engineering output, never mixed into problems solved.
Ledgers#
- Problem solving: solved + contests
- Engineering: commits + PRs (
fetchGitHubEngineering, not the card) - Consistency: active days summed. Best/current streak is max across platforms, not a merged calendar streak
Difficulty band#
Not three circular gauges on /profile. A segmented band of easy/medium/hard from stats.byDifficulty. Circular meters (DifficultyMeter) are for per-platform pages.
Languages vs topics#
- GitHub
topicAnalysisis language percentages. Averaged across accounts that have data. Private-repo accounts with zeros are dropped so they do not dilute. - Coding
topicAnalysisis problem counts, merged, top 14. Dev cards excluded on purpose.
Rating lines#
Prefer rating.history. If contest history is longer, use that. One contest is a single point. Filter: contests.rating != null || contests.rank.
Radar#
Needs at least 3 coding platforms. Competitive axes = rating (max if stacked accounts). DSA axes = solved (sum if stacked). Each family normalized to its own max so 2000 rating does not crush 165 solved.
Heatmap merge#
Card heatmaps are fetched as full history (view=all). Source toggle: all | coding | github. Range: last 365 or a calendar year. Merge is sum of counts per date. Hover breakdown keeps {platform, username, count}. Levels are fixed buckets 1 / 3 / 6 / 10, not per-max quartiles.
UniversalHeatmap on deep dives is a different widget: local ymd() to avoid UTC off-by-one, GitHub year-keyed calendars, quartile levels. Do not describe one heatmap as if there were only one.
Chart sizing#
MeasuredChart uses ResizeObserver because Recharts ResponsiveContainer measures 0 under React 19 StrictMode double-mount.
Share#
Long URL = window.location.href. Short URL = upsert primary config, copy /{claimedUsername}. There is no /s/:code anymore. The drop migration removed short_links. The reserved-name widen stayed.