New test module exercises pickCanonicalSourceRows with the realistic
W17b/c shape: same user reporting both WITHINGS rows (from the new
activity / sleep sync routines) and APPLE_HEALTH rows (from the v1.5
iOS passthrough) for the same day.
Coverage:
- Default Marc-directive priority picks APPLE_HEALTH for every
cumulative metric (steps, active energy, distance, flights)
- Same default applies to sleep — even when both sources captured
the same set of per-stage rows from Migration 0055
- Withings stays the fallback when Apple Health has no rows that
day (today's v1.4.25 reality; v1.5 may flip it per-user)
- User-level overrides re-prioritise the ladder as documented
- Activity rows (sleepStage NULL) and sleep rows (sleepStage non-null)
pick independently — Migration 0055's per-stage uniqueness doesn't
leak into the picker's source axis.
W10 senior-dev review flagged that workouts will collide once v1.5
lands the iOS HealthKit passthrough: a single ScanWatch run becomes
two rows — one from HKWorkout, one from the Withings Activity API.
The Measurement table solved the symmetric problem via
pickCanonicalSourceRows; workouts need a parallel helper before the
"recent workouts" tile can show one row per workout instead of one
per source.
This commit ships the scaffolding only. The helper:
- Clusters workouts whose start timestamps land within
proximityMinutes of each other (default 5 minutes — covers the
HealthKit passthrough lag plus a clock-skew buffer) AND share a
sport type, so a Walking + Running burst stays distinct.
- Walks a per-user source ladder (default
APPLE_HEALTH > WITHINGS > MANUAL > IMPORT — see file-level rationale)
and keeps the first source present in each cluster.
- Is deterministic on input order plus a lexicographic id
tiebreaker so the same fixture always produces the same canonical
list.
- Falls through cleanly when none of the ladder entries are
present in a cluster (legacy / future source values).
NOT yet wired into any query path. The wiring lands alongside the
workout ingest endpoint (W16b) or with the v1.5 iOS rollout,
whichever ships first. The Workout model already carries the
TODO(v1.5 iOS) breadcrumb in prisma/schema.prisma; this commit
delivers the helper that breadcrumb points at.
Unit tests cover the three brief-mandated fixtures (two-source same
workout, two-source different workouts close in time, single source
pass-through) plus the 5-minute proximity boundary, custom-ladder
override, empty input, and determinism guards.