From 125a01bc4e9d1d7e8ac32725858b27f73e05ae63 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Tue, 15 Sep 2026 23:15:18 -0500 Subject: [PATCH] Don't re-evaluate glucose alerts from a backfill older than the last reading CGMs deliver the live reading and then backfill the gap behind it, each as its own batch. evaluate() re-ran on the backfill, which carries a sample no newer than the one just evaluated, and re-decided the alert from it. Seen with the G7: a live reading raised an urgent low at 22:58:59 and the backfill of the same period retracted it at 22:59:00, which also stopped the in-process alarm audio one second after it started. Skip any batch whose newest sample is not newer than the last evaluated reading. Backfill still reaches the glucose store; it just cannot override an alert decision made on a newer reading. --- Loop/Managers/Alerts/GlucoseAlertManager.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Loop/Managers/Alerts/GlucoseAlertManager.swift b/Loop/Managers/Alerts/GlucoseAlertManager.swift index 45b3ce8b38..aa04e34817 100644 --- a/Loop/Managers/Alerts/GlucoseAlertManager.swift +++ b/Loop/Managers/Alerts/GlucoseAlertManager.swift @@ -559,6 +559,13 @@ final class GlucoseAlertManager: ObservableObject { os_log("Skipping stale sample", log: log, type: .debug) return } + // CGMs deliver the live reading and then backfill. A batch whose newest + // sample is no newer than the one already evaluated must not re-decide + // — and in particular must not retract — the alert that reading raised. + if let evaluated = latestReading, latest.date <= evaluated.date { + os_log("Skipping batch older than the latest evaluated reading", log: log, type: .debug) + return + } latestReading = (latest.quantity.doubleValue(for: .milligramsPerDeciliter), latest.date) let config = activeConfiguration(at: now) let mgdl: Double