chore(release): v1.28.23 — sleep disagreement on the dashboard; Apple Health medication groundwork

The sleep source-discrepancy annotation now reaches the surfaces: SleepNight
carries the MAIN session's annotation (naps never cross-compare), the analytics
slim slice / dashboard snapshot / iOS summary thread it additively, and the
dashboard sleep tile renders the shared discreet marker (extracted from the
sleep panel — one implementation, two surfaces). Served totals unchanged,
pinned by tests.

Apple Health medications groundwork (server side of the medication-import
request): IntakeSource gains APPLE_HEALTH; medications accept an external
mirror identity (source-exclusive by policy) and dose imports carry the HK
dose-event UUID — both idempotent per stable key, with the concurrent-create
race resolved to the winner. Migration 0239, additive only. Entries without
the new fields behave byte-identically.

Hardening: doctor-report aggregation + PDF charts compute ranges with loops
instead of spread calls — a report over a sample-dense year cannot overflow
the call stack (the class fixed for the Google Health full sync).
This commit is contained in:
Marc-André Bombeck committed 2026-07-11 00:18:23 +02:00
1 parent 755da41019
commit c400e2aa88
29 files changed
+1585 -276

No files matched your search

@@ -850,6 +850,25 @@ export const dashboardSnapshotResponse = z
}),
),
}),
// v1.28.x — additive: source-discrepancy annotation for the latest
// night behind `summaries.SLEEP_DURATION.latest`. Same shape as the
// per-session `sourceDiscrepancy` on the sleep-night resource.
sleepSourceDiscrepancy: z
.object({
deltaMinutes: z.number().int().nonnegative(),
sources: z.array(
z.object({
source: z.string(),
deviceType: z.string().nullable(),
asleepMinutes: z.number().int().nonnegative(),
}),
),
})
.nullable()
.optional()
.describe(
"Non-null when two writer buckets reported clearly different asleep totals for the latest night's main session (> 45 min apart and > 20% of the larger total). Observational only — the served summary stays the winning writer's totals; clients may show a discreet 'sources disagree' hint next to the sleep tile's headline. Null when the writers agree or the sleep module is off; optional for older cached snapshots.",
),
}),
extras: z
.object({