Skip to content

Completed workouts can bypass Health export (endWorkout, stale-session reconcile, workout-only imports) #277

Description

@abdulsaheel

Found by CodeRabbit during #262 review (flagged as outside that PR's diff — filing separately so it isn't lost). Not a regression from #262; pre-existing behavior.

The gap

Three paths mark a session row done without ever reaching the Health store:

  1. LocalRepositoryImpl.endWorkout — writes status: 'done' but never calls HealthExporter.exportWorkoutId / exportWorkout. Health export only picks sessions up inside exportAll's per-day_result scan.
  2. Stale-session reconciliation (AppState._reconcileOrphanedLiveWorkout) — silently finalizes stale live rows (deliberately: no resurfacing a days-old banner), but those rows carry end_ts: null, so even if export scanned them there is no end time to export. They are permanently un-exportable as things stand.
  3. Workout-only imports — an import that brings sessions but no/unchanged day_result rows can bypass exportAll's day scan entirely, so imported completed sessions never export.

Why it matters

AGENTS.md §4.7's exact failure class: capability wired into one call path but not all N. A user who finishes a workout offline (app killed mid-session → reconciled on next launch) or imports history gets silent gaps in Apple Health / Health Connect while the app shows the session as saved.

Suggested shape

  • endWorkout and reconciliation set a real end_ts (reconciliation may need to derive one — e.g. last sample ts or reconcile time, stated honestly) and then route through the existing HealthExporter.exportWorkoutId(...) after the DB write lands.
  • Workout-only import completion triggers an explicit session export pass (reuse existing exporter APIs; skip incomplete rows).
  • Keep the current single-flight/backoff machinery — this is about adding the missing call sites, not new plumbing.

Verification ideas

  • Test: end a workout with health configured → assert one export call with correct start/end.
  • Test: reconcile a stale live row → exported once, not re-exported on later passes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions