mirror of
https://github.com/bckelley/cgm-remote-monitor.git
synced 2026-08-24 03:14:12 -05:00
Saved your changes before starting work
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 06715f81-f852-4156-8ab0-cf9e0aa3564d Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 79dc8047-74ae-47e7-85a6-8c7255d9603d
This commit is contained in:
+112
@@ -0,0 +1,112 @@
|
||||
Yep — that historical reality is exactly why the “blobs → events + materialized views” move is so valuable: profiles and profile-affecting overrides are user-authored configuration, but Nightscout has mostly seen them only as snapshotted, controller-shaped state (often via devicestatus, sometimes with partial duplication into treatments).
|
||||
|
||||
Here’s a concrete way to treat this cleanly without breaking legacy.
|
||||
|
||||
1) Treat “user-defined profiles” as first-class config objects
|
||||
|
||||
Instead of “the profile is whatever the controller most recently uploaded,” make the canonical model:
|
||||
|
||||
ProfileDefinition
|
||||
|
||||
A user-authored object (versioned, addressable)
|
||||
• profileId (stable)
|
||||
• title, timezone, units
|
||||
• schedules: basal[], isf[], cr[], target[]
|
||||
• insulinModel / DIA parameters (where applicable)
|
||||
• createdBy (human/controller), createdAt
|
||||
• hash (content hash for dedupe and audit)
|
||||
|
||||
ProfileSelection
|
||||
|
||||
A state event: “which profile is intended to be active”
|
||||
• selectedProfileId
|
||||
• effectiveAt
|
||||
• selectedBy (human / controller / remote delegate)
|
||||
|
||||
Key point: Nightscout can store definitions and selections separately, so you don’t need to re-upload the entire profile every time.
|
||||
|
||||
2) Treat overrides as composable “deltas” over a profile
|
||||
|
||||
Loop and AAPS both have “things that modify what’s in force” (temp targets, overrides/percent, exercise/sleep modes, autosens or sensitivity scaling).
|
||||
|
||||
Model them as:
|
||||
|
||||
OverrideDefinition
|
||||
|
||||
User-authored template (optional but powerful)
|
||||
• overrideType = exercise | sleep | custom | illness | …
|
||||
• defaultDuration
|
||||
• effects (structured):
|
||||
• targetMgdl or targetRange
|
||||
• basalMultiplier / maxBasalCeiling
|
||||
• sensitivityMultiplier
|
||||
• carbRatioMultiplier (if supported)
|
||||
• “automation aggressiveness” knobs (if controller exposes)
|
||||
|
||||
OverrideInstance
|
||||
|
||||
A concrete activation
|
||||
• overrideInstanceId
|
||||
• definitionId (optional)
|
||||
• start, duration, end
|
||||
• requestedBy + authority
|
||||
• status = active | ended | canceled | superseded
|
||||
• reason / annotation
|
||||
|
||||
3) PolicyComposition is the “materialized view” that replaces devicestatus-as-truth
|
||||
|
||||
Whenever something changes (new CGM, override start/end, profile switch, autosens change), the controller can emit:
|
||||
|
||||
PolicyComposition
|
||||
• references:
|
||||
• profileId + profileHash
|
||||
• activeOverrideInstanceIds[]
|
||||
• capabilitySnapshotId (optional)
|
||||
• effective parameters in force right now:
|
||||
• computed target range
|
||||
• computed ISF/CR/basal constraints
|
||||
• computedBy:
|
||||
• controller kind + version
|
||||
• validFrom / validTo (or cursor ordering)
|
||||
|
||||
This is the “Kubernetes-style status” that you can always reconstruct and audit.
|
||||
|
||||
4) How this relates to historical devicestatus uploads
|
||||
|
||||
Historically, devicestatus often contains one or more of:
|
||||
• a current profile name / profile content (sometimes)
|
||||
• “temp target” state (sometimes)
|
||||
• “override percentage” style hints (sometimes)
|
||||
• algorithm outputs (predictions/suggested/enacted)
|
||||
|
||||
In the new model:
|
||||
• devicestatus remains as a legacy derived view (materialized from events/compositions)
|
||||
• ingestion can work in two modes:
|
||||
1. Native events (preferred)
|
||||
2. Devicestatus parsing → event synthesis (bridge)
|
||||
|
||||
Bridge approach (pragmatic):
|
||||
• When a controller uploads a new devicestatus snapshot:
|
||||
• compute hash of “profile-like content” → if new, emit ProfileDefinition
|
||||
• compare “active override-like fields” → emit OverrideInstance start/end
|
||||
• emit PolicyComposition reflecting the effective parameters
|
||||
• Result: Nightscout becomes append-only + auditable even if controllers stay chatty for a while
|
||||
|
||||
5) Why this matters for interop (Loop ↔ AAPS)
|
||||
|
||||
Because both systems can be represented as:
|
||||
• same ProfileDefinition shape (with some optional fields)
|
||||
• same OverrideInstance semantics
|
||||
• same PolicyComposition output
|
||||
|
||||
Even if their internal UX differs, Nightscout can now answer:
|
||||
• “What did the user intend?” (definition + activation)
|
||||
• “What was in force?” (composition)
|
||||
• “What happened?” (delivery observation + reconciliation)
|
||||
|
||||
If you want, next step is I’ll draft the minimal JSON schema for:
|
||||
• ProfileDefinition
|
||||
• OverrideInstance
|
||||
• PolicyComposition
|
||||
|
||||
…and then we can annotate “what Loop/AAPS typically provide today” vs “optional nice-to-have fields.”
|
||||
Reference in New Issue
Block a user