Skip to content

Restore IntegralRC integral-correction clamp (deployed-LoopKit safety bound)#36

Closed
ps2 wants to merge 1 commit into
mainfrom
restore-integral-rc-clamp
Closed

Restore IntegralRC integral-correction clamp (deployed-LoopKit safety bound)#36
ps2 wants to merge 1 commit into
mainfrom
restore-integral-rc-clamp

Conversation

@ps2

@ps2 ps2 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

The port of Loop's algorithm from LoopKit to the standalone LoopAlgorithm package dropped IntegralRetrospectiveCorrection's integral-correction limits — a safety guardrail that bounds the wound-up integral term so it cannot drive the forecast into over- or under-dosing. This PR restores that clamp.

It is a faithful restoration of the deployed-LoopKit formula (LoopKit/RetrospectiveCorrection/IntegralRetrospectiveCorrection.swift):

zeroTempEffect     = |ISF × basalRate|
positiveLimit      = min(max(glucose − rangeMax, 1× zeroTempEffect), 4× zeroTempEffect)
negativeLimit      = −max(10, glucose − rangeMin)
integralCorrection = clamp(integralCorrection, negativeLimit, positiveLimit)
  • (+) limit — between 1× and 4× zeroTempEffect, larger the further BG is above the correction-range top (more room to correct a real high).
  • (−) limit — at most ~(glucose − rangeMin) below target (10 mg/dL floor), capping over-suspension.

Design — backward compatible

The clamp needs ISF, scheduled basal rate, and correction range at the decision time. These are added as optional inputs to computeEffect(...) and generatePrediction(...):

  • Any nillegacy unclamped behavior, so the public API is unchanged for existing callers.
  • LoopAlgorithm.run() passes input.target, so the deployed dosing path is clamped by default.
  • Pure prediction (LoopPredictionInput carries no correction range) stays unclamped.
  • StandardRetrospectiveCorrection accepts and ignores the inputs (no integral term to bound).

Tests

New cases in IntegralRetrospectiveCorrectionTests (reading integralCorrection directly):

  • a wound-up positive integral is pinned to the positive limit;
  • a wound-up negative integral is pinned to the negative limit;
  • the clamp is inert when the integral is within limits (also confirms the change is non-breaking).

All 141 package tests pass.

… bound)

The port of Loop's algorithm from LoopKit to the standalone LoopAlgorithm
package dropped IntegralRetrospectiveCorrection's integral-correction limits — a
safety guardrail that bounds the wound-up integral term so it cannot drive the
forecast into over- or under-dosing.

This restores that clamp, faithful to deployed LoopKit
(LoopKit/RetrospectiveCorrection/IntegralRetrospectiveCorrection.swift):

  zeroTempEffect     = |ISF x basalRate|
  positiveLimit      = min(max(glucose - rangeMax, 1x zeroTempEffect), 4x zeroTempEffect)
  negativeLimit      = -max(10, glucose - rangeMin)
  integralCorrection = clamp(integralCorrection, negativeLimit, positiveLimit)

The clamp needs ISF, scheduled basal rate, and correction range at the decision
time. computeEffect() and generatePrediction() gain these as OPTIONAL inputs
(nil => legacy unclamped behavior, so the public API stays backward-compatible).
LoopAlgorithm.run() passes input.target, so the deployed dosing path is clamped;
pure prediction (which carries no correction range) stays unclamped.

Tests (IntegralRetrospectiveCorrectionTests): a wound-up integral is pinned to
the positive/negative limits, and left untouched when within limits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CkvtagxJNmFrbbHTgd9CDX
@ps2

ps2 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #37. Rather than restore the original settings-dependent clamp (bounded by ISF×basal and the target range), #37 bounds the RC correction rate to a settings-free physiological ceiling — a forecast of unmodeled physiology shouldn't be gated by a user's insulin needs or target.

@ps2 ps2 closed this Jul 24, 2026
@ps2
ps2 deleted the restore-integral-rc-clamp branch July 24, 2026 22:20
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