Skip to content

[LOOP-5925] Preserve scheduled basal rate in insulin delivery cache#746

Open
ps2 wants to merge 4 commits into
devfrom
ps2/LOOP-5925/preserve-basal-rate-in-cache
Open

[LOOP-5925] Preserve scheduled basal rate in insulin delivery cache#746
ps2 wants to merge 4 commits into
devfrom
ps2/LOOP-5925/preserve-basal-rate-in-cache

Conversation

@ps2
Copy link
Copy Markdown

@ps2 ps2 commented May 21, 2026

Jira: LOOP-5925

Summary

A live (mutable) scheduled basal shows a rate slightly off from the scheduled rate (e.g. 0.999 / 1.001 U/hr for a 1.0 U/hr basal), snapping back to exact once the dose finalizes.

The exact rate is lost because a .basal dose's scheduledBasalRate is dropped when it round-trips through the PumpEvent Core Data entity (which has no column for it). CachedInsulinDeliveryObject then stores only the delivered total quantized to 0.05 U increments (unitsInDeliverableIncrements); on read-back with a nil rate it falls back to unit == .units, so the displayed rate becomes delivered_total / elapsed and drifts until the duration crosses a 0.05 U boundary. (Note: this is the on-device delivery cache — mutable doses are never written to HealthKit.)

For a .basal (scheduled basal, as opposed to .tempBasal) the rate is intrinsically the dose's value, so this preserves it directly: CachedInsulinDeliveryObject.create(from:)/update(from:) now derive scheduledBasalRate from the dose's own rate for .basal entries when it isn't already set.

  • Display-only — net-insulin/IOB math is unchanged (basal net is always 0).
  • No Core Data migration; no change to the pump-event contract.
  • An existing scheduledBasalRate (e.g. one a pump manager provides) is still preferred when present.

Affects pumps that report explicit scheduled-basal events and aren't served from reservoir data; pumps that rely on LoopKit's basal interpolation were unaffected (those entries already get the rate stamped in overlayBasal).

Test plan

  • Added testCreateFromScheduledBasalEntryPreservesRate — a mutable 1.0 U/hr .basal over a duration that would quantize to a drifting total; asserts the cached rate and round-tripped dose.unitsPerHour are exactly 1.0.
  • CI: LoopKit unit tests pass.
  • Verify on-device that a live scheduled basal in the Insulin Delivery Log shows the exact rate.

ps2 added 4 commits May 21, 2026 16:00
A mutable .basal dose loses its scheduledBasalRate when it round-trips
through the PumpEvent Core Data entity, which has no column for it.
CachedInsulinDeliveryObject then stores only the delivered total
(quantized to 0.05 U increments) and, on read-back with a nil rate,
falls back to unit == .units, so the displayed rate becomes
delivered_total / elapsed and drifts (e.g. 0.999/1.001 U/hr for a
1.0 U/hr basal) until the dose finalizes.

For a .basal the rate is intrinsically the dose's value, so preserve it
as scheduledBasalRate in create(from:)/update(from:) when not already
set. Display-only (basal net-insulin is always 0); no Core Data
migration.
@ps2 ps2 requested review from Camji55 and nhamming May 21, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant