Developer Change Plan
Last updated: 2026-03-25 09:35 EDT
This document outlines where code changes are intended to land as the integration work continues. It is meant for internal engineering coordination.
Planning Document Ownership
Docs/Planning/ExecutionPlan.mdis the source of truth for prioritized workstreams, sequencing, and checkbox status.Docs/Planning/DevChangePlan.mddefines intended code boundaries, implementation design notes, and behavior contracts.- If a topic appears in both files, checklist/progress belongs in
ExecutionPlan.md, while architecture/code-location detail belongs here.
Clinical Settings (Workstream K)
Execution tracking: Docs/Planning/ExecutionPlan.md -> Workstream K.
Detailed contract: Docs/Planning/ClinicalAlgorithmConfigContract.md.
UX contract
- Add dedicated
Clinical Settingssection under settings as a navigated destination (chevron row from main settings list). - Gate entry by passcode prompt:
- temporary default passcode:
020508 - non-production control, pending Cognito/role-based auth replacement (Workstream
I) - Keep clinician-only controls out of participant-facing setup sections.
Current implementation status:
- Clinician-only section and passcode gate are implemented in Home settings.
- Subject ID, Weight, Start Algo, and Reset Algo are now hosted under clinician-gated controls.
- Target / meal-upfront / TMAX selectors are implemented with bounded normalization.
- Versioned ClinicalAlgorithmConfigV1 persistence blob is implemented for the clinical config.
- Current focus: participant-facing target governance layered on top of the persisted clinical config.
Locked behavior decisions (next slice):
- Clinical input edits are draft-only until explicit Save confirmation.
- Save must open a review surface showing old -> new values.
- OK commits new settings; Cancel preserves prior applied settings.
- Saving settings does not trigger runtime doWork.
- Runtime consumes committed settings at the next executed algorithm step only.
- Exiting the Clinical Settings destination auto-locks clinician controls.
- Save+OK closes settings after commit and returns user to Home.
- Clinical Settings owns a participant target-access profile:
- Pregnancy -> expose 90/100/110
- Standard -> expose 110/120/130
- Participant-facing target changes require approval capture:
- clinical staff member name
- approximate approval time
- Clinical Settings target options follow the selected participant target-access profile and normalize the draft target into that range when the profile changes.
Clinical-settings telemetry contract (required):
- ui.critical.state_viewed: emitted when save-review sheet opens.
- ui.critical.submit: emitted on Save+OK with old/new values and changed fields.
- ui.critical.cancel: emitted on review cancel/dismiss.
- ui.critical.blocked: emitted when save is blocked by validation/policy.
- ui.critical.state_viewed / submit / cancel / blocked: emitted for participant target-change approval capture with current/requested target, target-access profile, and approval metadata when submitted.
- loop.step.executed includes applied clinical config snapshot (target_mgdl, meal_upfront_percent, tmax_minutes) for activation traceability.
Controls moving into Clinical Settings
Subject IDWeight(lbs integer entry in UI; persisted/used as kg for algorithm input)Start AlgoReset Algo
New clinical configuration controls
- Target selector: profile-bounded options (
Pregnancy: 90/100/110,Standard: 110/120/130) - Meal upfront selector:
75%or90% TMAXselector:40...70in increments of5- Participant target-access profile selector:
Pregnancy/Standard - Participant-facing target buttons:
Pregnancy:90,100,110Standard:110,120,130
Planned implementation touchpoints
BionicLoop/Features/Home/- Move settings rows + control actions into clinician-gated section.
- Keep reusable passcode-gate view/state local to Home settings feature.
BionicLoop/Runtime/- Read/update clinical settings through a single persisted model for runtime use.
BionicLoopCore/Sources/BionicLoopCore/Algorithms/- Consume mapped target/upfront/TMAX values through the algorithm input/config boundary.
BionicLoopCore/Sources/BionicLoopCore/Persistence/- Store versioned clinical settings payload and migration defaults.
Verification hooks to wire
- Unit:
- passcode gate state transitions
- lbs->kg conversion and bounds validation
- selector range/step validation
- UI:
- locked/unlocked behavior
- moved control visibility
- participant target approval capture
- clinical target options follow selected profile and normalize on profile switch
- unchanged start/reset behavior after relocation
Core Loop + Algorithm
BionicLoopCore/Sources/BionicLoopCore/Algorithms/- Extend
RealBUDosingAlgorithmto map additional inputs/outputs as the C++ API evolves. - Translation logic for meal announcements is implemented (
MealAnnouncement-> Algo2015mealTime/mealSize). - Add translation logic for pregnancy targets.
BionicLoopCore/Sources/BionicLoopCore/Runtime/- Enhance
LoopRuntimeCoordinatorscheduling, retry logic, and offline fallback tracking. - Persist last‑run timestamps and loop health state.
Marjorie I/O Parity Workstream
- Detailed comparison and extracted requirements are documented in:
Docs/Analysis/Marjorie_AlgorithmIO_GapAnalysis.md- Priority implementation slices:
- Add canonical per-step telemetry persistence (
input + output + applied delivery) as a single source of truth. - Expand bridge/output mapping to include key fields needed for audit and chart parity.
- Maintain and verify pump-unavailable execution policy (
execute-with-unavailable, command blocked) across relaunch/reconnect cases. - Add test matrix coverage for degraded CGM/pump states and step continuity.
Reconnect fallback baseline (implemented)
- App runtime now listens for pump-status recovery notifications from
PumpStatusObserverand dispatches guardedpumpReconnectwake attempts throughLoopRuntimeEngine. - Guarded reconnect fallback is secondary to CGM and is intentionally not triggered from raw BLE
didConnect. - Current implemented guardrails:
- only after
firstSuccessfulStepAtexists - only when accepted CGM receipt age is
> 5 minutes - current due step only
- no step
0 - no cadence re-anchor
- no backlog replay
- fresh accepted CGM receipt suppresses reconnect fallback again
- Remaining closure work is real-device validation of reconnect/background behavior and same-slot duplicate suppression with physical G7 + DASH timing.
Algorithm Update Plan (Detailed)
- Input mapping:
- Build a single Swift “input model” that mirrors the C++ structs (glucose history, insulin history, device status, user weight, target selection, meal announcements).
- Centralize unit conversions (mg/dL, U/hr, minutes) and keep them in one file to prevent drift.
- Output mapping:
- Translate the C++ recommendation into
DosingRecommendationwith explicit 5‑minute dosing output (bolus/micro‑dose), plus any flags or status codes. - Preserve algorithm status details for logging and UI visibility (e.g., “insufficient data”, “using fallback basal”, “safety limited”).
- State handling:
- Maintain a stable per‑subject state (subject ID, last run time, persistent algorithm state if required by the C++ API).
- Add a versioned “algorithm state blob” store if the C++ interface needs to persist internal state across app restarts.
- Error handling:
- Normalize error codes from the C++ layer into a small set of Swift errors; log full raw codes for debugging.
- Ensure the loop fails closed (no dosing) on malformed inputs.
- Testing strategy:
- Add a golden‑input test harness that runs fixed inputs through the C++ wrapper and checks for deterministic outputs.
- Add “missing data” tests (no CGM, stale CGM, missing pump status).
- Add regression tests for target selection and meal sizing changes.
Algo2015 Full Verification Campaign (Workstream L)
Execution tracking: Docs/Planning/ExecutionPlan.md -> Workstream L.
Verification protocol and targets: Docs/Planning/Algo2015VerificationPlan.md.
Planned implementation touchpoints
BionicLoopCore/Tests/BionicLoopCoreTests/- Add
TV-ALG-*suites:- bridge contract edge cases
- deterministic replay vectors
- state continuity/reload/reset
- pregnancy-config differential replay
- soak/stability replay
Algo2015/+Scripts/- Add an instrumented coverage build/run path for Algo2015 (
llvm-covcompatible outputs). - Keep standard non-instrumented
xcframeworkbuild path unchanged for app builds. Docs/Quality/Evidence/- Add STR artifact structure for algorithm campaign output with command logs and coverage artifacts.
Verification outputs required before closure
- Coverage summary + full report artifacts for C bridge and Algo2015 C++ sources.
- Deterministic vector diff reports for baseline and changed configurations.
- Explicit uncovered-lines rationale log (if thresholds not fully achieved).
Implemented baseline (2026-02-18)
- Added bridge-contract suite in:
BionicLoopCore/Tests/BionicLoopCoreTests/Algo2015BridgeContractTests.swift- Added deterministic golden-vector coverage in:
BionicLoopCore/Tests/BionicLoopCoreTests/Algo2015GoldenVectorTests.swift- First evidence captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-001-004/- Additional evidence captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-005-006-008/- Stateful continuity evidence captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-007/- Added coverage automation script:
Scripts/run_algo2015_coverage.sh- Coverage artifacts captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-010-coverage/- Expanded coverage artifacts captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-010-coverage-v2/- Latest expanded coverage artifacts captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-010-coverage-v7/- Consolidated STR rollup captured:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-rollup-v1/- Current measured coverage (
Algorithm_2015_10_13.cpp): - Function
100.00% - Line
88.33% - Branch
78.87% - Residual uncovered-branch rationale map:
Docs/Quality/Evidence/STR-ALG-001/2026-02-18-tv-alg-010-coverage-v7/uncovered-branch-gap-map.md
Algorithm Changes for Protocol Requirements
- Pregnancy targets:
- Use configurable target set
90/100/110/120/130 mg/dLand surface it in UI + input mapping. - Meal fraction:
- Expose configurable meal upfront options
75%and90%. - Ensure both modes are explicitly traceable/tested in algorithm path.
- Initialization:
- Enforce weight‑only initialization (no carb ratios or correction factors).
- Expose configurable
TMAXrange40...70in increments of5(default remains team-configured). - CGM downtime rules:
- Accept fingerstick BG as CGM input during CGM downtime.
- Use weight‑based basal early, then adaptive basal after >= 24 hours of history.
Loop Timing + Step Semantics (doWork Plan)
Operational cadence assumptions (current hardware behavior)
- CGM cadence assumption: new G7 glucose values arrive approximately every
5 minutes. - Pump transport cadence assumption: Omnipod DASH BLE disconnect/reconnect occurs approximately every
3 minutes(pod-driven). - Implication:
- Current runtime execution is primarily CGM-driven, with explicit user-triggered execution paths for manual BG (
bgCheck) and meal announce (mealAnnounce). - Current implemented policy: pump reconnects are transport/state events and do not independently advance algorithm step.
- Planned future policy under review: pump reconnect may become a guarded fallback wake only after step
0is anchored and only when accepted CGM receipt age has already exceeded the approved freshness limit. - If both G7 and DASH are out of BLE range, the app has no reliable wake/data path and cannot safely execute algorithm steps.
Legacy BUMarjorie timing behavior to mirror
MasterControllercomputes next step wall-clock as:timeOfNextStep = firstStepTime + algorithmTime * 300s- Work is driven by
doWorkand split into: - Device reads (
CGM,insulin pump,glucagon pump) - Algorithm execution scheduling
- A single cycle trigger uses an early window:
- It schedules once when
timeUntilStep <= 300sand last schedule is older than273s(300 - 27). - Practical effect: one device/algorithm scheduling pass per 5-minute cycle, approximately 27 seconds before nominal boundary.
- Step skipping is wall-clock based:
- If late beyond grace, inferred step is
floor((now - firstStepTime) / 300s) + 1. algorithmTimeis advanced to inferred step before next run.AlgorithmControlleronly increments step after a successful run:- Input uses current
algorithmTimeasinputData.time. - After success, state saves and
algorithmTime = algorithmTime + 1. - Step 0 is blocked until either CGM or BG exists.
- BLE/device-driven wake behavior exists through device notifications:
DeviceController.deviceStateChangedtriggersscheduleWorkNow.- This supports "run when awakened by BLE" even without always-on silent audio.
Current BionicLoop behavior (implemented)
- Runtime path:
LoopRuntimeEnginein app layer receives G7 state updates and callsLoopRuntimeCoordinator.doWork(cause: .cgmUpdate).- Runtime engine responsibilities are now split into dedicated app-layer components:
LoopSessionStore(armed/runtime persistence boundary)LoopWorkScheduler(CGM wake dedupe/arming boundary)LoopAlertMediator(signal-loss tracking/reporting boundary)LoopTelemetryWriter(telemetry write boundary)LoopRuntimeWorkExecutor(doWork execution snapshot boundary)
Start Algoarms runtime and waits for the next new G7 reading timestamp.- Step 0 executes on that next new reading.
- Timing/cadence:
LoopRuntimeCoordinatorcomputes due step with early window:expectedStep = floor((now + 27s - firstSuccessfulStepAt) / 300s)
firstSuccessfulStepAt,lastExecutedStep, and related runtime fields are persisted inUserDefaultsLoopRuntimeStateStore.- Duplicate wake attempts within an already-executed step index are skipped with
stepNotDue. - Gate behavior:
- Step 0 requires fresh usable CGM (
missingFreshGlucoseon failure). - Step > 0 can execute with unavailable CGM input (
CGM_VALUE_NONE,-1) when CGM is stale/missing/out of range. - Pump status refresh failure executes with unavailable pump input (
deliveryState = unknown) and blocks command application. - A single in-flight guard prevents concurrent execution overlap.
- Home loop badge age states (
Active/Aging/Stale) are based on cadence phase (firstSuccessfulStepAt + nextStep * 300s) rather thanlastSuccessfulRunAt, so borrowed meal steps do not falsely age the loop before the next due boundary.- Current thresholds:
Activeto due+2m,Agingto due+15m, thenStale.
- Current thresholds:
- Meal announce behavior:
LoopRuntimeCoordinator.announceMeal(...)supports early execution of future step slots.- Borrow is only allowed when:
- current slot is not due yet (
expectedStep < nextStep) - pump availability is known (
deliveryState != unknown) - pump is not currently delivering
- next scheduled slot is within
2 * 300sfrom now
- current slot is not due yet (
- Availability checks treat missing cached pump status (
nil) as a cache-miss, not immediate signal loss; signal-loss gating is driven by policy state or explicit unknown status. - Once a current known pump status is recovered after reconnect, meal availability should reopen immediately from current state and must not remain blocked solely by stale historical signal-loss bookkeeping from the most recent failed step.
- Meal submit remains conservative: the announce attempt still requires a fresh known pump status at submit time, and a submit-time refresh failure should continue to block the request instead of relying only on previously cached status.
- On successful borrow, execution runs immediately as
nextStepand consumes that slot. - If request occurs after slot is due/missed (
expectedStep >= nextStep), execution uses current due step (expectedStep) with meal input. - Borrow remains rejected with
cannotBorrowfor pump delivering/unknown, no anchor, or out-of-window pre-due requests. tooLatewait messaging is bounded to the immediate due-step boundary (no forced extra +5 minute delay).- This due/missed meal behavior is provisional and requires explicit team review before release lock.
- Planned hardening work:
- implemented baseline: persist pending meal-request state across relaunch using the concrete target step accepted by the coordinator so duplicate entry is blocked while that request remains unresolved
- implemented baseline: defer Home success UI/telemetry until runtime/coordinator result is known and show explicit blocked/rejected messaging when outcome is not executed
- implemented baseline: add explicit uncertain-command-outcome handling so comms interruptions do not invite blind re-announce; uncertain requests remain blocked until reconciliation against pump-delivery evidence or session reset/disarm
- implemented baseline: preserve uncertain-vs-blocked semantics in loop-command telemetry via explicit
command_outcome - implemented baseline: block
slot_conflictwhen CGM/reconnect claims the observed meal slot before coordinator acceptance, rather than silently reassigning the meal to a new borrowed step - implemented baseline: persist meal
flow_idwith pending state and emit correlatedaccepted+resolvedlifecycle transitions when the request is accepted, reconciled, or cleared by session reset
- Step synchronization:
- Runtime computes
expectedStep. RealBUDosingAlgorithmis synchronized toexpectedStepbefore recommendation generation.- Bridge call still increments step by one after successful
algorithmRunStep. - Session control:
- Manual test bolus UI is removed.
Reset Algoperforms full fresh-session reset:- clears persisted algorithm state (
UserDefaultsAlgoStateStore) - clears persisted runtime cadence state (
UserDefaultsLoopRuntimeStateStore) - clears pump adapter request/delivery carry-over metadata
- clears persisted recent-step timeline used by UI
- clears persisted algorithm state (
Pump-unavailable policy alignment (BUMarjorie parity review)
- Legacy BUMarjorie behavior (documented in
Docs/Analysis/BUMarjorie.md): - Step executes even when pump is unavailable.
- Algorithm input marks pump unavailable and uses invalid request/delivery fields.
- Delivery is skipped if unavailable, but step/time still advances.
- Current BionicLoop behavior:
doWorkexecutes with unavailable pump input when pump status is unavailable/unknown and blocks command application.- Decision/work item:
- Policy selected and implemented:
POLICY-B(run step with unavailable pump input and gate delivery path only). - Implementation tasks after policy decision:
- Keep
step executedseparate fromdelivery appliedin persisted runtime telemetry. - Ensure next-step input carries last request/delivery fields only when they are valid.
- Keep reconnect/recovery path deterministic and visible in logs/UI.
- Required tests:
- Pump unavailable at step boundary.
- Reconnect before next step with valid status read.
- Delivery command failure after successful status read.
- Step counter behavior under each policy.
- CGM sanitization safety:
<39and>401map toCGM_VALUE_NONE(-1) before algorithm input.
Remaining implementation plan (no silent-audio dependency)
- Keep
doWorkCGM-driven for study closed-loop operation unless requirements change. - Add explicit fallback mode state machine (degraded/offline) and user status messaging.
- Add fingerstick BG fallback path for step 0 when protocol behavior is enabled.
- Evaluate additional wake paths (BGTask, reconnect-triggered run attempts) only after policy review.
BG check doWork policy (implemented baseline + pending policy details)
- Goal:
- Allow manual BG entry to drive algorithm execution when CGM-triggered execution is not viable.
- Runtime trigger model:
- Introduce dedicated wake cause
bgCheck. - Manual BG-triggered execution is loop-armed only;
Algorithm Offstate blocksbgCheckdispatch. bgCheckexecutes current due step when still pending; otherwise carries the submitted BG forward to the immediate next step only.bgChecknever borrows a future step and never advances cadence anchor by pre-running future slots.- Input mapping model:
- Manual BG maps to algorithm BG input (
BGval). - Manual BG accepted range is
20...600 mg/dL; values outside range are rejected before runtime dispatch. - CGM input mapping remains independent (
CGMmay be-1when unavailable/unusable). - Runtime records
manualBGsource tag in telemetry. - Deterministic behavior:
- Maintain one pending BG candidate at a time.
- If due step already executed at submit time, candidate is assigned to immediate next step.
- If candidate is not consumed at that immediate next step, discard as too old.
- If a newer BG is submitted while a candidate is pending, replace candidate with the newer value.
- Manual BG freshness-window rejection and user-visible stale messaging remain pending policy/implementation detail.
- Pump-unavailable policy remains unchanged: step may execute, command application remains blocked.
- Edge-case execution:
- No CGM wake events:
bgCheckcan run due step and prevent cadence stall. - CGM wake exists but CGM unusable:
bgCheckcan run due step withBGval+ CGM unavailable. - Step 0 with no fresh usable CGM:
- current policy is blocked; manual BG submit is rejected before first successful anchored step.
- optional BG-rescue remains provisional and requires clinical/team sign-off before behavior lock.
- Cross-document quality references:
- SRS:
SRS-BG-001..012(Docs/Quality/SoftwareRequirementsSpecification.md) - SDD:
SDD-BG-001,SDD-POL-010,SDD-POL-011,SDD-POL-012(Docs/Quality/SoftwareDesignDescription.md) - SVVP:
TV-BG-001..012(Docs/Quality/SoftwareVerificationAndValidationPlan.md)
Step increment and catch-up policy (implemented)
- Source of truth is persisted algorithm state (
timeStep) plus runtime anchor metadata. expectedStepis derived from wall-clock anchor and early window (+27slead).- If runtime is late, coordinator catches up by synchronizing algorithm step before running.
- If
expectedStep <= lastExecutedStep, algorithm execution is skipped for idempotency. - On successful algorithm call, bridge increments algorithm step by one.
Testable requirements for timing behavior
TIMING-01: Step 0 gate- Given no fresh CGM, step 0 is not executed and step counter does not advance.
TIMING-01b: Step 0 manual BG guard- Given no first successful anchored step, manual BG submission is rejected and no pending BG candidate is created.
TIMING-01a: Step > 0 degraded CGM execution- Given stale/missing/out-of-range CGM and step index > 0, runtime executes using
CGM_VALUE_NONE(-1) input. TIMING-02: Single-step increment- One successful run advances step exactly by 1.
TIMING-03: Wall-clock catch-up- If app wakes after missing >= 1 cycle, step aligns to inferred wall-clock step before next run.
TIMING-04: No duplicate execution in one cycle- Multiple wake events inside same cycle do not cause extra step increments.
TIMING-05: CGM-driven trigger- A new G7 reading timestamp triggers
doWorkattempt within bounded latency. TIMING-06: Restart continuity- After app quit/relaunch, scheduler restores prior step timeline and does not reset to step 0.
TIMING-07: Freshness gate (step 0)- If latest CGM exceeds configured max age before first successful step, run is skipped and reason is logged.
TIMING-08: Delivery feedback continuity- Next-step input contains prior request time/units requested/units delivered when available.
TIMING-09: Observability- Each attempt logs: cause, expected step, persisted step, run/skip reason, and post-run step.
TIMING-10: Pump reconnect non-trigger- Current implemented baseline: pump reconnect events alone do not trigger algorithm execution.
TIMING-11: Foreground non-trigger- App foreground/active transition alone does not trigger algorithm execution.
TIMING-12: CGM-step coupling- With CGM values at ~5-minute cadence, algorithm executes at most once per 5-minute step index.
TIMING-13: Reset fresh start- After
Reset Algo, next run starts at step 0 with no carried-over request/delivery metadata. TIMING-14: Out-of-range hard gate- Step 0 still requires usable CGM; for step > 0, unavailable CGM and unavailable pump execute in degraded mode with no command application.
TIMING-15: Fallback transition (planned)- After configured outage threshold (for example
>= 15 minuteswithout valid CGM + successful run), loop transitions to offline/degraded mode and emits user-visible status. TIMING-16: Fallback recovery (planned)- Once connectivity/data gates recover, loop exits offline/degraded mode and resumes normal step scheduling without resetting step timeline.
TIMING-17: Meal borrow window and consumption- Two immediate meal borrows are allowed when within 10 minutes of future slots, third is rejected.
- A borrowed step does not execute again at its original wall-clock slot.
TIMING-18: Meal borrow rejection paths- Borrow is rejected for pre-due out-of-window requests, pump delivering, pump unknown, or missing anchor.
TIMING-19: Meal announce on due/missed slot (provisional)- If meal announce is requested after a slot is due/missed, runtime executes meal on current due step (
expectedStep) rather than rejecting for late borrow. - Requires team/clinical sign-off before release behavior lock.
TIMING-20: Delivery-state auto-clear visibility- While pump reports
delivering, status is polled and Home/meal gating clear to non-delivering state without user entering pump settings. TIMING-21: BG check due-step execution only- BG-triggered doWork executes only current due step (
expectedStep) and never borrows a future slot. TIMING-22: BG check rescue path for CGM wake failure- If CGM wake does not occur, BG entry can still trigger execution (subject to other gates).
TIMING-23: BG check rescue path for invalid CGM data- If CGM wake occurs but CGM input is unusable, BG entry can still trigger execution with BG input mapping.
TIMING-24: BG late-submit carry-forward behavior- If BG is submitted after current due step already executed, BG is applied to immediate next step only.
TIMING-25: BG pending candidate replacement behavior- If multiple BG submissions occur before pending BG is consumed, newest submission replaces prior pending value.
TIMING-26: BG pending candidate expiry behavior- Pending BG candidate expires if not consumed on the immediate next step after it becomes eligible.
TIMING-27: Reconnect fallback gating (planned)- After first successful anchored step exists, reconnect-triggered execution is permitted only when accepted CGM receipt age exceeds the approved freshness limit (current proposal:
> 5 minutes) andexpectedStep > lastExecutedStep. TIMING-28: Reconnect fallback cadence safety (planned)- Reconnect fallback never executes step
0, never re-anchors cadence, and never replays multiple missed slots; each reconnect-triggered execution may service only the current due step. TIMING-29: Reconnect fallback suppression on resumed CGM (planned)- Once fresh accepted CGM receipts resume, reconnect-triggered fallback is suppressed and CGM remains the primary trigger for subsequent slots.
Deterministic Simulation Harness Plan (Medium now, High later)
Medium-fidelity target (implementation phase)
- Scope:
- deterministic runtime decision testing without real BLE transport
- full exercise of cadence, gating, degraded-mode behavior, and alert lifecycle
- Planned implementation surfaces:
BionicLoopCore/Sources/BionicLoopCore/Ports/- keep production protocols as-is; add test doubles conforming to
CGMServiceandPumpService
- keep production protocols as-is; add test doubles conforming to
BionicLoopCoretest targets- add scenario runner + virtual clock to drive coordinator/runtime with timestamped inputs
BionicLoop/Runtime/- optional launch-argument hook for deterministic preview scenarios in app UI/system tests
BionicLoopTests/- scenario fixtures and expected-output snapshots
- Scenario event model:
- CGM value/reliability/timestamp
- pump status transition (
idle,delivering,unknown, reconnect) - pump command success/failure and reconciliation updates
- alert issue/retract transitions
- Required scenario outputs/assertions:
- expected vs executed step index
- skip reason and gating reason
- algorithm input/output snapshot
- command-application decision/result
- alert center active/recent state
High-fidelity target (eventual, not current critical path)
- Scope:
- BLE/session-level emulation for Omni/G7 behavior not captured by medium mocks
- Candidate surfaces:
- reconnect jitter/timing edges
- ACK latency/failure patterns
- platform-specific session restoration quirks
- Goal:
- confidence amplification for hardware-specific behavior after medium-fidelity harness is stable
Safety/testing impact
- Improves repeatability for rare hazard paths that are difficult to reproduce on-demand with hardware alone.
- Reduces risk of regressions in command-block, degraded execution, and alert escalation logic.
- Produces traceable, deterministic evidence artifacts for RA/SRS/TV linkage before real-device validation.
- Complements (does not replace) hardware-in-the-loop testing for transport/physical-delivery behavior.
Identity and Onboarding (Cognito) - In Progress
Implemented baseline (current)
- Added secure auth-session/token boundary in app layer:
BionicLoop/App/AuthSessionNetworking.swiftAppAuthSessionManager(Keychain-backed token persistence, expiry check, refresh)AuthenticatedAPIClient(bearer injection + one-time refresh retry on401)- Session lifecycle behavior now includes:
- launch-time silent session-restore/refresh when persisted auth state is authenticated; explicit login only when restore fails
- sign-out path clearing secure token session in addition to local auth flag
- active-loop continuity fallback: login screen can expose
Go to Homewhile loop state is active, and Home shows persistent auth-recovery alert with directLog Inaction - Added targeted unit coverage in
BionicLoopTests/BionicLoopInfrastructureTests.swiftfor: - sign-in response token parsing (
AccessToken/IdToken/RefreshToken/ExpiresIn) - refresh-token exchange behavior
- session-manager refresh/persist semantics
- authenticated request retry after unauthorized response
- Added email/password recovery flow in unauthenticated routing and Cognito service layer:
ForgotPasswordreset-code requestConfirmForgotPasswordcode-confirmed password reset- UI path for request/reset/resend with explicit user feedback banners
- targeted unit coverage for request/confirm happy paths
- auth form metadata aligned for iOS Password AutoFill/Strong Password support (
username,password,newPasswordcontent types) across login/create/reset flows - Runtime lifecycle safety gate updated:
- unauthenticated auth/session state no longer stops or resets loop runtime state
- auth is treated as cloud/protected-operation gating only, preserving local therapy continuity
Scope (pending team decision)
- Add user onboarding/sign-in with:
Sign in with AppleGoogleEmail(password flow + reset currently implemented; policy still pending on long-term mode)- Gate cloud API access (telemetry and dashboard endpoints) behind authenticated identity context.
Proposed implementation surfaces
- App:
BionicLoop/Features/Onboarding/for sign-in flow screens and session state presentation.BionicLoop/Runtime/for auth/session coordinator and protected-request policy.- Infra:
- AWS Cognito
User Pool(+ optionalIdentity Poolif temporary AWS credentials are needed). - API authorization integration via JWT validation and role/scope checks.
Open design questions (must be resolved with team)
- Whether current investigational phase requires per-user sign-in or can remain unauthenticated for limited use.
- Preferred email auth method (magic link vs password) and operational support burden.
- Required role model (clinical, engineering, admin) and least-privilege mapping.
- Account recovery/deprovisioning workflows and emergency-access policy.
- Exact privacy/consent copy and legal text in onboarding.
Safety and verification notes
- Authentication must never block safety-critical local loop behavior in a way that causes unsafe operation.
- Cloud-side authorization failure handling must fail closed for protected data actions while preserving safe local behavior.
- Add dedicated tests for:
- first-run onboarding permutations (Apple/Google/Email),
- token expiration/refresh/revocation,
- unauthorized access attempts and expected denial paths.
AWS Telemetry and Observability - Planned
Execution tracking: Docs/Planning/ExecutionPlan.md -> Workstream J.
Detailed contract/taxonomy: Docs/Planning/TelemetryCloudIntegrationPlan.md.
Scope
- Send app/runtime/device/alert/UI-critical telemetry to
BionicScoutPOST /v1/telemetry. - Capture enough correlated context to reconstruct subject incidents and stuck-user flows.
- Keep telemetry transport fully non-blocking to local loop safety operation.
App-side implementation touchpoints (planned)
BionicLoop/Runtime/- Add app telemetry emitter boundary with typed DTOs and envelope builder.
- Add persistent outbox and flush worker (retry/backoff/idempotency metadata).
- Add telemetry transport health events (
flush.started/succeeded/failed, drop summaries). - Add client logging upload sink with severity filtering and batching (
app.log.batch). BionicLoopCore/Sources/BionicLoopCore/Algorithms/- Add deterministic Algo2015 native-log capture adapter integration point (session-aware).
BionicLoopCore/Sources/Algo2015Bridge/(optional phase-2 path)- Evaluate callback-based native log sink to replace/augment file-tail capture.
BionicLoop/Integrations/CGM/- Emit CGM reading processed/masked/state/connection events.
BionicLoop/Integrations/Pump/- Emit pump status/command result/pod lifecycle events.
BionicLoop/Features/Home/,BionicLoop/Features/CGM/,BionicLoop/Features/Pump/- Emit critical UI interaction events (
tap,submit,cancel,blocked,state_viewed). - Propagate
flow_idfor multi-step flows (meal announce, BG entry, setup). BionicLoop/Shared/- Shared event-id/session-id helpers and redaction-safe metadata population.
Client log-level upload controls (planned)
- Level model:
debug,info,warning,error. - Default cloud upload threshold:
error. - Threshold behavior: upload
selected level and above. - Planned settings control:
Cloud Log Upload Levelselector in app settings.- persisted locally and included in telemetry context.
- Planned precedence logic:
- remote override (if active and not expired)
- local settings choice
- default
error - Remote override target behavior (future):
- backend-pushed/fetched subject-scoped override with TTL
- automatic expiry/revert without user action
- telemetry audit event when override applied/reverted
Algo2015 native stream capture notes (planned)
- Preferred near-term capture source:
- tail
BP_LOG_<timestamp>.txtemitted byAlgo2015/Algorithm_2015_10_13.cppRecordConsole(). - Do not rely on device console scraping (
cout) for cloud routing. - Keep algorithm matrix/data dump files (
BP_<timestamp>.txt, read-matrix helpers) out of routine cloud pipeline. - Map native lines to shared cloud log DTO with:
subsystem = algo2015.native- parsed prefix/step metadata where available
- raw line retained for forensic replay.
Cloud-side integration assumptions (BionicScout)
- Current contract accepts envelope with required fields:
event_type,schema_version,subject_id,created_at,payload- Current route is JWT scope-protected (
bionicscout.dev.api/telemetry.ingest) and returns202. - Planned next cloud increments:
- per-event schema validation by
event_type + schema_version - idempotent durable persistence keyed by
(subject_id, event_id) - query support for incident timeline reconstruction
Reliability model (planned)
- Persistent outbox states:
pending,inflight,acked,failed_permanent- Ordered local sequencing for deterministic replay.
- Exponential backoff + jitter retries for transient failures.
- Non-retry for permanent schema/auth failures with explicit drop-summary telemetry.
- Priority flush path for safety-critical events (alerts, blocked loop commands, severe device states).
Open design questions (team review required)
- Crash capture stack choice (Sentry/Crashlytics vs AWS-only path).
- First-release dashboard scope for clinician vs engineering audiences.
- Retention windows by event class and timeline depth for incident review.
- Initial server-side schema evolution policy (strict reject vs staged compatibility).
- Remote log override governance:
- roles allowed to issue override
- max override duration
- production constraints for
debuguploads
Safety and verification notes
- Telemetry failures must never block loop execution, alerting, or safe state transitions.
- Cloud auth failures must fail closed for data access while preserving safe local behavior.
- Verification must include deterministic incident-story replay proving:
- device observations,
- algorithm decisions,
- command apply/block outcomes,
- alert lifecycle transitions,
- critical user actions.
- Formal evidence path for this workstream is
STR-CLOUD-*(quality-controlled runs only).
OmniBLE Integration
BionicLoopCore/Sources/BionicLoopCore/Ports/- Keep
PumpServiceinterface stable forOmniBLEPumpManageradapter use. BionicLoop/Integrations/Pump/- Maintain
PumpServiceAdapterand reconciliation of pump history usingdosesForStorage()after reconnect. BionicLoop/Features/Pump/- Wire Pump UI entry points, pairing flow, and status display.
G7 Integration
BionicLoopCore/Sources/BionicLoopCore/Ports/- Keep
CGMServiceinterface stable forG7SensorKitadapter use. BionicLoop/Integrations/CGM/- Maintain CGM manager adoption/restore flow and sensor lifecycle edge handling.
BionicLoop/Features/CGM/- Continue onboarding/settings UI integration and edge‑case handling.
Offline/Fallback Behavior
BionicLoopCore/Sources/BionicLoopCore/Runtime/- Add offline mode state machine (trigger at >= 15 min without valid CGM + algorithm).
- Define and enact offline basal via DASH.
BionicLoop/Features/Home/- Show offline mode banner and recovery messaging.
User Alerts
BionicLoop/Runtime/- Add alert normalization service that consumes runtime/policy events and produces canonical alert objects.
- Runtime-derived algorithm stepping interruption detection is now implemented for armed sessions when no successful algorithm step completes for
15 minutes; this remains distinct from G7-provided unreliable/failed lifecycle alerts and from Home-onlyAging/Stalestatus. - Current implementation measures interruption from the most recent successful step (or session start / first-step wait state if none exists yet), schedules/resets a local deadline from that baseline, recomputes interruption state on app foreground, and clears interruption alerting when stepping resumes or loop is disarmed/reset.
- Current normalized alert is
ALERT-ALGORITHM-STEPPING-INTERRUPTED, with blocker detail (No CGM,No Pod, signal loss, other runtime gates) surfaced without replacing stronger source-native alerts. BionicLoop/Integrations/Pump/- Map Omni alert/state events into normalized alert types with severity and dedupe keys.
BionicLoop/Integrations/CGM/- Map G7 alert/state events (sensor reliability, disconnect duration, critical glucose conditions) into normalized alert types.
BionicLoop/Features/Home/and settings/modals- Add consistent alert presentation surfaces and acknowledgment/clear interactions.
- Cross-cutting
- Add alert precedence/debounce policy and trace to
SRS-ALERT-*andTV-ALERT-*.
Persistence + State Restore
BionicLoopCore/Sources/BionicLoopCore/Persistence/- Persist loop state, last successful run, and last known device status.
BionicLoop/Integrations/- Restore device sessions on app launch and avoid unnecessary re‑pairing.
Reinstall Continuity (Planned)
Goal: allow safe continuity across app delete/reinstall without silently corrupting Pod session state or algorithm cadence state.
Continuity snapshot architecture
BionicLoopCore/Sources/BionicLoopCore/Persistence/- Add a versioned continuity payload model containing:
- algorithm continuity (
stateData,timeStep, cadence anchor metadata) - pump continuity (restore-critical manager/session fields)
- provenance (
subject_id,account_id,created_at, schema version).
- algorithm continuity (
- Add integrity metadata and verification hooks so stale/tampered snapshots are rejected.
BionicLoop/App/- Add continuity bootstrap coordinator at launch to decide:
- restore from same-device snapshot
- optionally fetch cloud escrow snapshot
- or require clean setup/fresh algorithm start.
Tiered restore model (proposed)
- Tier 1 (same-device reinstall):
- Store encrypted continuity payload in device-only Keychain so app-delete/reinstall on same phone can recover.
- Tier 2 (account recovery):
- Store encrypted continuity snapshot in cloud (account-scoped, device-bound envelope) for authenticated recovery.
- Auth/session checks must gate cloud restore.
Pod continuity path
BionicLoop/Integrations/Pump/- Restore manager/session fields from continuity snapshot before default setup flow.
- Immediately run live session/status verification; if invalid, force clean Pod setup.
- Never adopt snapshot across subject/account mismatch.
Algorithm continuity path
BionicLoop/Runtime/+BionicLoopCore/Sources/BionicLoopCore/Runtime/- Restore algorithm state/cadence only when snapshot integrity and compatibility checks pass.
- Resume from restored expected cadence anchor, not forced step 0.
- If restore preconditions fail, perform explicit fresh-session reset with user-visible reason and telemetry event.
Safety and verification notes
- Add deterministic reinstall scenarios in simulation harness:
- successful continuity recovery
- tampered/stale snapshot rejection
- mismatch fallback to clean setup/fresh session.
- Extend quality trace docs with reinstall-specific controls/tests before implementation closure.
Home Charts (Scout Reuse Plan)
Legacy chart code review summary
- Source reviewed:
/Users/jcostik/Scout/evan2020/Charts/EGVChart.swift/Users/jcostik/Scout/evan2020/Charts/InsulinChart.swift- Keep:
- Lightweight SwiftUI rendering (no heavy chart framework dependency).
- Drag-to-scrub interaction pattern.
- Time-axis labels and glucose visual zones from
EGVChart. - Refactor:
- Remove dependency on Scout
ChartData/Egvmodel. - Remove legacy interpolation assumptions tied to remote API payload shape.
- Convert insulin bars from equal-spacing to time-based x positioning so insulin and CGM align on the same timeline.
Current implementation status
- Implemented in
HomeView: - Shared-range CGM + insulin overlay chart with aligned x-axis placement by timestamp.
- Time window selector (
4h,8h,12h,24h). - Scrub pills above chart (
CGM,Dose) driven by chart scrub position. Dosescrub output includes0.0Ucases and time output even when no nearby insulin step exists.- Recent step timeline moved into
Bionic Loop Settings -> Recent Dose Steps. - Styling/interaction state now implemented:
- Dashed rounded plot border with matching corner radius.
- Left/right y-axis labels anchored to chart container edges.
- Continuous scrub line tracking across chart area.
Single source of truth for Home chart/list data
- Implemented:
LoopTelemetryStorein app layer as Home chart/list projection source.- Persist rolling CGM and step telemetry windows in
UserDefaultsJSON. - Runtime now writes executed-step telemetry from
DoWorkResultand reconciles with pump status updates. - G7 view model ingests both current reading and persisted history into telemetry store.
- Canonical records:
CGMPoint: timestamp, glucose mg/dL, trend (optional), source (live,backfill).DosePoint: algorithm step, requested units, delivered units, request timestamp, delivered timestamp, status.StepContext: step, CGM used by algorithm (value + timestamp), loop cause.- Home UI (charts + step list) reads from this store.
- Runtime/pump/CGM adapters write to this store; Home must not compute independent state copies.
Ingestion paths
- CGM stream:
- Capture readings in
AppCGMManagerDelegate.cgmManager(_:hasNew:)fromCGMReadingResult. - Persist every valid sample used for display, not just the latest sample.
- Algorithm/runtime stream:
- On executed step, write
StepContext(step index, CGM used, execution timestamp, wake cause). - Pump stream:
- Continue reconciling delivery via
PumpStatusObserver+PumpServiceAdapter. - Upsert
DosePointby step ID so requested vs delivered can evolve as pod finalizes bolus.
UI composition plan
- Replace current "Recent Dose Steps" ad-hoc rendering with projection from telemetry store.
- Add two Home chart components backed by the same projection:
EGVChartView(ported/refactored from ScoutEGVChart).InsulinDoseChartView(ported/refactored from ScoutInsulinChartwith time-based x-axis).- Keep text list under charts for quick debugging:
- Step, requested/delivered units, step timestamp, CGM value/timestamp used.
- Scrubbing behavior:
- CGM chart scrub shows glucose + absolute timestamp.
- Insulin chart scrub shows delivered/requested units + step + absolute timestamp.
Acceptance requirements (testable)
CHART-01: Single-source projection- Home chart data and Home step list are generated from the same telemetry store snapshot.
CHART-02: CGM history persistence- After app relaunch, Home chart still renders recent CGM points without requiring a new read first.
CHART-03: Dose reconciliation update- When pod delivery status transitions (in-progress -> finalized), existing step point is updated in place (no duplicate step rows).
CHART-04: Step reset behaviorReset Algoclears telemetry tied to prior session; next session begins with step 0 and fresh chart/list history.CHART-05: Time-axis alignment- CGM and insulin charts place points/bars by timestamp, not by array index.
CHART-06: Zero-dose visibility- Step list/chart still include executed steps with
0.0Udelivery so skipped/no-dose behavior is visible.
Rollout order
- Done: Add telemetry store models and persistence schema.
- Done: Move Home chart/list reads to telemetry store snapshot.
- Done: Wire ingestion from CGM + loop runtime + pump reconciliation.
- Done: Add store unit tests (
LoopTelemetryStoreTests) and coordinator telemetry tests. - Pending: Add UI smoke tests for range switching and scrub behavior with sparse CGM/dose data.
Testing
BionicLoopTests/- Add unit tests for loop scheduling, offline fallback, and reconciliation logic.
BionicLoopUITests/- Add onboarding flow smoke tests for G7 and DASH.
Docs
Docs/Architecture/Architecture.md,Docs/Requirements/Requirements.md, andDocs/Quality/RiskAnalysis.mdshould be updated alongside any new scheduling or device-integration behavior.