Skip to content

fix: show true lifetime totals in the Sessions widget#211

Merged
ntatschner merged 1 commit into
nextfrom
fix/session-lifetime-totals
Jun 29, 2026
Merged

fix: show true lifetime totals in the Sessions widget#211
ntatschner merged 1 commit into
nextfrom
fix/session-lifetime-totals

Conversation

@ntatschner

Copy link
Copy Markdown
Collaborator

Problem

The Sessions widget's summary line ("N sessions · Xh played", labelled lifetime) was computed from the session list endpoint, which caps at SESSIONS_LIST_LIMIT = 50 newest-first sessions. So the count pinned at "50" and the hours only summed the 50 newest sessions — a large undercount for anyone who's played more (reported live on v1.8.52).

Fix

Backend (query.rs): add an all_time flag to GET /v1/me/stats/playtime (new PlaytimeParams). When set, it aggregates over all history (since = None) instead of the bounded hours window (which is capped at 1 year and can't represent true lifetime). hours = 0 in the response is the all-time sentinel. The underlying total_playtime_secs(None) / count_sessions_since(None) already supported this — only the HTTP surface was missing it.

Frontend: the profile owner now fetches the all-time aggregate and the widget shows true lifetime session_count + playtime. Visitors (no me-scoped lifetime endpoint exists) fall back to the capped list, labelled N+ so the number doesn't read as exact. Summary logic extracted to a pure buildSessionSummary() with unit tests.

Scope note

Owner-first by design (per discussion). Accurate lifetime totals for visitors viewing someone else's profile would need a new handle-scoped /v1/users/{handle}/stats/playtime (sharing-auth) — deliberately deferred.

Test plan

  • cargo test -p starstats-server — new stats_playtime_all_time_includes_sessions_outside_window (counts a 60-day-old session the default window excludes) + existing playtime test pass
  • cargo clippy -p starstats-server clean; cargo fmt --check clean
  • pnpm --filter web test:run — 248 pass incl. 4 new buildSessionSummary cases (lifetime, 50+ cap label, exact count, singular)
  • pnpm --filter web typecheck + lint clean
  • OpenAPI client regenerated (all_time query param added)
  • e2e: sessions widget specs are test.skip'd (NEXT_PUBLIC_PROFILE_WIDGETS not set in playwright.config) — no drift

⚠️ Roadmap label omitted: roadmap/game-running-detection-session-metrics-anti-cheat-safe exceeds GitHub's 50-char label limit. At release time pass --roadmap-item-slug game-running-detection-session-metrics-anti-cheat-safe manually.

Roadmap-Item: game-running-detection-session-metrics-anti-cheat-safe

The widget's "N sessions · Xh played" line was computed from the session
LIST endpoint, which caps at SESSIONS_LIST_LIMIT (50) newest-first
sessions. Heavy users therefore saw the count pinned at "50" and hours
summing only the 50 newest sessions — a large undercount.

Backend: add an `all_time` flag to GET /v1/me/stats/playtime
(PlaytimeParams) so it aggregates over all history (since=None) instead
of the bounded hours window (capped at 1 year). hours=0 in the response
signals all-time.

Frontend: the profile owner now fetches the all-time aggregate and the
widget shows true lifetime session_count + playtime. Visitors (no
me-scoped lifetime endpoint) fall back to the capped list, labelled
"N+" so the number doesn't read as exact. Summary logic extracted to a
pure buildSessionSummary() helper with unit tests.
@ntatschner ntatschner merged commit e99851b into next Jun 29, 2026
11 checks passed
@ntatschner ntatschner deleted the fix/session-lifetime-totals branch June 29, 2026 21:22
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