All checks were successful
deploy / Build prerendered web (push) Successful in 4m32s
deploy / Deploy web to oolon (push) Successful in 21s
deploy / Build api + worker (static musl) (push) Successful in 5m32s
deploy / Deploy moments-worker to frootmig (push) Successful in 17s
deploy / Deploy moments-api to nikola (push) Successful in 19s
refresh / Rebuild prerendered web (push) Successful in 4m12s
refresh / Deploy refreshed web to oolon (push) Successful in 36s
The summary cards only ever counted public activity, so a period spent mostly or entirely in private repos read as near-idle — or vanished altogether — while the contribution graph directly above it showed that period as busy. The two views disagreed with no explanation on the page. `activity/summary` now emits, alongside the named per-repo rows, at most one row per period with `private = true` and a null source/repo, holding that period's private-repo change count. `source` and `repo` on `RepoPeriodCount` become nullable to carry it. The card counts it towards the period's changes but never towards its repository count (the lump covers an unknown number of repos), renders it last, unlinked, and without a language bar — a language mix would narrow the lump back down to the repo it was hiding. Not split by forge: the per-period total is already derivable from `activity/daily`, which counts private activity, so publishing it adds no information that isn't on the contribution graph already. A per-forge breakdown would be new. `?source=` does narrow the aggregate, which makes per-forge counts recoverable by diffing two requests — chosen knowingly, because a summary that contradicts the filter it was given is worse than a forge attribution on an unattributed count. `include_private` keeps its meaning: with it set, the named branch takes everything and the aggregate is empty, so a future authenticated view sees repos rather than a lump. Verified against postgres 16 with seeded public/private history: the summary now reconciles with `activity/daily` per period (3 public + 7 private = the graph's 10), a private-only period appears at all where it previously did not, no aggregate row is emitted for a period with nothing private, and the row sorts last within its period. Prerendered `/activity` against that data renders "8 changes in 1 repository + private work" with a muted `private 6` row, "4 changes in private repositories" for the private-only day, and contains zero occurrences of the private repo's name in either the markup or the dehydrated query cache. Closes #7