Skip to content

Commit 2284d89

Browse files
Don't snooze high alarm when there is no IOB (#6348)
The Bolus Wizard Preview plugin snoozes a high alarm when its `bolusEstimate` is below the snooze threshold, treating that as "enough insulin on board to cover the high". But `bolusEstimate` is 0 in a case that has nothing to do with IOB coverage: when the BG is above the alarm threshold (`bgTargetTop`) yet still below the profile's high target, so neither the high nor low branch of calc() runs. With no insulin on board this leaves bolusEstimate at its initial 0 and a genuine high alarm is silenced -- the scenario reported in #6348 (complete profile, no insulin treatments). Because the snooze is requested at URGENT level and snoozedBy() matches by level across the group, it can also suppress other urgent alarms for the snooze duration. Guard the snooze on `prop.iob > 0` so a high is only snoozed when there is actually insulin on board to cover it. Legitimate "enough IOB" snoozing is unchanged. Adds regression tests for the reported scenario (BG below the profile high target with no IOB) and for the unchanged enough-IOB snooze. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 17283fe commit 2284d89

2 files changed

Lines changed: 46 additions & 1 deletion

File tree

lib/plugins/boluswizardpreview.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ function init (ctx) {
107107
var ar2EventType = sbx.properties.ar2 && sbx.properties.ar2.eventType;
108108
var high = ar2EventType === 'high' || prop.scaledSGV >= sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop);
109109

110-
return high && prop.bolusEstimate < settings.snoozeBWP;
110+
// Require real IOB: a bolusEstimate of 0 does not imply insulin is covering
111+
// the high -- it also happens when the BG is above the alarm threshold but
112+
// below the profile's high target. Without IOB that must not be read as
113+
// "enough IOB" and silence a genuine high alarm. See #6348.
114+
return high && prop.iob > 0 && prop.bolusEstimate < settings.snoozeBWP;
111115
};
112116

113117

tests/boluswizardpreview.test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe('boluswizardpreview', function ( ) {
1515
var ar2 = require('../lib/plugins/ar2')(ctx);
1616
var iob = require('../lib/plugins/iob')(ctx);
1717
var bgnow = require('../lib/plugins/bgnow')(ctx);
18+
var simplealarms = require('../lib/plugins/simplealarms')(ctx);
1819

1920
function prepareSandbox ( ) {
2021
var sbx = require('../lib/sandbox')().serverInit(env, ctx);
@@ -297,6 +298,46 @@ describe('boluswizardpreview', function ( ) {
297298

298299
});
299300

301+
it('does not snooze a high alarm with no IOB when the BG sits below the profile high target', function (done) {
302+
// Faithful to #6348: a complete profile whose target_high is above the
303+
// current high reading leaves bolusEstimate at 0 even though calc succeeds.
304+
// With no insulin on board that must not be read as "enough IOB".
305+
ctx.notifications.resetStateForTests();
306+
ctx.notifications.initRequests();
307+
ctx.ddata.sgvs = [{mills: before, mgdl: 270}, {mills: now, mgdl: 273}];
308+
ctx.ddata.treatments = []; // no insulin -> no IOB
309+
ctx.ddata.profiles = [{ dia: 3, units: ctx.settings.units, sens: 100, target_high: 280, target_low: 100 }];
310+
311+
var sbx = prepareSandbox();
312+
313+
simplealarms.checkNotifications(sbx);
314+
boluswizardpreview.checkNotifications(sbx);
315+
316+
var highest = ctx.notifications.findHighestAlarm('default');
317+
should.exist(highest);
318+
should(ctx.notifications.snoozedBy(highest)).not.be.ok();
319+
320+
done();
321+
});
322+
323+
it('still snoozes a high alarm when real IOB covers it', function (done) {
324+
// Contract contrast for #6348: the guard discriminates on iob > 0, so a
325+
// genuine "enough IOB" high is still snoozed.
326+
ctx.notifications.resetStateForTests();
327+
ctx.notifications.initRequests();
328+
ctx.ddata.sgvs = [{mills: before, mgdl: 295}, {mills: now, mgdl: 300}];
329+
ctx.ddata.treatments = [{mills: before, insulin: '5.0'}];
330+
ctx.ddata.profiles = [profile];
331+
332+
var sbx = prepareSandbox();
333+
var prop = sbx.properties.bwp;
334+
335+
prop.iob.should.be.greaterThan(0);
336+
boluswizardpreview.highSnoozedByIOB(prop, {snoozeBWP: 0.10}, sbx).should.equal(true);
337+
338+
done();
339+
});
340+
300341
it('set a pill to the BWP with infos', function (done) {
301342
// BWP-TIME-001: Use fixed timestamp for deterministic IOB calculation
302343
// Using `now` instead of `Date.now()` prevents timing drift between

0 commit comments

Comments
 (0)