You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Auto-detected workouts never reach the sessions table — invisible to AI Coach (v_sessions) and Apple Health export despite both documenting they include them #131
Reported 22 Jul 2026 (user RR, 0.9.19+50): today's completed workout does not appear. Two faces:
AI Coach says the latest v_sessions row is yesterday and there is no session for today.
Edge does not write today's workout to Apple Health, even after a forced sync.
#129 and #130 explain these as independent bugs for a manual session (a sessions row that exists but is mis-dated / not yet exported). This issue is the third defect and the single root that unifies both symptoms when the workout is auto-detected rather than manually started in-app — the dominant path for a WHOOP-style band where the user never taps start/stop.
Root cause: auto-detected workouts are never written to the sessions table, yet both the coach view and the HealthKit export read only that table — while documenting that they include auto/detected workouts
Detected workouts live only in the derived day_result bundle under detected_workouts:
Produced by the derivation engine into the bundle (lib/compute/derivation_engine.dart:3065, and the detected_workouts field noted at :2497).
Surfaced to the UI by merging them at read time in LocalRepositoryImpl.getSessions() (lib/data/local_repository_impl.dart:1016-1032), which unions sessionsInRange (manual) with detected_workouts decoded from each recent bundle. The comment there is explicit: "Manual/live sessions (the sessions table) MERGED with auto-detected workouts from the per-day bundle."
Nothing ever promotes a detected workout into the sessions table. The only LocalDb.putSession callers are the manual live-session paths — app_state.startWorkout/stopWorkout (lib/state/app_state.dart:2960, :3088), LocalRepositoryImpl.startWorkout/endWorkout (:1899, :1917), and the legacy cloud_import (lib/cloud/cloud_import.dart:258). None of them write detected bouts.
But the two other consumers of workout data read the sessions table exclusively — and both claim, in their own docs/comments, to include auto/detected workouts:
AI Coach reads v_sessions, a raw passthrough of the sessions table (lib/data/db.dart:1171-1175). The coach system prompt documents it as "v_sessions(…) — workouts (manual/live/auto)" (lib/coach/coach_prompt.dart:52; column list mirrored at lib/coach/coach_engine.dart:711). The "auto" is false — v_sessions can never contain an auto-detected workout. So the coach genuinely sees no row for today and reports yesterday's last manual session as the latest. (This is independent of AI Coach mis-dates workouts: v_sessions has no local-day column, so 'today's session' resolves in UTC #129: even with a local date column added, an auto workout still isn't in the table to be dated.)
HealthKit / Health Connect export writes workouts only inside _exportDay, from LocalDb.sessionsInRange(...) (lib/health/health_export.dart:542-571) — and the comment above it reads "Workouts (manual/live/detected) finalized in this calendar day."sessionsInRange is a sessions-table query (lib/data/db.dart:3621-3632), so detected workouts are never written. A forced sync cannot help: healthSyncNow() → exportAll() → _exportDay → sessionsInRange (app_state.dart:357), same table. (Independent of Today's workout not written to Apple Health: HealthKit export is day_result-gated, not session-triggered #130's day-result gating: even if the day exports, a detected workout isn't in the queried table.)
So getSessions() (the workouts screen) shows today's detected workout, while the coach and Apple Health both silently omit it — one gap, both symptoms.
Shared-root verdict
If RR's workout was auto-detected (no in-app start/stop), this single defect explains both symptoms and they share a root. If it was a manual session that persisted, #129 (coach mis-dating) and #130 (export day-gating) apply instead and the two are independent. The auto-detected case is the more likely real-world scenario for a band, and is the only hypothesis consistent with the coach seeing no row at all (a persisted manual done session would still appear in v_sessions, merely mis-dated).
Recommended fix (confidence: high that this is a real gap; medium that it is RR's specific case)
Make detected workouts first-class in the same store the coach and health export read. Either:
Promote confirmed detected bouts into the sessions table at derive/finalise time with source='auto', deduped against overlapping manual spans exactly as getSessions() already does (local_repository_impl.dart:1013-1014,1029). Then v_sessions and the health export need no change. Cleanest — one source of truth.
Or merge detected_workouts into both consumers the way getSessions() does: give v_sessions a UNION over the latest bundle's detected bouts, and have _exportDay also write detected workouts for its day. More code, two extra merge sites to keep in sync.
Fixing the two doc/comment claims (coach_prompt.dart:52 "auto", health_export.dart:538 "detected") is not optional either way — today they assert coverage the code does not provide.
Confirm the workout is visible on the in-app Workouts screen today (proves it exists as a detected bout in the bundle and only the coach/health surfaces miss it).
Related: #129 (coach v_sessions missing local-day column — manual-session variant), #130 (HealthKit export day-result-gated — manual-session variant). This issue is the auto-detected-workout root that unifies both symptoms; the three can all be true at once.
Symptom (shared root behind both #129 and #130)
Reported 22 Jul 2026 (user RR, 0.9.19+50): today's completed workout does not appear. Two faces:
v_sessionsrow is yesterday and there is no session for today.#129 and #130 explain these as independent bugs for a manual session (a
sessionsrow that exists but is mis-dated / not yet exported). This issue is the third defect and the single root that unifies both symptoms when the workout is auto-detected rather than manually started in-app — the dominant path for a WHOOP-style band where the user never taps start/stop.Root cause: auto-detected workouts are never written to the
sessionstable, yet both the coach view and the HealthKit export read only that table — while documenting that they include auto/detected workoutsDetected workouts live only in the derived
day_resultbundle underdetected_workouts:lib/compute/derivation_engine.dart:3065, and thedetected_workoutsfield noted at:2497).LocalRepositoryImpl.getSessions()(lib/data/local_repository_impl.dart:1016-1032), which unionssessionsInRange(manual) withdetected_workoutsdecoded from each recent bundle. The comment there is explicit: "Manual/live sessions (the sessions table) MERGED with auto-detected workouts from the per-day bundle."Nothing ever promotes a detected workout into the
sessionstable. The onlyLocalDb.putSessioncallers are the manual live-session paths —app_state.startWorkout/stopWorkout(lib/state/app_state.dart:2960,:3088),LocalRepositoryImpl.startWorkout/endWorkout(:1899,:1917), and the legacycloud_import(lib/cloud/cloud_import.dart:258). None of them write detected bouts.But the two other consumers of workout data read the
sessionstable exclusively — and both claim, in their own docs/comments, to include auto/detected workouts:AI Coach reads
v_sessions, a raw passthrough of thesessionstable (lib/data/db.dart:1171-1175). The coach system prompt documents it as "v_sessions(…) — workouts (manual/live/auto)" (lib/coach/coach_prompt.dart:52; column list mirrored atlib/coach/coach_engine.dart:711). The "auto" is false —v_sessionscan never contain an auto-detected workout. So the coach genuinely sees no row for today and reports yesterday's last manual session as the latest. (This is independent of AI Coach mis-dates workouts: v_sessions has no local-day column, so 'today's session' resolves in UTC #129: even with a localdatecolumn added, an auto workout still isn't in the table to be dated.)HealthKit / Health Connect export writes workouts only inside
_exportDay, fromLocalDb.sessionsInRange(...)(lib/health/health_export.dart:542-571) — and the comment above it reads "Workouts (manual/live/detected) finalized in this calendar day."sessionsInRangeis asessions-table query (lib/data/db.dart:3621-3632), so detected workouts are never written. A forced sync cannot help:healthSyncNow()→exportAll()→_exportDay→sessionsInRange(app_state.dart:357), same table. (Independent of Today's workout not written to Apple Health: HealthKit export is day_result-gated, not session-triggered #130's day-result gating: even if the day exports, a detected workout isn't in the queried table.)So
getSessions()(the workouts screen) shows today's detected workout, while the coach and Apple Health both silently omit it — one gap, both symptoms.Shared-root verdict
If RR's workout was auto-detected (no in-app start/stop), this single defect explains both symptoms and they share a root. If it was a manual session that persisted, #129 (coach mis-dating) and #130 (export day-gating) apply instead and the two are independent. The auto-detected case is the more likely real-world scenario for a band, and is the only hypothesis consistent with the coach seeing no row at all (a persisted manual
donesession would still appear inv_sessions, merely mis-dated).Recommended fix (confidence: high that this is a real gap; medium that it is RR's specific case)
Make detected workouts first-class in the same store the coach and health export read. Either:
sessionstable at derive/finalise time withsource='auto', deduped against overlapping manual spans exactly asgetSessions()already does (local_repository_impl.dart:1013-1014,1029). Thenv_sessionsand the health export need no change. Cleanest — one source of truth.detected_workoutsinto both consumers the waygetSessions()does: givev_sessionsa UNION over the latest bundle's detected bouts, and have_exportDayalso write detected workouts for its day. More code, two extra merge sites to keep in sync.Fixing the two doc/comment claims (
coach_prompt.dart:52"auto",health_export.dart:538"detected") is not optional either way — today they assert coverage the code does not provide.Needs on-device confirmation
SELECT id, source, status, start_ts FROM sessions ORDER BY start_ts DESC LIMIT 5— confirm today's workout is absent fromsessions(i.e. it was auto-detected), which distinguishes this from AI Coach mis-dates workouts: v_sessions has no local-day column, so 'today's session' resolves in UTC #129/Today's workout not written to Apple Health: HealthKit export is day_result-gated, not session-triggered #130.Related: #129 (coach
v_sessionsmissing local-day column — manual-session variant), #130 (HealthKit export day-result-gated — manual-session variant). This issue is the auto-detected-workout root that unifies both symptoms; the three can all be true at once.