8000 yuwell: real-hardware transport evidence + firmware-decode blocker (milestone, not live glucose) by shroominic · Pull Request #106 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
164b170
feat(yuwell): add macOS BLE debug path + real-hardware transport evid…
shroominic Sep 9, 2026
a474dcc
fix(ble): close the stopScan double-invocation race in FlutterBluePlu…
shroominic Sep 10, 2026
ddd3c9d
feat(yuwell): capture firmware+binding evidence and admit one read-on…
shroominic Sep 10, 2026
2ab04df
fix(yuwell): stop walking away from the macOS debug scan, bounded
shroominic Sep 10, 2026
196a8d9
fix(ci): unbreak PR #106's Unit Tests and Secret Scan checks
shroominic Sep 10, 2026
a45eb3f
docs(yuwell): promote OTA and history/query-code cipher findings from…
shroominic Sep 10, 2026
40d6db2
test(yuwell): cover the already-bound branch of the non-V1150 fail-cl…
shroominic Sep 11, 2026
b28de3d
test(yuwell): cover the resumed non-transmitter-computed fail-closed …
shroominic Sep 11, 2026
949fdef
docs(yuwell): source-ground advertisement verify() and record the app…
shroominic Sep 11, 2026
5b90839
docs(yuwell): pin down verifyHolder as a generic AD-structure walker
shroominic Sep 11, 2026
b32dd44
test(yuwell): cover the credentials-null non-setDate unresolved-inten…
shroominic Sep 11, 2026
786a8aa
docs(yuwell): source-ground ProtocolToolsHolder_CT5.verify() as the a…
shroominic Sep 11, 2026
afaaba6
docs(yuwell): resolve the jadx-empty continuity branch in algorithmGl…
shroominic Sep 11, 2026
9966161
docs(yuwell): source-ground CT5Init as a distinct view-layer session-…
shroominic Sep 11, 2026
4147213
test(yuwell): cover the missing-CT5-service topology fail-closed branch
shroominic Sep 11, 2026 8000
b31e628
docs(yuwell): sharpen CT5Init's prerequisite gate, finish-guide chain…
shroominic Sep 11, 2026
e7ae2a4
test(yuwell): cover the cross-driver sensor-identity fail-closed branch
shroominic Sep 11, 2026
b4a3788
docs(yuwell): resolve a second jadx-vs-smali gap, this time inside Pr…
shroominic Sep 11, 2026
af24af7
test(yuwell): cover the unconditional calibration-capability fail-clo…
shroominic Sep 11, 2026
5cb693d
docs(yuwell): trace Transmitter.sureClose and resolve the advertiseme…
shroominic Sep 11, 2026
38ce3e7
test(yuwell): cover the credential-store-read fail-closed branch
shroominic Sep 11, 2026
0d65e12
test(yuwell): cover four of the five remaining fail-closed branches
shroominic Sep 11, 2026
7991e5a
test(yuwell): cover scan() advertisement dedup, found via coverage no…
shroominic Sep 11, 2026
658725a
test(yuwell): extend coverage past driver.dart into frames.dart
shroominic Sep 11, 2026
377279e
test(yuwell): cover the V1150 evidence-report construction boundaries
shroominic Sep 11, 2026
10428f2
test(yuwell): extend the coverage sweep to the macOS Keychain session…
shroominic Sep 11, 2026
7f87c18
test(yuwell): close the last coverage-sweep gaps in commands.dart and…
shroominic Sep 11, 2026
67956bd
docs(yuwell): record structural-investigation status for CT5Init/Prot…
shroominic Sep 11, 2026
ba792f2
test(yuwell): cover the GRAB/RELEASE-bracketed observe path's remaini…
shroominic Sep 11, 2026
1a006c4
test(yuwell): cover cgm_driver_registry's constructor admission gates
shroominic Sep 11, 2026
a71533f
docs(yuwell): source-ground the pre-scan CT5BSNUtils admission gate a…
shroominic Sep 11, 2026
675a1e5
docs(yuwell): correct the scan callback's bound-branch — it's a three…
shroominic Sep 11, 2026
f8b15d9
docs(yuwell): source-ground CommonScan's already-active-device admiss…
shroominic Sep 11, 2026
a3e1bd0
docs(yuwell): record sureClose's second, backend-sourced write path
shroominic Sep 11, 2026
aa556a6
docs(yuwell): record CommonScan's actual primary path and its phone-n…
shroominic Sep 11, 2026
dfc082c
docs(yuwell): close the prepareMultiWear/finishAntTreatmentOut pointe…
shroominic Sep 11, 2026
b1450cc
docs(yuwell): trace onCheckIDResponse — closes the 0x31 continuation,…
shroominic Sep 12, 2026
7bd77e6
docs(yuwell): record onBSNRead as a logged-only callback, and stop de…
shroominic Sep 12, 2026
b8346ff
fix: bound Anytime history release paths
shroominic Sep 19, 2026
027527f
feat(yuwell): add private raw record state core
shroominic Sep 21, 2026
8782571
fix(yuwell): bind record key provenance
shroominic Sep 21, 2026
55706ab
test(app): keep provisional restore fixture fresh
shroominic Sep 21, 2026
b58b7bc
feat(yuwell): persist private raw history
shroominic Sep 21, 2026
78f8c51
fix(yuwell): enforce private recovery quarantine
shroominic Sep 21, 2026
dfbedea
fix(anytime): reconcile private live persistence
shroominic Sep 21, 2026
51882a9
docs: renumber Anytime persistence ADR
shroominic Sep 22, 2026
d979d49
fix(yuwell): require exact discovery names
shroominic Sep 22, 2026
3f830fa
test: cover N5P write-without-response topology
shroominic Sep 23, 2026
0bec58c
feat(yuwell): add internal temperature state model
shroominic Sep 23, 2026
30b8bd3
test: add guarded V1140 pairing coordinator
shroominic Sep 23, 2026
f0d69cd
feat: add bounded V1140 control exchange
shroominic Sep 23, 2026
9769db7
feat: add durable V1140 pairing authority
shroominic Sep 23, 2026
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
Diff view
14 changes: 14 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Reviewed gitleaks false positives.
#
# Each entry below was manually checked against the actual diff and
# confirmed to contain no real credential, token, or secret material.
# Do not add an entry here without doing that check first, and say why.

# ct5.macos.selftest.v1 is a FlutterSecureStorage/Keychain *lookup key
# name* (like a dictionary key), not a credential value. It labels a
# throwaway self-test entry that _selfTestKeychain() in
# openhealth/lib/yuwell_macos_debug_main.dart writes, reads back, and
# deletes to confirm the macOS Keychain is reachable before a debug BLE
# attempt. generic-api-key matched on the identifier name and the
# dotted-version-like string shape, not on any secret content.
164b1705bfab7c622088e526de2cfbb46cf485f3:openhealth/lib/yuwell_macos_debug_main.dart:generic-api-key:103
93 changes: 93 additions & 0 deletions docs/architecture/adr/0006-yuwell-private-record-persistence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ADR 0006: Persist Yuwell raw history as a private contiguous prefix

- Status: Accepted
- Date: 2026-09-21
- Owner: `@shroominic`
- Risk: R2 health/device data and serialized local state

## Context

The Anytime driver keeps exact authenticated history records and all-FF empty
slot observations in process memory. Process death discards both collections,
so the next session cannot distinguish a previously consumed empty slot from a
true history gap and restarts paging at index zero.

The pure Dart vendor package must remain independent of Flutter storage. The
app already has an atomic, backup-excluded restricted history-blob store. Raw
records must not enter the normalized repository, `CgmReading`, UI, export,
analytics, or decoder paths.

Saved communication credentials and a locally generated token do not prove an
immutable physical wear or record era. A sensor reset or lifecycle transition
cannot be ruled out from check-ID alone.

## Decision

The vendor package owns an additive schema-v1 `YuwellRecordState` envelope and
`YuwellRecordStateOwner` persistence boundary. The envelope stores one strict
contiguous prefix from index zero. Each slot is either the exact authenticated
11-, 15-, or 17-byte record for the bound layout or an explicit consumed all-FF
empty slot. An FC terminator is never stored or counted.

The envelope is bound to the fixed driver ID, a one-way selected-sensor binding,
exact verified firmware, a 128-bit local persistence generation, and the exact
history opcode/layout. The local generation namespaces storage; it is not
sensor-emitted era evidence. A domain-separated SHA-256 key over the selected
storage key and generation gives each generation a separate app blob, leaving
older generations untouched.

The owner validates the whole envelope before use, accepts each complete parsed
history batch atomically, serializes immutable whole-envelope writes, and
advances durable revision only after a successful write. It flushes after 16
newly consumed slots, after a larger completed frame, at history-cycle
completion, and on explicit disconnect drain. A failed write retains dirty
in-process state and the prior durable blob; it never deletes, truncates, or
repairs stored state automatically.

On restart, matching stored state remains quarantined. The driver must re-read
history from index zero and compare every durable record and empty slot before
trusting the cursor and requesting the suffix. Early termination, a missing
slot, or any record/empty/byte mismatch preserves the prior blob and fails
closed. This costs radio time proportional to the durable prefix but avoids
inventing sensor-era certainty.

Secure credential schema v2 will add exact verified firmware and the local
generation in the integration delivery. Schema v1 remains readable but cannot
authorize raw restore. A v1 saved session may upgrade only after the existing
read-only version query and unchanged authenticated check-ID succeed; no new
activation, configuration, pairing, or other state-changing command is added.

## Alternatives

- Keep records only in process memory: rejected because restart loses exact raw
history and FF slot continuity.
- Persist through the normalized health repository: rejected because raw
authenticated protocol evidence is not validated glucose and must remain
private.
- Add a vendor-specific database: rejected because atomic whole-envelope blobs
fit the bounded state and the app already supplies the required restricted
storage semantics.
- Put all records in secure credentials: rejected because Keystore/Keychain
credentials are for small bootstrap identity, not bounded history payloads.
- Trust check-ID plus a local random token as a sensor era: rejected because
neither is source-backed immutable wear evidence.
- Re-read only the durable tail: rejected for this delivery because source does
not establish a defensible tail witness that rules out every earlier-era
mismatch.

## Consequences and follow-up controls

- A process can lose at most the uncommitted suffix under the 16-slot policy;
the next process revalidates the complete durable prefix and re-fetches that
suffix.
- Live records ahead of the history prefix remain bounded in memory until a
matching history frame consumes their slots; they never advance durability.
- Malformed, future-schema, oversized, foreign, or conflicting state fails
closed without overwrite or deletion.
- Raw blobs are additive and ignored by older builds. Credential schema v2 and
driver/app composition must ship together; downgrade must reject unknown
secure credentials rather than corrupt them.
- Task 1 supplies only the pure package codec/store boundary. App durability is
not claimed until credential, driver, adapter, restart, and failure tests in
the integration delivery pass.
- Physical process-kill/restart proof remains a separate release gate.
1 change: 1 addition & 0 deletions docs/architecture/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enforcement detail is already implemented.
| [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 |
| [0006](0006-yuwell-private-record-persistence.md) | Accepted | Persist bound private Yuwell raw slots and revalidate the durable prefix before cursor resume |

## Adding an ADR

Expand Down
10 changes: 10 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ not establish Anytime 5P compatibility or reproduce the vendor-native glucose
algorithm. See the physical-evidence and V1150 production-publication gates
before changing that boundary.

That explicit debug composition can also inject additive private raw-record
durability. Credential schema v1 remains readable for authentication but does
not authorize restore. Schema v2 binds the exact sensor-key digest, verified
firmware, opaque generation, history opcode, and record layout. Recovery starts
at history index zero, compares every durable record and empty slot in
quarantine, and only then fetches and commits the suffix. Conflicts preserve
the old blob and fail closed. This path does not register Yuwell in normal
builds, enable normalized Anytime glucose, or establish physical restart
durability; an authorized process-kill/restart device test remains pending.

Restricted health-state schema three changes history-blob filenames from a
reversible base64 storage key to `history-<sha256>.blob`. Schema-zero/one
embedded histories and schema-two filenames migrate automatically. The rename
Expand Down
Loading
Loading
0