Skip to content

CreatorTrack Fitness polish + wellness data-freshness fixes

URL: https://mkdocs.justinsforge.com/memory/handoffs/creatortrack-fitness-polish-2026-07-06/

Data freshness: root causes found and fixed (forge main, already live)

  1. Hevy frozen since 2026-07-03 (the 86h monitor alert). forge_hevy_poll.py was stubbed out in the Notion decommission, but it was the ONLY thing fetching workouts from the Hevy API; data/hevy/raw_hevy_workouts.jsonl, wellness.hevy_workouts, and the ~/.forge-state/hevy_last_sync stamp all froze. Fix (commit 3d23ab5 on forge main): forge_wellness_pg_sync.py now owns the fetch (refresh_hevy_raw()): full workout list + exercise-template catalog from api.hevyapp.com, atomic rewrite, refuses an empty API response, stamps hevy_last_sync; age-gated to 6h so the 15-min timer hits the API ~4x/day. Verified end to end: 483 workouts + 485 templates fetched, PG synced, stamp current, chip shows green. Retired forge_hevy_poll cron lines removed from crontab. Note: newest workout is genuinely 2026-06-29; Justin has not lifted since.
  2. Eight Sleep gaps are device-side, not code. facts_wellness has no rows for Jul 5 and only 6 for Jul 4, then resumes Jul 6; ha_poller runs every 15 min and is healthy. Pattern matches the pod dropping off wifi (known fix: 2.4GHz AP, reference_eight_sleep_pod_connectivity). App now shows gaps explicitly instead of silently showing an older night.
  3. Garmin is healthy. Poller every 30 min 09:00-22:00 CT, facts current same-day. The app-side date math (America/Chicago in lib/fitness/time.ts) is correct; "stale-looking" Garmin was the silent-fallback UI problem, now labeled.
  4. Also fixed while here: the worktree DB was missing 4 migrations merged to main after the dev-base clone (core.my_blocked_apps 500); applied.

Fitness app UI (branch feat/fitness-polish, commit 12c6ad0)

  • Today view = real day surface: shared WeekStrip + DayHead (Habits/Meals pattern), any day in the 60-day window viewable; ring fill = Eight Sleep score, so pod-offline days show as empty rings right in the strip. DashboardData now ships daily per-day metric maps + today_iso.
  • Freshness chips in the app header on every view: Eight Sleep / Garmin / Hevy pipeline age, green/amber/red (warn at expected cadence, bad at 2x), tooltip with expectation.
  • Explicit gap states: a day with no Eight Sleep/Garmin data says so (.fit-daygap); today-with-no-data-yet falls back to the latest rich day WITH a visible "showing Jul 3" note (Eight Sleep card previously had NO stale indicator at all).
  • Polish: card hover elevation, readiness banner left-band + tint keyed to the call (push/maintain/pull back/rest), chip/gap styles. Chart primitives were already solid (tooltips, range nav, heatmap); left intact.
  • Not done, deliberate: converting DetailModals to the shared SidePeek (URL-param plumbing on a node route; modals work; separate PR if wanted). 4 pre-existing eslint errors in DetailModals.tsx/charts.tsx (react-hooks/refs, setState-in-effect) predate this branch.

Ops warning: dev-slot reaper reaped an ACTIVE agent slot

At 19:02 the reaper hit the >4-slot cap and tore down feat/fitness-polish (worktree + DB deleted) while this agent was mid-session; headless Playwright probes leave no persistent connection, so agent slots look idle. Recovered via re-bootstrap; this session now holds a keep-alive TCP socket to :3066 as a workaround. Consider teaching the reaper to treat slots with a recent git commit or recent file mtime as active.

Review

  • Branch: feat/fitness-polish (do not merge without rm -rf .next-dev gotcha check; no route changes though)
  • Review: Today view day-nav (click days, prev week, Jul 5 = Eight Sleep gap state, Back to today), header chips on all 7 views, readiness banner tint. tsc clean.
  • Forge main commits: 3d23ab5 (hevy fetch), 4d48d62 (topic file).
  • Preview: http://100.97.43.104:3066

[Claude Code]