fix(medications): rebase dashboard compliance denominator onto the schedule

The dashboard compliance tile set scheduled = COUNT(*) of logged intake
rows, so its rate (taken / scheduled) sat at ~100% across every window
regardless of real adherence — every logged row was both numerator and
denominator, and the 7/30/90 windows never diverged.

Anchor scheduled to the canonical recurrence engine's expected-dose count
per day, summed across active medications, so days the schedule expected a
dose the user missed pull the rate down and the windows genuinely diverge
with partial adherence. taken is capped per day at the expected count so a
duplicate log can't push a day above 100%. The response shape stays
{date, scheduled, taken} for the existing chart consumer.

Regenerate the OpenAPI contract for the new expected/missed count fields.
This commit is contained in:
Marc-André Bombeck committed 2026-06-07 13:26:58 +02:00
1 parent cb239c2803
commit 7bbb473070
4 files changed
+275 -134

No files matched your search

+24
View File
@@ -1274,11 +1274,35 @@ const complianceDisplay = z
short: z.object({
rate: z.number().int().min(0).max(100),
taken: z.number().int().nonnegative(),
expected: z
.number()
.int()
.nonnegative()
.describe(
"v1.15.9 rate denominator over the short window (`taken + missed`); user skips are excluded. Render `taken / expected · rate%`.",
),
missed: z
.number()
.int()
.nonnegative()
.describe(
"v1.15.9 doses counted against the rate over the short window — includes forgotten doses the auto-miss cron flipped.",
),
streak: z.number().int().nonnegative(),
}),
long: z.object({
rate: z.number().int().min(0).max(100),
taken: z.number().int().nonnegative(),
expected: z
.number()
.int()
.nonnegative()
.describe("v1.15.9 rate denominator over the long window (`taken + missed`)."),
missed: z
.number()
.int()
.nonnegative()
.describe("v1.15.9 doses counted against the rate over the long window."),
}),
currentCycle: z
.object({