8000 Release OpenGlucose 0.3.0 (sensor lane: Libre 2 capture, GS1 evidence, live GS1 driver) by shroominic · Pull Request #128 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content
8000
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
8000
Diff view
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
/packages/cgm_ble/ @shroominic
/packages/cgm_ble_flutter/ @shroominic
/packages/cgm_aidex/ @shroominic
/packages/cgm_libre2/ @shroominic
/packages/cgm_yuwell_anytime/ @shroominic
/.github/ @shroominic
/docs/ @shroominic
/SECURITY.md @shroominic
Expand Down
2 changes: 2 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ body:
- cgm_ble
- cgm_ble_flutter
- cgm_aidex
- cgm_libre2
- cgm_yuwell_anytime
- Build, tooling, or documentation
- Unsure
validations:
Expand Down
22 changes: 22 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ updates:
labels:
- dependencies

- package-ecosystem: pub
directory: /packages/cgm_libre2
schedule:
interval: weekly
day: monday
time: "06:20"
timezone: Etc/UTC
open-pull-requests-limit: 3
labels:
- dependencies

- package-ecosystem: pub
directory: /packages/cgm_yuwell_anytime
schedule:
interval: weekly
day: monday
time: "06:25"
timezone: Etc/UTC
open-pull-requests-limit: 3
labels:
- dependencies

- package-ecosystem: gradle
directory: /openhealth/android
schedule:
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ app.*.map.json
*.log
*.swp

# Private physical-device captures (the harness also rejects Git-local output)
openglucose-protocol-captures/
.openglucose-passive-capture
bugreport-*.zip
btsnoop_hci.log
*.pcap
*.pcapng

# Apple credentials / certs (defense in depth — these should never be in repo)
*.p8
*.p12
Expand Down
56 changes: 56 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,62 @@ expectations are defined in [docs/compatibility.md](docs/compatibility.md).

## [Unreleased]

### Added

- Add a `cgm_cbio` GS1 scaffold, pure `FF30` discovery mapping, synthetic
contract/frame tests, offline plaintext inspection, and SiSensing UUID/protocol
evidence. The package has no
transport, app registration, authentication, or glucose support. Record a
separately authorized Mac bench probe in the evidence document.
- Add a private Android Gen1 Libre 2 receiver path with an explicitly initiated
NFC streaming exchange, encrypted receiver state, durable login counters,
exact-target Bluetooth connection, and CRC-validated packet diagnostics.
A separate GPL reference decoder can display provisional current estimates
in the explicit private bench build. Neither path is enabled in normal builds.
- Keep sensor setup inline on the home screen with automatic Bluetooth
discovery. A `Can't find your sensor?` action opens model-specific help;
AiDEX/LinX stays on Bluetooth, while an explicit FreeStyle Libre 2 selection
opens guided NFC in debug capture builds. Move sample data to Settings.
- Add an identifier-free Libre NFC scan event bridge with an animated
listening state, neutral tag detection, verified model identification, and
generic retry states. Raw tag identifiers and protocol bytes stay in the
bounded app-private capture.
- Add a pure-Dart, target-unverified Libre 2-family offline protocol core for
UUID/topology classification, observation-only sequence validation, and
strict opaque fragment assembly. It contains no live sensor I/O, keys,
authentication, activation, decryption, or glucose decoding.
- Add a pure-Dart, target-unverified Yuwell Anytime CT5 offline protocol core
with synthetic checksum, framing, transform, authentication-arithmetic, and
record-parser tests. It contains no BLE transport, live driver, activation,
proprietary binary, real identifier, or vendor-native glucose algorithm.
- Add an app-owned multi-driver registry that routes one physical BLE scan by
stable vendor driver ID while preserving existing AiDEX identifiers, storage
keys, histories, and presentation behavior.

### Changed

- Keep the current NFC calibration patch separate from the frozen Libre 2
Bluetooth receiver patch. Verify the receiver binding and all FRAM CRCs
before saving calibration for the private debug decoder.
- Reuse a confirmed Libre receiver after a fresh, same-sensor NFC read instead
of repeating streaming setup. Failed or stale verification cannot start a
new NFC enable attempt.
- Restore the saved Libre receiver before discovery, and wait for a fresh
exact-target advertisement before one explicit Bluetooth connection attempt.
Preserve the completed NFC setup and login counters across app restarts.
- Show closed, user-readable Libre connection failures instead of raw internal
codes, and distinguish radio search from successful data reception.
- Full-product protocol capture builds can keep the existing AiDEX and LinX
driver available while passively recording Libre-family observations. The
strict capture-only entry point remains observation-only.
- The one-shot target-unverified Libre patch-information probe now requires an
exact eight-byte ISO 15693 identity, derives its manufacturer byte from that
identity, accepts only an exact successful seven-byte response, and rejects
unknown model signatures before publishing a UI result.
- The Libre NFC animation now starts only after the native reader confirms NFC
and capture readiness. Reader loss publishes a closed retry state; reopening
or retrying waits for a fresh native state instead of inventing readiness.

## [0.1.4] - 2026-08-22

### Added
Expand Down
7 changes: 7 additions & 0 deletions NOTICE.md
10BC8
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
OpenGlucose source is licensed under the [MIT License](LICENSE). That license
applies only to material owned by OpenGlucose contributors.

Exception: `packages/cgm_libre2_glucose` is a separately GPL-3.0-only package
derived from pinned xdripswift source. Its full license and third-party notices
are in that directory. The optional `libre_glucose_debug_main.dart` executable
links it and is not an MIT-only combined program. Existing MIT files retain
their licenses. See [ADR 0004](docs/architecture/adr/0004-private-libre-glucose-decoder.md)
for the private-bench scope and distribution gates.

The application and packages depend on Flutter, Dart packages, CocoaPods,
Android libraries, and operating-system frameworks that retain their own
copyrights, licenses, and notice requirements. The MIT License does not
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
OpenGlucose is an open-source, local-first Flutter workspace for exploring
continuous glucose monitor (CGM) data. It includes a reference mobile app, a
sensor-agnostic domain API, reusable Bluetooth Low Energy (BLE) contracts, and
an AiDEX/LinX protocol driver.
an AiDEX/LinX protocol driver. The workspace also contains a target-unverified
offline Libre 2-family analysis core and a safety-gated Yuwell Anytime driver
for private Android hardware validation. The Yuwell path is not enabled in
normal builds. An explicit Android debug-capture build can display the exact
V1150 packed field as a clearly provisional engineering value; this is not a
production compatibility or clinical-accuracy claim.

> [!CAUTION]
> OpenGlucose is early-stage wellness and reference software. It is not a
Expand All @@ -20,6 +25,8 @@ an AiDEX/LinX protocol driver.
| [`packages/cgm_core/`](packages/cgm_core/) | Sensor-neutral readings, capabilities, snapshots, and session contracts | Dart |
| [`packages/cgm_ble/`](packages/cgm_ble/) | Platform-neutral BLE transport interfaces | Dart |
| [`packages/cgm_aidex/`](packages/cgm_aidex/) | AiDEX/LinX protocol, session, history, calibration, and diagnostics | Dart |
| [`packages/cgm_libre2/`](packages/cgm_libre2/) | Target-unverified offline Libre 2 classification and framing | Dart |
| [`packages/cgm_yuwell_anytime/`](packages/cgm_yuwell_anytime/) | Target-unverified Yuwell CT5 primitives and gated live session driver | Dart |
| [`packages/cgm_ble_flutter/`](packages/cgm_ble_flutter/) | `flutter_blue_plus` adapter for the BLE contracts | Flutter |

The package dependency direction and extension rules are documented in the
Expand Down
63 changes: 53 additions & 10 deletions docs/architecture/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,29 @@ openhealth (Flutter app, demo driver, platform lifecycle and presentation)
├── cgm_aidex ───────────────┐
│ ├── cgm_core │
│ └── cgm_ble │
└── cgm_ble_flutter ─────────┘
├── cgm_libre2 (explicit Gen1 debug receiver, target-unverified)
│ ├── cgm_core
│ └── cgm_ble
├── cgm_yuwell_anytime (debug-gated, target-unverified) ──┐
│ ├── cgm_core │
│ └── cgm_ble │
└── cgm_ble_flutter ─────────────────────────────────────┘
└── cgm_ble
│
└── flutter_blue_plus / native BLE APIs
```

Dependencies point toward contracts. `cgm_core` and `cgm_ble` are pure Dart
leaves. `cgm_aidex` composes those contracts without importing Flutter.
`cgm_ble_flutter` implements the transport boundary. The app is the composition
root and owns platform-specific user experience.
`cgm_libre2` uses the domain and BLE contracts for an explicit Gen1 receiver;
its classification and cryptographic primitives remain pure Dart.
`cgm_yuwell_anytime` depends on the domain and
BLE contracts for an explicit private-debug validation path. Its normal policy
publishes no glucose; the gated Android validation build can project only the
exact V1150 packed field as provisional engineering data. It is absent from
the normal driver registry. `cgm_ble_flutter`
implements the transport boundary. The app is the composition root and owns
platform-specific user experience.

## Responsibilities

Expand All @@ -46,6 +59,29 @@ explicit unsafe administration. It depends only on the domain and BLE
contracts. New sensor vendors should be separate drivers rather than conditionals
inside this package.

### `packages/cgm_libre2`

Owns Libre 2-family reference classification, sequence validation, Gen1
cryptographic primitives, and opaque fragment assembly. Its explicit Gen1
driver connects only to the target from a completed native NFC streaming
bootstrap. It reserves a durable login counter before one write-with-response
login and subscribes only after acknowledgement. The Android app owns the
encrypted receiver journal and the separately initiated NFC state changes.
The driver reports CRC-validated packet status; it does not interpret raw
measurements as glucose. Gen2 and Libre 3 live operation remain unimplemented.

### `packages/cgm_yuwell_anytime`

Owns target-unverified CT5 name/UUID classification, checksum and framing
helpers, reversible byte transforms, synthetic authentication arithmetic,
strict record parsers, and a safety-gated BLE session state machine. The live
path requires explicit activation authorization and Android Keystore-backed
credentials plus a durable write journal. It cannot unbind, reset, update,
calibrate, or load vendor code. Its default output policy publishes no glucose.
Only the explicit private Android debug-capture composition can opt in to a
fail-closed, provisional V1150 engineering projection until physical 5P
evidence passes the documented production-promotion gates.

### `packages/cgm_ble_flutter`

Translates the `cgm_ble` contracts to `flutter_blue_plus`. It owns adapter and
Expand All @@ -54,17 +90,24 @@ physical-device verification on every affected platform.

### `openhealth`

Composes drivers, stores presentation preferences/history, owns runtime
permissions, communicates connection and freshness state, and renders the UI.
On IO platforms it constructs the AiDEX driver and Flutter transport. On web
and in widget tests it uses a deterministic demo driver.
Composes drivers through one physical-scan registry, stores presentation
preferences/history, owns runtime permissions, communicates connection and
freshness state, and renders the UI. On IO platforms the registry currently
contains the verified AiDEX driver and Flutter transport. On web and in widget
tests the app uses a deterministic demo driver. Libre 2 is registered only
with `OG_PROTOCOL_CAPTURE_LIVE_LIBRE=true` in an Android debug trace build
using the Libre capture profile. Normal builds do not register it. Yuwell can
be registered only by the explicit Android debug trace
flags; normal debug and release builds do not include it in the driver registry.

## Runtime flow

1. The app asks a `CgmDriver` to scan.
2. The driver maps advertisements into sensor-neutral `DiscoveredSensor`
1. The app asks its `CgmDriver` registry to scan once for all registered
service UUIDs.
2. Pure vendor matchers map advertisements into sensor-neutral `DiscoveredSensor`
values with explicit capabilities.
3. The app connects and observes `CgmSessionSnapshot` values.
3. The registry stops scanning, routes connection by stable `driverId`, and the
app observes `CgmSessionSnapshot` values.
4. The protocol driver uses `BleTransport` for I/O and translates bytes into
normalized readings and status.
5. The app displays current and historical data together with connection,
Expand Down
65 changes: 65 additions & 0 deletions docs/architecture/adr/0004-private-libre-glucose-decoder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# ADR 0004: Isolate the optional Libre glucose decoder

- Status: Accepted for private Android bench work; distribution is not approved
- Date: 2026-09-05
- Owner: `@shroominic`
- Risk: R2 implementation; external distribution retains the R3 gate

## Context

The MIT LibreTools reference establishes Gen1 decryption and raw fields, not
factory-calibrated glucose. A bounded review found no verified permissive
converter. The maintainer explicitly approved the GPL route if necessary while
preferring MIT. The bench sensor is expired and applied to fruit; this work
cannot establish wearable glucose accuracy.

## Decision

Keep the existing MIT crypto/transport package free of GPL implementation
inputs. Put the GPL-derived factory conversion and its exact upstream notices,
license, pinned provenance, and synthetic tests in `cgm_libre2_glucose`.
The MIT live driver accepts an optional decoder contract. The app supplies the
GPL implementation only from a separate, guarded full-UI Android debug entry
point. Normal `lib/main.dart` does not import the GPL adapter.

This separation preserves source attribution and allows removal. It is **not**
a license exception: a distributed combined executable that includes the GPL
decoder must satisfy the applicable GPL terms for the combination, even when
the components live in separate packages. Existing MIT source notices remain.
See the [GNU license FAQ](https://www.gnu.org/licenses/gpl-faq.html.en#WhatDoesCompatMean)
and [license compatibility explanation](https://www.gnu.org/licenses/license-compatibility.en.html).

Calibration must come from exact-length, CRC-verified FRAM bound to the current
protected receiver UID and initial patch information. No guessed coefficients,
cross-sensor fixture, raw ADC conversion shortcut, or host artifact discovery
is permitted. Missing evidence suppresses glucose, not a healthy BLE stream.
Decoded packets need independent CRC, age, quality, temperature, and finite
math checks. Provisional bench output must not be presented as validated
clinical glucose or silently exported as such.

## Alternatives

- Continue MIT-only raw packet capture: preserves current license simplicity
but does not supply calibrated glucose.
- Guess conversion from raw values: rejected for data correctness.
- Treat DiaBLE's repository-level MIT label as covering all inherited factory
conversion: rejected; per-file lineage is required.
- Relicense all source without reviewing rights and dependencies: rejected.

## Consequences and release gates

Before sharing an APK, TestFlight build, or combined source distribution:

1. Review the exact compiled/resolved graph, all notices, reciprocal license
terms, and intended platform/store distribution conditions.
2. Supply corresponding source, modifications, build instructions, and any
required installation information under the applicable terms. Do not call
the combined decoder build MIT-only.
3. Complete independent decoder review and exact-model conformance evidence;
synthetic differential tests alone are insufficient.
4. Verify normal release entry-point exclusion or approve an explicitly
compliant decoder-enabled release. A runtime flag alone is not proof of
exclusion from an artifact.

No journal, NFC activation, streaming-enable result, or login counter is rolled
back when removing the decoder. It performs no network, storage, or device I/O.
1 change: 1 addition & 0 deletions docs/architecture/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ enforcement detail is already implemented.
| [0001](0001-package-boundaries.md) | Accepted | Separate domain, BLE transport, vendor protocol, platform adapter, and app composition |
| [0002](0002-local-first-health-data.md) | Accepted | Keep health data local by default and make movement explicit |
| [0003](0003-platform-release-model.md) | Accepted | Build source-bound mobile artifacts and release only through fail-closed platform lanes |
| [0004](0004-private-libre-glucose-decoder.md) | Accepted for private bench work | Separate the optional GPL decoder; preserve MIT provenance and gate combined distribution |

## Adding an ADR

Expand Down
Loading
0