Skip to content

Dash Offline Basal Fallback Feasibility Review

Last updated: 2026-05-06 17:30 EDT Status: Team review required Owner: BionicLoop engineering

Purpose

This note evaluates a specific question for DASH operation:

  • If phone and pump are separated for more than a defined threshold, can the pod already have a pending fallback basal that will activate without further app communication?

This is narrower than the existing general "offline basal fallback" idea already captured in product and architecture docs. The core question here is whether the fallback can be armed ahead of time so that it starts later on the pod if the phone is no longer able to communicate.

Executive Summary

Current repo evidence supports this conclusion:

  1. A pod-side autonomous "pending fallback basal" is not currently shown to be supported by the BionicLoop pump abstraction or the current OmniBLE surface.
  2. The current codebase clearly supports only immediate dosing actions: immediate temp basal, cancel temp basal, suspend, resume, and immediate basal schedule replacement.
  3. True autonomous post-disconnect fallback is only plausible through a masked fallback-schedule design, not through a later threshold-time command once communication is already gone.
  4. In that design, the pod's active basal schedule must already be a fallback schedule, and the app must keep it masked with repeated 0.0 U/hr temp basals while communication remains healthy.
  5. Resume accounting is a real blocker, not a detail. If offline basal is ever delivered during a communication blackout, the resumed algorithm path needs a reliable representation of what basal insulin was actually delivered during the blackout. The underlying algorithm bridge supports this concept, but the current app/core host path does not yet expose enough delivery history.
  6. This reconciliation problem is broader than offline basal alone. The same reconnect truth model must also resolve accepted-but-uncertain meal boluses and other in-flight pump commands so Home/UI state, duplicate blocking, and cancel affordances are driven by authoritative request identity instead of a generic pump delivering state.

Recommended product position for now:

  • Treat true autonomous post-disconnect fallback as the product goal.
  • Use a masked fallback-schedule design for the current feasibility path.
  • Use the safety-track nominalBasal as the fallback source. The current implementation now maintains a Swift-side q5 nominal-basal profile and programs a four-period local-time fallback schedule when at least one profile observation is available.
  • Keep a single-rate scalar fallback as the safe fallback-of-the-fallback only when the q5 nominal profile cannot yet produce a schedule.
  • Defer any instantBasal-driven autonomous schedule shaping until the algorithm owner confirms whether that extra complexity is warranted.
  • Require a separate design for resume-time basal reconciliation before any shipping implementation.

Current staged implementation approach after algorithm-owner feedback:

  1. Expose the algorithm's existing hourly basal outputs (nominalBasal, instantBasal) through the Swift bridge and runtime telemetry.
  2. Run a secondary/safety algorithm track using the same accepted inputs as the primary track, but derive its target from the active target:
  3. if active target is 110 mg/dL or below, use 120 mg/dL
  4. if active target is already 120 mg/dL or higher, raise to the next higher allowed target, capped at the highest target
  5. Preserve separate persisted state for that safety track and persist its latest fallback-basal candidate separately from the primary command path.
  6. The current staged implementation persists both primary and secondary/safety q5 nominal-basal profiles in runtime state, built from each track's scalar nominalBasal output at every successful or replayed algorithm step.
  7. For the current autonomous command path, derive a four-period fallback basal schedule from the secondary/safety q5 nominal profile:
  8. update the 288 local-time 5-minute slots with safety-track nominal basal values
  9. keep up to seven observations per slot
  10. impute unobserved slots from observed slot averages, so a step-1 profile is usable and improves as more local-time history is collected
  11. average four 72-slot blocks (00:00-06:00, 06:00-12:00, 12:00-18:00, 18:00-24:00)
  12. round each six-hour bucket through the pump service before programming
  13. While communication remains healthy, keep that fallback schedule masked with repeated 0.0 U/hr temp basals using the DASH-supported 30 minute duration window.
  14. For an already-active mask, enter the maintenance renewal window when 20 minutes or less remain on the current 30 minute mask so renewal can happen before the next loop execution rather than waiting for a later successful-step callback.
  15. Refresh the masked fallback schedule at most at the configured refresh cadence while communication remains healthy and the derived four-bucket schedule changes, but treat refresh as a controlled reprogram-and-immediate-remask maintenance sequence rather than a neutral schedule write. The current hardware-dev cadence remains shorter than the intended production cadence and is intentionally code-configurable.
  16. Current audible-behavior expectation for field testing: because the existing OmniBLE basal-schedule programming path is classified as a manual/profile save command, fallback arm and each 6 hour schedule refresh may emit the normal DASH confidence beep when pod confidence beeps are enabled. The connected 0.0 U/hr temp-basal mask itself follows the existing automatic temp-basal beep rules and should stay silent unless the pod is configured for extended automatic-command beeps. For the current branch, accept the schedule-programming beep as known behavior; users who want silent fallback maintenance must disable pod confidence beeps or silence the pod.

Nominal-basal schedule notes from Algo2015/Algorithm_2015_10_13.cpp review:

  • The algorithm sampling period is Ts = 5 minutes, so N_PER_DAY = 288.
  • The current Swift bridge only copies scalar nominalBasal and instantBasal from AlgorithmStepOutputData. It does not yet expose q5BasalRates[288] or hourlyBasalRates[24].
  • In Output_To_CoreData(), the scalar outputs are weight-scaled U/hr values: nominalBasal = R_w * Hrly_B0_Basis[L_BP] and instantBasal = R_w * Hrly_B_Basis[L_BP].
  • The array outputs currently exposed by AlgorithmStepOutputData are copied from Q5BRs and HrlyBRs. Q5BRs is the algorithm's 288-slot active / BR-scaled time-of-day basal profile at 5-minute resolution. HrlyBRs is built as 24 hourly averages, each averaging 12 adjacent 5-minute Q5BRs values.
  • The nominal companion profile is Q5BR0s, populated from Hrly_B0_Basis, but it is not currently exposed in AlgorithmStepOutputData. If fallback should use nominal rather than active/instant basal shaping, the bridge needs a nominal 288-point and/or 24-point output instead of reusing the current q5BasalRates[288] field.
  • OL_BasalProfiles() builds Q5BRs from same-time-of-day history. If fewer than 288 steps are available, it fills observed slots from Hrly_B_Basis and fills the rest of the day with the observed average. Once at least one day exists, each 5-minute slot is averaged across the same time-of-day slot for up to the prior 7 days.
  • The C++ comment next to HrlyBRs says the pod-facing rate should be weight-scaled and rounded from R_w * HrlyBRs. Therefore any Swift-exposed schedule array should be normalized to U/hr before UI display, telemetry, or pod programming so it matches the scalar nominalBasal units.
  • A four-period nominal fallback schedule can be derived from a future Swift-exposed nominal 288-point profile by averaging four 72-slot blocks: 00:00-06:00, 06:00-12:00, 12:00-18:00, and 18:00-24:00. Equivalent derivation from a future nominal hourlyBasalRates[24] companion is to average each group of six hourly values. The resulting PumpBasalSchedule entries would start at 0, 21600, 43200, and 64800 seconds.
  • Current implementation note: before exposing Q5BR0s through the C++ bridge, Swift builds an interim nominal q5 profile from the scalar nominalBasal reported at each step. This lets the feasibility branch test four-period fallback schedule behavior now while preserving the bridge-owned nominal array exposure as a follow-up improvement.
  • The maintenance sequence is:
  • keep renewing the active 0.0 U/hr mask while communication remains healthy, but only once the current mask is inside its final 20 minutes
  • perform that renewal before the next loop execution when pump maintenance safety gates pass
  • if renewal is blocked by active bolus or another unsafe pump state while the current mask is still active, record deferred maintenance and retry on the next safe wake instead of raising an immediate hard failure
  • if successful step execution stalls or deferred maintenance runs long enough for the active mask to expire, allow fallback delivery to activate and record that transition for reconciliation
  • if the rounded fallback rate did not change materially, continue normal mask renewal and leave the programmed schedule alone
  • if the rounded fallback rate changed materially, wait for a healthy connected window with no active bolus and known pump state
  • replace the programmed fallback schedule even though DASH will interrupt current delivery as part of that write
  • immediately reapply the 0.0 U/hr / 30 minute mask in the same connected maintenance sequence
  • if schedule replacement or remask fails, surface a high-severity condition because the underlying fallback schedule may now be exposed while the phone is still connected
  • on session reset/disarm, attempt to restore the original programmed basal schedule rather than leaving the fallback schedule armed underneath the pod
  • record restore success or failure as an explicit fallback review event so operators and logs can distinguish a clean disarm from a latent armed fallback state
  • If communication is lost and the current mask later expires, the pod resumes the already programmed nominal-derived fallback schedule autonomously.
  • Keep instantBasal exposed in telemetry and review surfaces for future analysis, but do not make it part of the first autonomous masked fallback command path.
  • Keep TMAX aligned with the primary track; no fallback-specific TMAX policy is currently needed for basal-only offline mode.

Deferred OmniBLE refinement

  • Backlog a small OmniBLE enhancement for a silent masked-fallback maintenance schedule-programming path. The minimal desired shape is an explicit maintenance/silent schedule-write mode that forces acknowledgementBeep = false for fallback arm, refresh, and disarm while preserving the existing user-facing confidence-beep behavior for ordinary manual/profile schedule changes.

Current Documented Intent

The repo already describes offline basal fallback as a planned behavior:

  • Requirements: proposed offline basal after >= 15 minutes with no valid CGM plus algorithm run.
  • Architecture: revert to predefined offline basal on DASH, show offline indicator, then replace with current algorithm recommendation once CGM resumes and the algorithm runs.
  • OmniBLE API notes: same proposal, with a note to reconcile missing delivery events when returning online.
  • Execution Plan: "Extended fallback execution (offline basal) implementation" is still parked, not implemented.

Important distinction:

  • Those docs describe an offline fallback concept.
  • They do not prove that DASH currently supports a pre-armed delayed fallback which starts later without new controller communication.

What The Current Pump Surface Actually Supports

BionicLoop pump abstraction

The app/core pump abstraction currently exposes only immediate actions:

  • refreshStatus()
  • deliverBolus(units:)
  • setTempBasal(rateUnitsPerHour:duration:)
  • cancelTempBasal()
  • suspendDelivery()
  • resumeDelivery()

See:

  • BionicLoopCore/Sources/BionicLoopCore/Ports/PumpService.swift
  • BionicLoop/Integrations/Pump/PumpServiceAdapter.swift

There is no app-facing concept of:

  • "schedule this basal to begin later"
  • "arm this fallback only if communication is lost"
  • "program a watchdog timer that changes delivery mode if no new controller command arrives by time T"

Current answer at the app layer:

  • BionicLoop today can issue only immediate commands.
  • It cannot queue a second future command behind a current command.

OmniBLE temp basal support

Current OmniBLE dosing support is immediate:

  • enactTempBasal(unitsPerHour:for:)
  • runTemporaryBasalProgram(unitsPerHour:for:automatic:)

See:

  • OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManager.swift

The temp basal API takes only a rate and duration. It does not expose a delayed start time or a conditional "activate later if disconnected" primitive.

Important command constraints confirmed in the current OmniBLE implementation:

  • supported temp basal durations are 30 minutes to 12 hours
  • duration 0 is a special cancel/resume-scheduled-basal case, not a 0-minute future programming primitive
  • supported temp basal rates do include 0 U/hr

Implication:

  • a 0 U/hr temp basal is available
  • a 15-minute temp basal is not available through the current Dash surface

This matches the public DASH user-facing behavior described in the official Omnipod DASH Technical User Guide, which documents temp basals as 30 minutes to 12 hours and describes basal program changes as explicit immediate activation decisions rather than delayed future-start programming.

OmniBLE basal schedule support

OmniBLE basal schedule support

OmniBLE does also support a basal schedule and immediate basal schedule replacement:

  • OmniBLE/OmniBLE/OmnipodCommon/BasalSchedule.swift
  • OmniBLE/OmniBLE/PumpManager/OmniBLEPumpManager.swift (setBasalSchedule)

But that is not the same as a future pending fallback.

Current evidence shows:

  • the schedule is a full 24-hour basal profile
  • writing it is immediate
  • setBasalSchedule(...) cancels current delivery before saving the new profile

So, while the pod can autonomously run a programmed basal schedule, the current repo does not show a clean one-shot "activate fallback later if controller goes away" feature. Repeatedly rewriting the pod basal schedule as a rolling future fallback is only a theoretical idea at this point, and would be a high-risk design change because it changes the pod's underlying autonomous schedule, not just a temporary command.

Additional current-app constraint:

  • BionicLoop does not currently maintain a dynamic algorithm-owned basal program on the pod.
  • The current DASH setup flow initializes the pod-facing basal schedule with an all-day 0.0 U/hr schedule during onboarding.
  • No current app runtime path continuously rewrites the pod basal schedule on every algorithm step.

So there is no existing "true dosing basal rate" sitting on the pod that a temp basal would naturally revert to in closed-loop operation.

Direct Answer To The Proposed Command Pattern

Question under review:

  • With each successful algorithm step while the pump is available, can we set an immediate 15-minute window at 0.0 U/hr, and have a true dosing basal rate begin after that window so it only matters if the phone later stops talking to the pump?

Current answer:

  • Not with the currently demonstrated command surface.

Why not:

  1. Temp basal duration cannot be 15 minutes.
  2. Current Dash support here is 30 minutes to 12 hours, with 0 reserved for cancel/resume.
  3. Temp basal does not queue a second future dose command.
  4. When temp basal ends, the pod reverts to the active basal program.
  5. There is no current app command such as "start this other basal later."
  6. BionicLoop does not currently keep a dynamic algorithm-owned basal program on the pod.
  7. The current app setup path seeds a 0.0 U/hr basal schedule.
  8. The runtime does not currently rewrite basal schedule on every loop step.
  9. Rewriting the full basal schedule every step to fake a delayed future start would be a fundamentally different architecture.
  10. setBasalSchedule(...) is immediate.
  11. It cancels current delivery and replaces the active pod basal program.
  12. It is not a delayed conditional fallback mechanism.

What is technically closest?

The closest currently available patterns are:

  1. Immediate 0 U/hr temp basal for 30 minutes, after which the pod reverts to whatever active basal schedule is already programmed.
  2. Immediate basal schedule replacement, where the pod begins following the new schedule right away based on the current schedule offset.

Neither of these is the same as:

  • "arm a pending fallback to activate in 15 minutes if the controller goes silent"

Why the "0 now, real rate later" workaround is risky

Even if engineering tried to emulate this by rewriting the full basal schedule, the behavior would be risky because:

  • the schedule replacement is immediate, not pending
  • the rewrite would affect the pod's autonomous baseline delivery, not just a temporary fallback
  • the runtime would need to keep pod schedule state synchronized with every algorithm step
  • resume accounting would become even more important because the pod would be autonomously delivering from a rewritten schedule during blackout

Feasibility Assessment By Approach

Approach A: Pre-armed pending basal on pod that starts later after separation

Assessment: Not established by the current codebase. Low confidence / unproven.

Why:

  • No current BionicLoop abstraction exposes delayed or conditional pump commands.
  • No current OmniBLE temp basal surface exposes delayed start.
  • The only autonomous pod-side programmable delivery behavior visible here is the regular basal schedule, and the available API replaces it immediately.
  • The repo does not contain a pod-side watchdog concept such as "if no controller contact by threshold, switch to fallback basal."

What would need to be proven before this could be treated as feasible:

  • that the Dash protocol can encode a future-start or conditional basal behavior at the pod level, or
  • that a rolling basal-schedule rewrite approach is clinically acceptable, technically robust, and compatible with the current closed-loop design

Current conclusion:

  • Do not assume this is feasible from existing implementation evidence.

Approach B: App issues fallback basal immediately when threshold is reached and comms is still alive

Assessment: Feasible in principle. Medium confidence.

Why:

  • Current surfaces can issue immediate temp basal.
  • Current runtime docs already contemplate entering an offline mode after a threshold.
  • User-facing offline indicators and alerting fit the current runtime model much better than a hidden pod-side pending schedule.

Major work still required:

  • explicit offline-mode state machine
  • threshold monitor and trigger ownership
  • fallback basal selection policy
  • duration cap and user action rules
  • resume/recovery reconciliation
  • operator-facing review surfaces for fallback details (for example Recent Dose Steps showing fallback rate, selection source, safety target, and reconciliation status)
  • verification on real hardware

Approach C: Separation happens before threshold, and no comms is available at threshold

Assessment: Not feasible with currently demonstrated behavior.

Why:

  • if the phone cannot communicate with the pod at threshold time, the app cannot issue a new temp basal then
  • the current repo does not demonstrate a previously armed delayed fallback that the pod can autonomously start later

Practical implication:

  • if the product requires safe fallback even when separation begins before the threshold is reached, then either:
  • a real pod-side autonomous fallback capability must be proven, or
  • the system must rely on whatever autonomous basal program is already running on the pod by design

Resume And Reconciliation: Why This Is A First-Class Design Problem

Current positive evidence

The pump integration already has recovery-oriented building blocks:

  • recoverUnacknowledgedCommand(using:) in OmniBLE/OmniBLE/PumpManager/PodCommsSession.swift
  • dosesForStorage(...) in OmniBLE/OmniBLE/PumpManager/PodCommsSession.swift
  • storage of NewPumpEvent records in BionicLoop/Integrations/Pump/AppPumpManagerDelegate.swift

This is useful because it means BionicLoop does have a basis for reconciling what happened on the pod after uncertainty or disconnection.

Current limitation in the algorithm host path

The algorithm bridge can represent basal backfill across a blackout:

  • basalInsulinDelivered
  • deliveryTime

See:

  • BionicLoopCore/Sources/Algo2015Bridge/include/AlgorithmInterface.h

That is exactly the sort of information needed when a delivery happened during a communication gap and the resumed step needs to account for it.

But the current app/core host path is much narrower:

  • PumpStatus carries only one lastDelivery record
  • RealBUDosingAlgorithm only maps one request time plus requested/delivered units into the algorithm input

See:

  • BionicLoopCore/Sources/BionicLoopCore/Domain/PumpStatus.swift
  • BionicLoopCore/Sources/BionicLoopCore/Algorithms/RealBUDosingAlgorithm.swift

Conclusion on algorithm needs

Yes, the algorithm effectively needs delivered-basal information on resume if an offline basal fallback has been running during a blackout.

Without that:

  • first resumed dosing decisions may underestimate or overestimate insulin on board
  • recovery behavior will depend on incomplete delivery history
  • the system could double count, undercount, or miss fallback insulin delivered while disconnected

So resume accounting is not optional. It is part of the core safety case for offline basal fallback.

Shared Reconnect Reconciliation Scope

Offline fallback should not be treated as an isolated resume problem. The repo already has a smaller version of the same issue for meal announce:

  • a meal request can be accepted
  • communication can become uncertain before delivery truth is confirmed
  • the app must block duplicate meal entry until pump evidence proves what happened

That means the reconnect design should be shared across all insulin-affecting flows, not split into one solution for fallback basal and another for meal announce.

At minimum, the reconnect reconciliation model needs to answer:

  1. What command or schedule was active when communication was lost:
  2. meal bolus
  3. ordinary loop bolus
  4. temp basal / masked fallback basal
  5. suspend / resume interaction
  6. What pod-side evidence is authoritative after reconnect:
  7. current PumpStatus.lastDelivery
  8. stored pump events / dosesForStorage(...)
  9. command outcome certainty vs uncertainty
  10. What UI affordance is safe before truth is established:
  11. generic "pump delivering" block
  12. explicit meal-delivery cancel action
  13. blocked closed-loop resume
  14. degraded/manual recovery path

Two practical implications follow:

  • Home/UI must not infer a meal-specific cancel path from generic pump delivery alone. It needs a reconciled request identity that says the active delivery is actually the accepted meal request.
  • If fallback basal is ever allowed during disconnect, the same reconciliation layer must classify and settle that autonomous delivery before normal closed loop resume, just as uncertain meal delivery must be settled before another meal can be announced.
  • Operator review surfaces must expose reconciled fallback details after the fact. Recent Dose Steps should show whether a recorded fallback rate came from instantBasal or nominalBasal, what safety target drove that rate, when the fallback command was issued, and whether later reconnect evidence confirmed, corrected, or canceled that delivery.

Safety And Product Risks

Main safety concerns:

  1. Incorrect autonomous insulin after loss of communication.
  2. False belief that fallback started when the pod never actually accepted it.
  3. Double counting delivered insulin on resume.
  4. Missing delivered insulin on resume.
  5. Interference between fallback basal and current suspension / temp basal / command uncertainty states.
  6. Extended offline duration without clear patient-visible status.
  7. Hidden controller-schedule behavior that clinicians and operators cannot easily understand.

Specific design risk with a rolling future-schedule approach:

  • If the app repeatedly rewrites the pod basal schedule to keep pushing out a fallback threshold, schedule-management bugs could directly affect autonomous pod behavior even while closed-loop is otherwise healthy.
  1. Treat a true pod-side pending fallback as unproven.
  2. Do not implement it based only on current app-layer assumptions.
  3. If the product still needs offline basal fallback, pursue a masked fallback schedule with nominal-derived autonomous pod delivery after mask expiry.
  4. Treat instantBasal as review-only input for now, not as part of the first autonomous schedule contract.
  5. Gate any implementation on resume-time delivery reconciliation design.
  6. Treat reconnect reconciliation as a shared cross-command subsystem covering fallback basal, uncertain meal bolus, and other in-flight insulin commands, not as a fallback-only appendix.

Use this framing in team discussions:

  • "Offline basal fallback is potentially feasible as an app-issued immediate fallback when the threshold is reached and the pump is still reachable."
  • "A pre-armed pod-side pending fallback basal is not yet demonstrated by the current Dash/OmniBLE implementation surface."

Refined Design Under Review: Masked Fallback Schedule

The current team discussion has narrowed from "pending basal that starts later" to this design:

  1. keep an offline fallback basal schedule active on the pod using setBasalSchedule(...)
  2. during healthy closed-loop operation, keep that schedule masked with repeated 0.0 U/hr temp basal commands
  3. if communication is lost, the most recent 0.0 U/hr temp basal eventually expires and the underlying fallback basal schedule becomes active

Mechanical feasibility

This is more plausible than a true delayed-start pending basal, but it is still not a trivial change.

What currently lines up:

  • Dash supports 0 U/hr temp basal.
  • Dash temp basal minimum duration is 30 minutes, which is acceptable if the agreed watchdog window can be 30 minutes rather than 15 minutes.
  • Dash supports immediate basal schedule replacement through setBasalSchedule(...).

What this means operationally:

  • the fallback schedule would not be "pending"
  • it would be the currently active pod basal program underneath a continuously renewed 0.0 U/hr temp basal mask

Critical command-order constraint

The order matters:

  1. write or refresh the fallback basal schedule
  2. immediately apply the masking 0.0 U/hr temp basal

Why:

  • setBasalSchedule(...) cancels current delivery and immediately activates the new schedule
  • if the schedule refresh succeeds and the following mask command fails, the fallback basal starts immediately

This is the main safety hazard of the masked-schedule approach.

Low-cadence refresh possibility

For the first single-rate masked implementation, the current recommendation is to refresh the programmed fallback schedule no more often than every 6 hours, using a controlled reprogram-and-immediate-remask maintenance sequence instead of attempting to rewrite it every loop step.

That is attractive because it reduces:

  • schedule churn
  • immediate-activation risk frequency
  • command traffic

But even with low-cadence refresh, the design still depends on:

  • reliable repeated 0.0 U/hr / 30 minute masking while comms is healthy
  • a clearly enforced 20 minute renewal window so the next safe wake can renew the mask before it reaches actual expiry
  • deferred-not-failed handling when active bolus temporarily blocks renewal but the current mask is still active
  • a clearly defined source for the fallback schedule
  • a maintenance sequence that rewrites the programmed schedule and immediately reapplies the 0.0 U/hr mask while comms is still healthy
  • explicit safety handling for the brief delivery interruption caused by DASH schedule replacement, including “do not run during active bolus” gating and alerting if remask fails
  • a matching restore/disarm sequence that attempts to put the original programmed basal schedule back on the pod when the algorithm session is intentionally reset or disarmed
  • resume-time accounting when the fallback schedule delivers during blackout, limited to same-pod pump-reported evidence

Six hours is a reasonable starting cadence because it is:

  • materially more responsive than a once-daily refresh for dynamic diabetes needs
  • still infrequent enough to keep disruptive schedule replacement on a bounded, reviewable arm/re-arm cadence
  • compatible with a future move from a single fallback rate to a fuller time-of-day fallback schedule without changing the masked-fallback contract

Fallback Schedule Source: Safety-Track Target Escalation

The current design question is not just whether the pump can run the fallback. It is also:

  • how BionicLoop should derive the fallback basal schedule, specifically for a conservative safety target derived from the active target

Current target input support

The good news is that stepped safety targets are already first-class algorithm inputs in this repo.

Current path:

  • clinician config persists targetMgdl
  • runtime constructs the algorithm with setPointNominal and setPoint
  • current branch work exposes hourly-basal outputs from the algorithm bridge so fallback-rate selection can be reviewed against real telemetry before command wiring is enabled
  • RealBUDosingAlgorithm passes those values directly into the bridge each step

See:

  • BionicLoop/Runtime/ClinicalAlgorithmConfigStore.swift
  • BionicLoop/Runtime/LoopRuntimeEngineOperationalSupport.swift
  • BionicLoopCore/Sources/BionicLoopCore/Algorithms/RealBUDosingAlgorithm.swift
  • BionicLoopCore/Sources/Algo2015Bridge/Algo2015Bridge.c

So, if fallback should represent an escalated safety target, the input side is not the hard part.

Why a scalar factor is not acceptable

One tempting shortcut is:

  • run the live algorithm at the current target
  • apply a factor to the resulting basal-related output
  • treat that as the safety-target equivalent fallback

The current code and tests do not support that assumption.

Why not:

  • target is a direct algorithm input, not an external post-processing knob
  • the algorithm is stateful across steps
  • current tests only prove monotonic direction, not linear or proportional convertibility
  • production output currently exposes requested insulin for the actual run, not a transformable "target factor" contract

Evidence:

  • BionicLoopCore/Tests/BionicLoopCoreTests/Algo2015MetamorphicTests.swift
  • BionicLoopCore/Tests/BionicLoopCoreTests/Algo2015DifferentialReplayTests.swift

Safe conclusion:

  • higher target tends not to increase insulin
  • lower target tends not to decrease insulin
  • but the repo does not justify using a fixed multiplier to convert one target's output into another target's output

If the fallback schedule must reflect a true safety-target algorithm track, the safest design is:

  1. run a dedicated fallback algorithm track configured from the active target
  2. persist state for that fallback track separately from the live control track
  3. derive the fallback schedule from that dedicated track, not from a factor applied to the current live-target run

This could be implemented as a shadow algorithm instance or an explicit fallback basal provider contract. Either way, it should be treated as a real algorithm integration feature, not a UI/runtime heuristic.

Candidate data surfaces

There are two broad ways to source fallback basal data:

  1. Recommended:
  2. add an explicit runtime/algorithm contract for fallback basal rate or schedule generation at target 120

  3. Not recommended without algorithm-owner signoff:

  4. infer fallback schedule from inspection-only fields such as hourlyBasalBasisActive, hourlyBasalBasisNominal, or related inspection snapshots

Those inspection fields do exist:

  • BionicLoopCore/Sources/BionicLoopCore/Domain/AlgorithmInspectionTelemetry.swift
  • BionicLoopCore/Sources/BionicLoopCore/Algorithms/Algo2015InspectionSnapshotAdapter.swift

But they are currently inspection/debug surfaces, not the production dosing contract. Shipping the fallback schedule from those fields without a formal contract would be risky.

Resume And Reconciliation Impact For The Masked-Schedule Design

The masked-schedule design does not remove the recovery problem. It makes it more important.

If the mask expires during communication loss and the fallback schedule delivers autonomously, the resumed algorithm path must know:

  • how much basal was delivered
  • over what period
  • whether delivery certainty is known or uncertain

Current bridge capability is promising:

  • basalInsulinDelivered
  • deliveryTime

Current host/runtime limitation remains:

  • only one lastDelivery record is carried into PumpStatus
  • production algorithm execution currently treats basalInsulinRequested as a 5-minute micro-dose output, not as a reusable hourly schedule source

So any masked-schedule implementation must include a dedicated resume-time basal reconciliation design before it should be treated as shippable.

Conflict With The Current Degraded-Stepping Model

There is a direct architectural conflict between autonomous fallback basal on the pod and the current live algorithm stepping policy.

What the current runtime does today

Current runtime policy intentionally allows the live algorithm to keep stepping when CGM is fresh but pump status is unavailable:

  • the coordinator refreshes pump status and falls back to an unavailable pump input tuple when refresh fails or pump state is unknown
  • the algorithm still executes that 5-minute step
  • only pump command application is blocked until pump status recovers

See:

  • BionicLoopCore/Sources/BionicLoopCore/Runtime/LoopRuntimeCoordinator.swift
  • BionicLoopCore/Tests/BionicLoopCoreTests/LoopRuntimeCoordinatorPumpAvailabilityExecutionTests.swift
  • BionicLoopCore/Tests/BionicLoopCoreTests/SimulationHarnessTests.swift
  • Requirements
  • Architecture

This policy is correct for the current product because the pod is not expected to continue autonomous algorithm-directed fallback dosing underneath those degraded steps.

Why autonomous fallback basal changes that assumption

If the pod can begin delivering fallback basal while communication is lost, then the live algorithm cannot safely continue advancing through those same 5-minute intervals with "pump unavailable" sentinel input and no delivered-basal truth.

Otherwise:

  • the live algorithm state will already have advanced across the blackout interval
  • the algorithm's internal stacked-insulin state will not include the fallback basal actually delivered on the pod
  • reconnect-time "replay" becomes a state-correction problem against already advanced live state, not a clean deterministic reconstruction

In other words:

  • current degraded stepping is compatible with "no dosing applied while pump is unavailable"
  • it is not compatible with "pod may be autonomously dosing fallback basal during that same interval"

Implication for a masked fallback schedule

If masked fallback basal is ever pursued, BionicLoop will likely need a new policy for those intervals:

  1. detect when fallback basal may have become active
  2. stop treating the current live degraded-step path as authoritative state
  3. prevent normal closed-loop resume until delivered basal across the blackout interval is reconciled with sufficient confidence

There are only a few viable architecture options:

  1. Recommended:
  2. freeze live algorithm step advancement once fallback basal may be active
  3. on reconnect, replay missed 5-minute steps using historical CGM/BG inputs plus reconstructed delivered basal per step

  4. Higher risk:

  5. continue a speculative live state during outage, but discard it and rebuild authoritative state by replay on reconnect

  6. Only viable with extremely strong evidence:

  7. continue stepping live only if the host can deterministically inject the exact fallback basal delivered on each missed step as trusted input

At present, the repo does not show enough host-side delivery history or reconciliation fidelity to support option 3.

Current branch guardrail

The current feasibility branch now implements the first half of the recommended shape:

  • maskExpiredOffline persists a reconciliation-required masked-fallback recovery state
  • while that state is present, ordinary loop stepping, manual BG execution, meal announce, and new algorithm arm are blocked
  • while that state is present, runtime now attempts connected restore/disarm of the original programmed basal schedule on runtime start, app foreground, or pump reconnect
  • if that restore succeeds while the loop remained armed and reconnect evidence is confirmed or corrected, runtime clears the masked-fallback recovery state, preserves the existing session/cadence anchor, and replays the missed fallback-delivery slots before resuming the current due 5-minute step in the same session only when same physical pod continuity and credible pump-reported delivery delta are proven. If reconnect evidence is ambiguous, the pod is different/new, pod identity is unknown, or delivery history is discontinuous, runtime keeps the existing explicit feasibility path: preserve cadence/session and resume the current due slot without replay, marked as unreconciled. If the operator explicitly reset or turned the loop off first, recovery restores the original schedule but keeps the loop off
  • if that restore fails, the blocked recovery state remains pending for later retry
  • if a valid fallback candidate already exists but no masked fallback is currently armed, pre-execution maintenance now arms fallback before the next step so a bolus from that step cannot race the first mask application
  • bolus-blocked mask-renewal errors are normalized into deferred maintenance while the current mask is still active, including late unfinalizedBolus failures returned by the pump-command seam
  • reconnect recovery now captures a basal-only pump snapshot containing the programmed basal schedule, recent automatic temp-basal evidence, and pod cumulative delivered-insulin total; against persisted fallback context, that snapshot yields confirmed, corrected, or ambiguous fallback-exposure classification
  • Home Recent Dose Steps now surfaces both modeled fallback delivery and the pump-reported delivered insulin delta since the last connected fallback baseline when that hardware evidence is available
  • basal-only same-session replay is now implemented for confirmed / corrected reconnect recovery using a replay plan over missed 300 second slots plus historical CGM and reconstructed fallback delivery; remaining follow-on work is broader ambiguous/non-basal reconstruction and final policy on how to handle insufficient evidence beyond the explicit unreconciled feasibility path

Replay viability conclusion

Replay is still the best recovery shape if autonomous fallback basal is used, but only if the system can reconstruct:

  • the exact time the masking 0.0 U/hr temp basal expired
  • the fallback schedule that was active underneath
  • whether pod state remained suitable for delivery throughout the blackout
  • per-step basal delivered across the missed 5-minute intervals

If those facts cannot be reconstructed with high confidence, the safe fallback is not replay. It is blocked closed-loop resume plus a degraded/manual recovery path until delivery truth is re-established.

Proposed Investigation And Test Plan

Phase 1: Capability proof

  1. Confirm at the Dash protocol / OmniBLE maintainer level whether a delayed or conditional pod-side fallback basal exists at all.
  2. If not, explicitly close the "pending basal" concept as unsupported and move to app-issued threshold fallback only.

Phase 2: Immediate fallback prototype

  1. Implement a bench-only prototype that issues fallback temp basal when the offline threshold is reached while comms is still available.
  2. Verify pod acceptance, duration handling, alerting, and user-visible offline state.

Phase 3: Resume accounting prototype

  1. Reconnect after fallback basal has been active.
  2. Reconcile delivery using dosesForStorage(...), NewPumpEvent, and pod status where needed.
  3. Design the host-side mapping needed so resumed algorithm steps can consume delivered basal during blackout, not just one last-delivery record.
  4. Include accepted meal-bolus uncertainty in the same prototype so reconnect reconciliation proves:
  5. active delivery classification by request identity
  6. stale delivery-state cleanup
  7. duplicate meal blocking until truth is known
  8. correct Home action routing after reconnect

Phase 4: Failure drills

Run explicit scenarios:

  1. Separation begins before threshold.
  2. Separation begins after fallback temp basal has already been accepted.
  3. Fallback command is sent but acknowledgement is uncertain.
  4. Reconnect occurs before fallback duration ends.
  5. Reconnect occurs after fallback duration ends.
  6. Pump is suspended, faulted, or has no active pod at the time fallback would otherwise be entered.
  7. Meal bolus accepted, then disconnect occurs before delivery truth is known.
  8. Reconnect shows a different active delivery than the last meal request.
  9. Reconnect clears uncertainty with partial meal delivery rather than full completion.

Questions The Team Needs To Decide

  1. Is the product goal specifically a pod-side autonomous masked fallback schedule, and if so is nominal-only sufficient for the first version?
  2. What is the approved threshold for entering offline mode?
  3. What basal source should offline fallback use:
  4. fixed conservative subject schedule
  5. last known safe rate
  6. last accepted algorithm rate
  7. dedicated fallback algorithm output from the safety track
  8. What maximum offline duration is acceptable before requiring user action?
  9. What reconnect/accounting rules apply if the outage passes 60 minutes and the rate source flips from instantBasal to nominalBasal?
  10. Do we require a dedicated shadow algorithm track rather than any output-scaling shortcut?
  11. What resume-time accounting is required before dosing can safely resume?
  12. Do we require this feature for the current IDE scope, or does it remain a post-baseline enhancement?

Bottom Line

Based on the current repository:

  • "Can DASH hold a pending basal that activates later if the phone is gone?" Answer: not proven by the current app or OmniBLE surface.
  • "Can BionicLoop issue an offline fallback basal once the threshold is reached while the pod is still reachable?" Answer: yes, likely feasible.
  • "Can BionicLoop safely estimate the safety-track fallback schedule by applying a factor to the current live-target output?" Answer: no. Current code and tests support target as a first-class algorithm input, not as a safe post-processing multiplier.
  • "Does the algorithm need delivered basal information when communication resumes?" Answer: yes. That is a core safety requirement for any offline basal feature.