Make SERVER_TIMEZONE authoritative for streaks, coach, and day boundaries#219
Merged
Merged
Conversation
…ries The coach was reporting time in UTC and pulling rollups on UTC day boundaries, and the streak headline could read 0 while the breakdown showed on-track days. Root causes: - llm_client injected "Current date/time (UTC)" into every LLM call, so the coach narrated the wrong evening date. Now injects the configured SERVER_TIMEZONE clock. - coach query_nutrition_rollup and coach_context logging-consistency grouped by hardcoded UTC days; goals/profile_sync bucketed daily biometric totals by UTC even though their window was server-local. All now bucket in SERVER_TIMEZONE. - /today and /today/streak-history (plus water and health "taken today") honored a client tz hint from the browser, overriding the configured server timezone. They now always use SERVER_TIMEZONE; the frontend no longer sends a tz param and derives "Today" from the server date. - The /today headline streak added *today's* supplement nutrients to *every* historical day, flipping earlier days off-track and contradicting the per-day breakdown. Supplements are now credited to the day they were logged, mirroring /today/streak-history. https://claude.ai/code/session_01NhMPok8EUdmK9o7pDKEx4a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two timezone symptoms were reported:
SERVER_TIMEZONEis documented as the single source of truth for calendar-day boundaries (.env.example), but several paths ignored it.Root causes & fixes
Coach reporting UTC
llm_client._inject_current_datetimeprependedCurrent date/time (UTC): …to every LLM call usingdatetime.now(UTC). → Now injects the configuredSERVER_TIMEZONEclock (with%Z).Coach / rollups pulling UTC days
coach.query_nutrition_rollupgrouped + filtered by hardcodedAT TIME ZONE 'UTC'(and filtered onCAST(ts AS date)). → Now groups and filters by:tz = SERVER_TIMEZONE.coach_contextlogging-consistency count, and the daily biometric buckets ingoals.recommend/profile_sync, all used hardcoded UTC even though their windows were server-local. → All bucket inSERVER_TIMEZONE.Streaks driven by the browser, not the server
?tz=<browserTz>to/today,/today/streak-history,/water, and/health/*, overriding the configured server timezone. → Backend now always resolves toSERVER_TIMEZONEand ignores the client hint; the frontend stops sending it and derives "Today" from the server'sdate.Streak headline ≠ breakdown (the screenshot)
/todayheadline streak added today's supplement nutrients to every historical day, which could flip earlier days off-track — so the headline read 0 while the per-day list still showed them on-track. → Supplements are now credited to the day they were actually logged, mirroring/today/streak-history(including supplement-only days).Testing
ruff+mypy(touched files) clean.pnpm type-check,pnpm lint(0 errors),pnpm test97 passed. UpdatedWaterCard.test.tsxquery keys.Note
This intentionally removes the per-device timezone override so the configured server timezone governs everywhere, per the request that everything be pulled based on the server's timezone setting. The notification "nudge timezone" preference is left untouched (it's an explicit user setting, not a day-boundary override).
https://claude.ai/code/session_01NhMPok8EUdmK9o7pDKEx4a
Generated by Claude Code