Repository navigation
chore(release): append the app-live and scan-close lanes to the 0.4.0 aggregate - #163
Merged
Merged
Conversation
The GS1 driver now owns one authenticated session: connect, subscribe on FF31, authenticate, ingest the pushed 08 history, then poll the live edge and publish every reading as an explicitly provisional raw record. App surface changes: - the nearby-sensor list can finally complete, so a real sensor is selectable from the dashboard flow, - the hero value renders the sensor's raw field / 10 with no glucose unit, - the hero reports how many records were stored and their sensor-minute range, so the fetch is verifiable without opening a chart, - the provisional marker is on every rendered number and reads "sensor raw / 10, scale unverified". Reading positions come from the protocol's own index counter; the sensor's second counter has no epoch, so no wall-clock timestamp is invented from it. Evidence, screenshots, and the reproduction steps are in docs/testing/cbio-gs1-app-live.md.
FlutterBluePlusTransport.scan returned a stream that outlived the scan. flutter_blue_plus stops the radio at its own timeout, but the transport's cleanup awaited cancelResults, cancelScanning, awaitPendingStart, and stopScan before closeController. On a stack that leaves any of those pending, controller.close() never ran, so callers waited forever and cancelling the subscription hung for the same reason. - close the caller's stream first in closeFlutterBluePlusScanResources, - bound each cleanup step so a pending plugin future cannot hold a caller, - arm a scan deadline so a scan still closes when the plugin stops the radio without publishing isScanning = false, - cover it with a regression test that drives cleanup with futures that never complete. Measured before the fix on a Pixel 6: a 6 s window left isScanningNow false at ~7 s while the transport stream was still open at 12 s, and a 25 s timeout on the stream fired, while the plugin's raw result stream delivered 429 advertisements in the same period. Fixes #143.
The Secret Scan gate fails on this lane with one gitleaks `generic-api-key` finding in `packages/cgm_cbio/test/cbio_crypto_test.dart`. The value is a published synthetic masking vector, but it is a 50-character high-entropy string assigned to a name containing "auth", which is exactly the shape the detector is built to catch. The five masking vectors are now byte lists. The vectors and the assertions are unchanged; `dart test` still passes 60 tests, and the same package tree now reports no leaks to gitleaks 8.24.3.
`make format-check` fails on this lane in the Quality job: the new `openhealth/integration_test/cbio_glucose_query_test.dart` was committed unformatted, so the CI gate exits 2 before lint runs. This is the formatter's own output, nothing else: `dart format` reports one changed file and `make format-check` then exits 0 across every project.
…release/v0.4.0-lane-append
…release/v0.4.0-lane-append
`make test-integration` handed `test/integration/*` and `integration_test/*` to one `flutter test` call, which Flutter rejects: Integration tests and unit tests cannot be run in a single invocation. The two roots now run as separate lanes. The host lane keeps its behaviour (`test/integration/*` plus tag-marked files, and `integration_test/*` for plain Dart packages). The device lane runs `integration_test/*` in its own invocation and only against hardware named by `FLUTTER_TEST_DEVICE_ID`; otherwise it reports the deferred files and the knob that enables them, so a host without a device stays green instead of failing closed on a lane it cannot run. Adds scripts/test-workspace-integration-runner.rb, which drives the real script against a fixture repository with stubbed Flutter tooling and pins the lane split, the deferral notice, the device-id plumbing, and the existing nothing-found diagnostic. The check runs from `make tooling-check`. (cherry picked from commit d8c9acb)
…e formatter output Merges the two lanes the aggregate was missing (#142 app-live, #144 scan-close) and cherry-picks the integration-runner gate fix (#141) instead of merging main, so the aggregate keeps its own history. Also carries `dart format` output for four files that the lanes committed unformatted, so the aggregate's own Quality gate can run to completion.
The dependency review still described cgm_cbio as an offline scaffold with no vendor material. That is no longer true: the package carries link material and a stream masking constant derived from a shipped third-party sensor application, i.e. exactly the shape that needs a notice and redistribution review before an artifact ships. Corrects the package section, states the two open reviews (notice and redistribution terms, and how the material reaches a build at all), and adds the matching paragraph to NOTICE.md. References the derivation record by path instead of restating any bytes.
The vector table printed the authentication frame's plaintext hex, whose bytes 9..24 are the 16-byte link credential, and the masked column was derived from the real stream key. Both contradict the record's own stated policy and belong to the material tracked in #164. Keep the plaintext layouts, omit the credential field, and generate masked bytes at run time from injected material instead.
The archive divided the raw 08 field by ten and then multiplied by 18.0182 to produce an mg/dL number, and the test asserted that number as a fact. Nothing in this repository establishes that /10 is mmol/L, and no reference measurement exists for this sensor, so the accessor asserted a unit the protocol does not carry. The app rendered that number as a glucose value. Expose the raw field and its scaled value and nothing else: rawCurrentScaled is documented as an unverified engineering value with no unit, the unit-bearing accessors are gone, and a regression test fails if either name comes back. Refs #145
Merging this lane into the sensor aggregate broke openhealth/test/session_sync_failure_test.dart, the guard for the bounded session-sync failure contract (#133/#134): the connection screen started passing CgmSessionSnapshot.statusText straight into the progress card for every cbio snapshot, so a session that never decoded rendered the driver's internal string ('Listening for notifications' in the guard) instead of the stage label 'Syncing sensor history' the contract asserts. That is a surface regression beyond the guard: statusText is unbounded and internal, and the screen deliberately renders a closed set of user-facing strings for every other driver. Map the closed phase in cbioPhaseMetadataKey (connecting, authenticating, history, live, disconnected) to product copy instead, and fall through to the generic stage label when the phase is absent or the snapshot is not cbio. The guard is untouched. New coverage: a presentation test for the mapping and a widget test that drives the real connect button and asserts the bounded-sync stage label is shown and the driver's text is not. Refs #162
…m_cbio driver The aggregates still declared 0.1.4+25 while main shipped 0.1.6+28, so an assembled 0.4.0 artifact would carry a version and build number below the released one. The release workflow also requires the tag to equal the pubspec version, so the train now records 0.4.0+29 (next build after main's +28). The cgm_cbio manifest and changelog still described an offline scaffold with no transport, authentication, or glucose support. Both now describe the delivered live driver, and the package version moves to 0.1.0 to match the other sensor packages.
The path dependency records the package version, so the 0.1.0 bump has to reach openhealth/pubspec.lock or make bootstrap fails under --enforce-lockfile.
…ting' into release/v0.4.0-lane-append
…g' into release/v0.4.0-lane-append
…to release/v0.4.0-lane-append
… into release/v0.4.0-lane-append
…' into release/v0.4.0-lane-append
…n' into release/v0.4.0-lane-append
…nto release/v0.4.0-lane-append
…ease/v0.4.0-lane-append
origin/fix/cbio-progress-copy left openhealth/test/cbio_app_surface_test.dart unformatted, so format-check would stop the Quality job before lint ran. Formatter output only; the lane keeps its own formatting PR.
shroominic
force-pushed
the
release/v0.4.0-lane-append
branch
from
September 18, 2026 04:51
212237c to
e9d3eeb
Compare
The sensor lane added the app's `integration_test` dev dependency and its harness directory, so `pod install` now resolves an `integration_test` pod that the committed lockfile never recorded. The iOS job fails closed on that drift: the iOS build changed ios/Podfile.lock; update and review the lockfile explicitly This records the change the pinned toolchain produced on CI (Xcode 26.6, CocoaPods 1.16.2): the PODS, DEPENDENCIES, EXTERNAL SOURCES and SPEC CHECKSUMS entries for `integration_test` only. main is unaffected, its lockfile is byte-identical to the pre-image. No local Xcode or CocoaPods on this host, so the change is applied from the CI diff and verified by blob hash: the result is ad15bd2, byte-identical to the post-image the iOS job generated.
…-test' into release/v0.4.0-lane-append
…to release/v0.4.0-lane-append
shroominic
force-pushed
the
release/v0.4.0-lane-append
branch
from
September 18, 2026 05:16
a2f9ce4 to
018dd90
Compare
…ants The vendor GS1 stream key, link credential, and authentication prompt were plaintext constants in packages/cgm_cbio/lib/src/cbio_crypto.dart. The repository is public, the file is on the 0.4.0 release aggregate, and the Secret Scan job is red on the same lane for a fixture derived from it. Remove the constants and make the material an explicit input: * cbio_credentials.dart adds CbioCredentials (validated, immutable, redacting toString), CbioCredentialSource, CbioMapCredentialSource, CbioDefineCredentialSource, and the fail-closed CbioCredentialUnavailable. * cbioRc4Keystream, maskCbioFrame, unmaskCbioFrame, and every builder in cbio_vendor_frames.dart now take the key and material as required arguments, so a caller that has not resolved material cannot compile a call. * the device harness reads the material from the process environment or --dart-define and aborts with vendor-material-missing before touching radio. * tests use clearly synthetic fixtures; the real-material checks skip unless the values are injected. * .gitleaks.toml adds a rule for this exact class of literal and a narrow allowlist for synthetic fixtures only. Refs #164 (cherry picked from commit 7fa477c)
…ource The live session still called the pre-redaction crypto API: `maskCbioFrame`, `unmaskCbioFrame`, and every masked builder defaulted to compiled constants, and the session read its link credential from `CbioCompiledAuthMaterialProvider`. Those defaults are gone, so the lane has to resolve the material explicitly. - `CbioGlucoseSession` takes a `CbioCredentialSource` and resolves it once per session, before the transport is touched. An unconfigured build fails closed with `cbio.auth.material` and a configuration status text instead of opening a link it could never authenticate or unmask. - Every mask, unmask, and masked builder receives the resolved key explicitly, and the authentication frame receives the resolved material. - `CbioSensorDriver` exposes its source and a `canAuthenticate` predicate. - The app's platform registry registers the GS1 driver only when the build supplied the material, so a plain build does not offer a sensor it cannot read. The capture harness reads the material from the environment or `--dart-define` and reports `vendor-material-missing` when it is absent. Tests: cgm_cbio 81 passed (2 skipped), openhealth 480 passed; `flutter analyze` clean in both, including `openhealth/integration_test`.
…ishes #146 recorded a +7h28m skew on screen: the hero read `Latest reading at 09:04` and the 12 h axis ended at `09:01` while the phone clock read `02:34`. The counter advances 60 s per stored record, so 448 stored records rendered as 7 h 28 m of apparent elapsed time. The rendering half of that fix lives in the app-live branch: the session publishes `recordedAt: null` for these records, the hero reports the protocol position (`Sensor raw value · index 10067`), and the chart's null path renders `m<minute>`. Nothing on the lane pins that, so this adds the guard: - the removed counter-to-clock formula is asserted to be the on-screen skew (448 x 60 s == 7 h 28 m), so the arithmetic cannot be re-derived as harmless; - a GS1 reading is asserted to carry no `recordedAt`, and the hero's only time formatter is asserted to refuse to invent one; - the real dashboard is rendered with those readings and asserted to show the protocol position with no `HH:mm` anywhere in the hero, and to hand the chart only timestamp-free readings. Mutation check: reinstating `recordedAt: DateTime.fromMillisecondsSinceEpoch(record.rawTime * 1000, isUtc: true)` in `CbioGlucoseSession._historyReadings` fails `cbio_glucose_session_test.dart` with `Expected: null / Actual: DateTime:<...>`. Tests: openhealth 483 passed; `flutter analyze` clean; `dart format` clean on the added file.
Owner
Author
|
Head
This supersedes the |
Absorbs feature/cbio-gs1-app-live at 05785b0, which carries the redacted credential API (#166 verbatim as a7c21bc) and the live lane's adoption of an injected CbioCredentialSource (PR #192, issue #191). Conflict resolution: - packages/cgm_cbio/README.md: union. The aggregate's FF31 reply-decode paragraph (#132) and the lane's new injected-material section are both kept; neither lineage had the other. - packages/cgm_cbio/test/cbio_crypto_test.dart: take the lane's version. It supersedes the masked-vector fixture from #148 by removing the published vectors entirely and testing the mask with synthetic material.
…release/v0.4.0-lane-append
…edential API Merges fix/bounded-automatic-reconnect (#182). The branch forked at 17db5b4, so its session conflict re-introduced the compiled credential provider that #166 removed. Resolution keeps the aggregate's injected-credential API and ports only the new logic: - cbio_FailureAllowsAutomaticReconnect is added; the provider classes stay out. - The session's reconnect-allowed field, metadata marker, and _fail gate apply unchanged. - app_controller.dart and the persistence test are unions: the aggregate's sync-stage deadline tracking and the wedged-scan test both stay. No credential, address, or vendor material is added by this merge.
Merges fix/cbio-failure-taxonomy (#186). Conflicts were both additive: - session_presentation.dart: union. The aggregate's closed-phase progress copy and the new per-code failure sentences are independent additions. - cbio_glucose_session.dart: take the aggregate's keyed builder call and keep the branch's write verdict. One auto-merged line returned bool from a CbioFrameWrite method; corrected to CbioFrameWrite.unavailable.
Merges fix/cbio-history-holes (#188). The one conflict was additive: the aggregate's closed-failure sentence test and the branch's hole-caption tests both insert at the same point, so both are kept. No credential, address, or vendor material is added by this merge.
…lane Merges fix/cbio-device-harness-assertions (#185). The branch forked at 4702025, before the app-live lane's injected-credential adoption, so its harness files call the pre-redaction API. Resolutions: - packages/cgm_cbio/lib/cgm_cbio.dart: union of both exports. - scripts/flutter-workspace.sh: union. device_integration_files() keeps the aggregate's device lane; device_backed_harnesses() feeds the new test-e2e deferral report. - openhealth/integration_test/cbio_glucose_query_test.dart: take the branch's file. It is a strict superset of the aggregate's (formatting only). - openhealth/integration_test/cbio_glucose_authenticated_test.dart: take the branch's instrumented file and re-apply the aggregate's injected-credential boundary: _credentials from the environment/defines, a noted vendor_material_missing abort, and key:/material: arguments on every builder and unmask call.
…ct' into release/v0.4.0-lane-append
…o release/v0.4.0-lane-append
The guard that keeps the vendor material out of the tree had never been exercised, and as written it belonged in the wrong place. - `security/gitleaks-vendor-material.toml` holds one tree-scoped rule that matches a material-shaped binding plus a literal payload. It restates no byte, no key-derived vector, and no device address, and it carries no allowlist, because an exemption would have to name the value it exempts. - `scripts/check-cbio-vendor-material.sh` makes the rule prove itself: it scans the checked-out tree, then asserts the same rule still reports a deliberate synthetic canary. A rule that silently stops matching now fails instead of reporting a clean tree. - The scanner is installed through the repository's existing checksum-pinned quality-tool installer, so local runs and CI use gitleaks 8.24.3, the version `gitleaks-action` resolves to. - `make vendor-material-guard` runs it locally and is part of `make check`; the `Vendor Material Guard` job in `security.yml` runs it on every pull request. The rule is deliberately not added to `.gitleaks.toml`: the material and a key-derived masked vector are already in this repository's public history, so a history-wide rule would fail forever and no change on the tip could clear it. Fixes #172.
Two union resolutions joined two adjacent test blocks without the shared closing brace, which the Dart parser rejects; both now close before the next test. dart format also normalised three files the absorbed branches left unformatted or that the resolution re-flowed: session_presentation.dart, the authenticated harness, and the live-capture harness.
…andidate Reverts the merge of fix/cbio-archive-unit-claim (#168). #168 removes CbioRawGlucoseRecord.derivedMilligramsPerDecilitre and .derivedMillimolesPerLitre and leaves only an explicitly unitless rawCurrentScaled. The app-live surface still fills CgmReading.valueMgdl from the removed mg/dL accessor, so the merge leaves six analyzer errors in cgm_cbio and, fixing them, would change the number the live surface renders. That is a unit-reference decision on the product surface, not a mechanical merge, and it is the owner's to make. The lane needs an adoption change (as #192 was for #166) before this can land. Recorded as excluded in the PR body.
Three cases added by #186 constructed a session with the default credential source, which now fails closed with cbio.auth.material before the code under test can run. They take the suite's synthetic source like their neighbours, so they reach cbio.auth.rejected, cbio.auth.timeout, and cbio.write.failed again.
…budget Closes #198. The Unit gate failed on protocol_capture_status_test.dart:123 with 'Expected: a value greater than or equal to <3> / Actual: <0>' on head a084d8f, while the same job passed on 018dd90 with the same test and the same app sources for this path. The test fired its heartbeat timer twice and then counted statuses after a fixed 40 event-loop turns; the status writer commits through real asynchronous work, so a loaded runner can finish those turns before the writes land. _pumpUntil() pumps in small chunks until the condition holds, bounded by a wall-clock timeout so a real hang still fails the following assertion with the real evidence. The strictly-advancing assertions are unchanged. Verification: - flutter test test/protocol_capture_status_test.dart 3/3 pass - flutter test test/ (483 tests) pass twice - dart format --set-exit-if-changed lib test integration_test exit 0
…e' into release/v0.4.0-lane-append
This was referenced Sep 18, 2026
…gelogs The repository changelog requires package-level public API changes to be recorded in the package changelog too, and neither file mentioned this cycle's additions. - packages/cgm_cbio/CHANGELOG.md (0.1.0): CbioSessionEvidence, CbioSessionOutcome and CbioWriteKind, including the redaction boundary and the unverified unit status. - CHANGELOG.md (Unreleased): the redacted GS1 evidence artifact and harness verdicts, and the self-proving vendor-material guard. Docs only; no code or gate input changes.
This was referenced Sep 18, 2026
Owner
Author
|
Release aggregate note: #163 remains open as the lane append and is not the final source of truth for CBIO GS1. The complete implementation and release workflow fix are in #209 at |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Assembled 0.4.0 candidate for #154. Base
release/v0.4.0; headrelease/v0.4.0-lane-append@4a865cd,mergeStateStatus: CLEAN. Every lane tip claimed below is a real ancestor. Nothing here merges: this PR and every lane PR stay open.Gate matrix — all ten checks green on
4a865cdtooling-check format-check lint)4a865cd4a865cd4a865cd80004a865cd4a865cd4a865cd4a865cd4a865cd4a865cd4a865cdThe same matrix was green on
92a1de2(Quality 3m24s, Unit 3m6s, Integration 1m48s, Vendor Guard 4s, Android 5m54s, iOS 11m53s, macOS 11m15s, Web 2m16s, Secret Scan 6s, Dependency Review 9s);4a865cdadds only the two changelog entries, and this table is that head's own run.The head before
92a1de2,a084d8f, was green on nine of ten: Unit failed onprotocol_capture_status_test.dart:123(Expected: >= <3>,Actual: <0>) — a fixed event-loop budget rather than a product contract. The same job passed on018dd90,git diff --name-only 018dd906..a084d8ftouches nothing that test imports, and the file passes 5/5 locally. Filed as #198, fixed by #203, absorbed here as92a1de2, rather than absorbed as a re-run.Local cross-check on
4a865cd:bootstrap,format-check,lint(all nine projects, 0 issues),test-unit(all packages, app 497),test-integration, andscripts/check-cbio-vendor-material.sh(canary rejected, tree clean) exit 0.Absorbed this cycle
feature/cbio-gs1-app-liveat05785b0(feat(cbio): stream GS1 history and live readings into the app #142), which now carries the redacted credential API (fix(cbio): require injected vendor material instead of compiled constants #166 verbatim, asa7c21bc) and the lane's own adoption of an injectedCbioCredentialSource(fix(cbio): resolve the live lane's vendor material from an injected source #192, issue The live GS1 lane still compiles its vendor key, so it cannot compile against the redaction branch #191). This is what unblocked the fix(cbio): require injected vendor material instead of compiled constants #166/fix(cbio): drop the unverified mg/dL claim from the raw record #168 note from the previous cut.main, carried as cherry-pick0490128, somain's six post-fork commits are not imported). It now proves itself here rather than on a tree that compiles material.Merge resolutions, all recorded in the commits: the app-live advance was a union on
packages/cgm_cbio/README.md(the aggregate'sFF31reply-decode paragraph and the lane's injected-material section are independent) and took the lane's test file where it supersedes #148's masked-vector fixture. #182 forked before the redaction, so its session conflict re-introduced the compiled credential provider: the resolution keeps the aggregate's injected API and ports only the new reconnect logic. #186's write-verdict change neededCbioFrameWrite.unavailablewhere an auto-merged line returnedbool. Both #185 harnesses took the branch's instrumented file with the aggregate's credential boundary re-applied by hand. Three #186 cases that constructed a session without material now take the suite's synthetic source.Packaging and attribution: the root
CHANGELOG.mdentry for the GS1 lane and thecgm_cbio0.1.0entry did not mention this cycle's additions, so4a865cdrecords the session-evidence model, the redacted evidence artifact with the harness verdicts, and the self-proving vendor-material guard.Still excluded
fix/cbio-archive-unit-claimis deliberately out. It removesderivedMilligramsPerDecilitre/derivedMillimolesPerLitreand leaves only an explicitly unitlessrawCurrentScaled, but the app-live surface still fillsCgmReading.valueMgdlfrom the removed accessor: merging it leaves six analyzer errors incgm_cbio, and repairing them changes the number the live surface renders. That is a unit-reference decision, so it needs a lane adoption change (what fix(cbio): resolve the live lane's vendor material from an injected source #192 was for fix(cbio): require injected vendor material instead of compiled constants #166) rather than an assembly edit. The candidate therefore still ships the mg/dL accessor; units stay UNVERIFIED behind the provisional marker. Recorded on fix(cbio): drop the unverified mg/dL claim from the raw record #168.main): fix(workspace): isolate host and device integration test roots #141's content is carried as a cherry-pick, fix(security): scope the scheduled secret sweep to a real finding #150 fixes the scheduled sweep onmain, which this tree does not contain.Decisions
main-based re-cut in this cycle, and the candidate is behindmain.mainis six commits ahead ofrelease/v0.4.0(EN/zh localization feat(app): add English and Simplified Chinese localization #85, TestFlight delivery workflow ci: add protected TestFlight delivery workflow #66, iOS export share sheet fix(ios): restore archived export share sheet #80, v0.1.5/v0.1.6 prep chore(release): prepare v0.1.5 #81/Release OpenGlucose 0.1.6 #88, Android dependency bump chore(deps): bump com.android.application from 9.3.1 to 9.4.0 in /openhealth/android #105). A trial merge ofmaininto this head conflicts in 12 files / 33 hunks, andopenhealth/lib/main.dartalone holds 537 conflict lines, because feat(app): add English and Simplified Chinese localization #85 rewrote the same file the sensor lane rewrote. Re-cutting is a lane-level reconciliation with bilingual copy — its own focused task — not a merge to do under a release deadline. Residual exposure, stated plainly: this candidate is newer thanmainin identity (0.4.0+29) but not a superset of it — it lacks main's localization, its TestFlight workflow, and its iOS export fix. It must not be merged tomainas the release until that reconciliation lands.openhealth/pubspec.yamlis0.4.0+29,cgm_cbiois0.1.0with a live-driver description,NOTICE.mdcarries the interoperability-material paragraph, anddocs/dependencies.mdrecords the vendor-material review — both halves of Release packaging metadata is stale: aggregate version behind main, cgm_cbio manifest and notices unreviewed #157 on this branch.Queued
The
main-reconciliation lane (#85 localization against the rewritten sensor surface); an app-live adoption of #168; #155/#156 follow-ups beyond #185/#189.