Skip to content

[Safety][ComboV2] Unknown bolus outcome is reported as zero delivery and does not guard subsequent requests #30

Closed as not planned

Description

@birdfly

Code-level safety defect

ComboV2 conflates an unknown outcome after communication loss with confirmed non-delivery. This leaves a gap between accepting a non-idempotent command and recording its eventual pump-history entry.

This is a synthetic reproduction derived from public source code, not patient logs or an individual medical event. Related reports: nightscout/AndroidAPS#4378 and nightscout/AndroidAPS#4240.

Synthetic software reproduction

Use a scripted pump:

  1. Submit request A. Reply Bolus started: true, then return partial progress.
  2. Break the transport before a completed history entry is available. Make cancellation fail on that disconnected transport.
  3. ComboV2Plugin.deliverTreatment() catches the exception and returns success=false enacted=false bolusDelivered=0.0 when lastBolusFlow is null.
  4. Before history for A arrives, submit independent request B. There is no durable unresolved-request guard in this path.
  5. Reconnect, complete B, and return DELIVERED with zero remaining.
  6. Return a history delta containing A's delayed infusion, B's request and B's infusion.
  7. Both infusions are forwarded for ledger insertion, then Pump.deliverBolus() throws UnaccountedBolusDetectedException because it counts more than one StandardBolusInfused entry. Completed request B is reported as failed.

No automatic resend is required: A and B are independent requests.

Source paths

At Boost baseline fde4735649:

  • pump/combov2/src/main/kotlin/info/nightscout/pump/combov2/ComboV2Plugin.kt: generic exception handling and the lastBolusFlow/zero fallback in deliverTreatment().
  • pump/combov2/comboctl/src/commonMain/kotlin/info/nightscout/comboctl/main/Pump.kt: post-delivery history-delta counting in deliverBolus().
  • implementation/src/main/kotlin/app/aaps/implementation/queue/commands/CommandBolus.kt: accompanying carbohydrates are committed only when result.success is true; outcome distinctions also matter here.

Expected behaviour

  • Persist a pending request before a command might reach the pump; conservatively account for uncertain delivery without duplicating it when history arrives.
  • Do not resend the original non-idempotent command as a reconnect strategy.
  • Double-check with read-only status/history queries; protect subsequent dose-increasing requests while the outcome remains unresolved.
  • Bound synchronous verification and background retries. Do not leave the UI/queue waiting indefinitely or silently turn unknown delivery into zero when a timer expires. Provide an explicit, audited recovery path.
  • Associate history with its original request. Distinguish confirmed delivery with a history discrepancy from confirmed non-delivery and unknown outcome. Do not simply suppress unexpected-history errors.

No patient data, real doses, timestamps, hardware identifiers or raw logs are included. This is a source-level report, and no hardware validation of a proposed fix is claimed.

Activity

  1. birdfly commented on Oct 21, 2026

    @birdfly
    Author

    Tracking upstream at nightscout/AndroidAPS#5359. The affected paths were rechecked against AndroidAPS master commit aa16db6. Closing this fork-specific report to avoid duplicate tracking; this does not mean the defect is fixed. The upstream report contains source analysis and a synthetic reproduction recipe only, with no claim of upstream hardware validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions