From 1ed2e5d2a2d5269f5ac0ac98a06aa99888dfefeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 15 Jun 2026 01:28:26 +0200 Subject: [PATCH] docs(recovery): note the date-anchor bucketing gap for negative-UTC users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oura and Polar recovery rows are bucketed on the local day of their raw measuredAt, on the assumption that both stamp the wake morning. Polar always anchors at UTC midnight of the wake date and Oura falls back to the same anchor when no real wake instant is present, so for a user in a far negative UTC zone that anchor reads as the previous local evening and a single night can split across two recovery days near the date line. A correct fix needs an anchor-kind signal threaded through the recovery read so the date-anchored sources read their wake day in UTC while a real wake instant stays local — out of scope here. Document the assumption at the bucketing site; positive-UTC users are unaffected. --- src/lib/insights/derived/recovery-resolve.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/lib/insights/derived/recovery-resolve.ts b/src/lib/insights/derived/recovery-resolve.ts index b87298301..ce8cb09e0 100644 --- a/src/lib/insights/derived/recovery-resolve.ts +++ b/src/lib/insights/derived/recovery-resolve.ts @@ -76,6 +76,20 @@ function rankOf(source: MeasurementSource): number { * shifted forward by one before the local-day read — aligning it onto the same * wake day the WHOOP row for that night carries. Reading the key in the user's * timezone keeps a near-midnight or late re-score on the same night. + * + * KNOWN LIMITATION (05-M2, deferred to v1.17.2). OURA and POLAR are bucketed by + * the local day of their raw `measuredAt` on the assumption that both stamp the + * wake morning. Polar always anchors `measuredAt = ${date}T00:00:00.000Z` + * (UTC-midnight of the wake date); Oura prefers a real `bedtimeEnd` wake instant + * but FALLS BACK to the same UTC-midnight anchor. For a user in a far-negative + * UTC zone, a UTC-midnight anchor reads as the PREVIOUS local evening, so a + * Polar (or Oura-fallback) night can land one day earlier than the WHOOP/Oura + * night it should align with — splitting one physiological night across two + * recovery days near the date line. A correct fix needs an "anchor kind" + * (date-midnight vs real-instant) threaded through the recovery read so the + * date-anchored sources read their wake-day in UTC while WHOOP / Oura-bedtimeEnd + * stay local; that DTO change is out of scope for v1.17.1. Europe / positive-UTC + * users (the common case) are unaffected. */ function wakeDayKeyOf(d: Date, source: MeasurementSource, tz: string): string { const anchor =