Skip to content

Sample correction range per prediction point in insulinCorrection - #39

Merged
ps2 merged 1 commit into
mainfrom
fix/per-point-correction-range
Sep 24, 2026
Merged

ps2 merged 1 commit into
mainfrom
fix/per-point-correction-range

Conversation

@ps2

@ps2 ps2 commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Sample correction range per prediction point in insulinCorrection

What

insulinCorrection sampled the correction range once, at the decision time, and used that single band for every predicted point. LoopKit's DoseMath samples the range at each prediction point's own time (correctionRange.quantityRange(at: prediction.startDate)), so a forecast that crosses a target-band boundary is corrected to the band actually in effect at each point.

This change matches LoopKit: look up the correction range per prediction point.

Why

With a schedule like evening 100 mg/dL → overnight 110 mg/dL, a forecast generated near the boundary extends into the overnight band, but the port corrected those points to 100 instead of 110 — systematically over-correcting into the higher band (and under-correcting into a lower one).

Replay verification against deployed Loop (real dosing history, LoopEval): this discrepancy was the dominant source of auto-bolus mismatch for a donor with an evening/overnight band change. The fix lifted exact auto-bolus agreement with the deployed app from 75.6% to 82.9% (agreement within one 0.05 U increment: 93.1% → 95.1%).

Behavior change

Only forecasts that cross a correction-range boundary are affected; with a single band (or none within the forecast horizon) the result is unchanged. The precondition message changes from "must cover date" to "must cover prediction", since the range must now cover the forecast horizon — AlgorithmInput.target timelines already do.

Testing

  • New testCorrectionRangeSampledPerPredictionPoint: a flat-high forecast with the target band stepping up at t+2h requires less correction than the same forecast against the uniform low band.
  • Full suite passes (142 tests).

🤖 Generated with Claude Code

https://claude.ai/code/session_01XEGCDE2D9wF3zig7uQ9PY2

The correction range was sampled once at the decision time and applied to
every predicted point. LoopKit's DoseMath samples the range at each
prediction point's own time (correctionRange.quantityRange(at:
prediction.startDate)), so a forecast that crosses a target-band boundary
(e.g. an evening band ending and a higher overnight band beginning) is
corrected to the band in effect at each point. Sampling once over-corrects
the portion of the forecast that lands in a higher later band, and
under-corrects for a lower later band.

Match LoopKit: look up the correction range at each prediction point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEGCDE2D9wF3zig7uQ9PY2
@ps2
ps2 requested review from Camji55 and nhamming September 24, 2026 17:45
@ps2
ps2 merged commit 4ddd4a0 into main Sep 24, 2026
4 checks passed
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.

2 participants