8000 fix(cbio): give every closed failure its own code and its own sentence by shroominic · Pull Request #186 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content

fix(cbio): give every closed failure its own code and its own sentence - #186

Merged
shroominic merged 1 commit into
feature/cbio-gs1-app-livefrom
fix/cbio-failure-taxonomy
Sep 18, 2026
Merged

shroominic merged 1 commit into
feature/cbio-gs1-app-livefrom
fix/cbio-failure-taxonomy

Conversation

@shroominic
Copy link
Copy Markdown
Owner

Closes #184.

The defect

Code Reachable before Readable before
cbio.connect.failed yes no - printed as itself
cbio.topology.failed yes no
cbio.auth.material yes no
cbio.auth.timeout yes no
cbio.auth.rejected yes no
cbio.write.failed never -
cbio.disconnected yes no

_sendMasked logged a refused write and returned false; every caller returned
quietly, so the session stayed in connecting with no terminal state. And
primaryErrorTextForSnapshot returned snapshot.lastError verbatim for any
driver that is not Libre 2, so the failure card showed cbio.connect.failed.

RED

cd packages/cgm_cbio && flutter test test/cbio_glucose_session_test.dart --plain-name 'write the radio refuses'
exit 1
CbioGlucoseSession lifecycle a write the radio refuses fails the setup with its own code [E]
  condition was not satisfied before the deadline
test/cbio_glucose_session_test.dart 247:3  _pumpUntil
cd openhealth && flutter test test/cbio_app_surface_test.dart --plain-name 'reaches the user as a sentence'
exit 1
Expected: not contains 'cbio.'
  Actual: 'cbio.connect.failed'
  cbio.connect.failed is a support code, not a sentence
test/cbio_app_surface_test.dart 126:7

Both runs are against 17db5b4, the base this branch forks.

GREEN

Same two commands on this branch: exit 0, +1: All tests passed! each.

The fix

_sendMasked stops returning a bare bool. It returns CbioFrameWrite -
sent, failed, unavailable, blocked, budgetExhausted - because those
five outcomes are not interchangeable. A blocked frame never left the app, an
exhausted read budget is a normal end to polling, and a failed write means the
sensor never received the frame.

  • _requireWritten(outcome) fails closed with cbio.write.failed when the
    outcome is failed. It is used by the three frames the vendor sequence cannot
    proceed without: authentication, the one-time clock, and the first packed
    query. The clock and query previously ignored their result entirely.
  • A refused write now publishes CgmSyncStage.error +
    CbioSessionPhase.failed + cbio.write.failed instead of parking.
  • _readFrom (the live poll) keeps its old behaviour for the non-write
    outcomes: only a genuinely spent budget publishes the budget state. A refused
    poll write no longer publishes "Read budget reached", w 8000 hich it never was.

userMessageForCbioFailure(code) gives each code its own sentence, and
primaryErrorTextForSnapshot uses it for CBio snapshots, exactly where Libre 2
already does. Samples:

  • cbio.auth.rejected - "The sensor refused the link credential this build
    uses. Choose another sensor or update the app."
  • cbio.topology.failed - "This sensor does not present the link OpenGlucose
    supports yet. Choose another sensor."
  • cbio.auth.timeout - "The sensor did not answer the link setup. Keep it close
    and try again."

What this deliberately does not change

The per-code statusText in _fail is still the same string. It is not the
user-visible surface for a failure: sensor_connection_screen.dart routes
error and disconnected stages to _ConnectionFailure, whose message comes
from primaryErrorTextForSnapshot. Changing statusText would have added a
second, competing layer of copy that nothing on the failure path reads. The
sentence layer is the one that was missing.

_failureCodeFor keeps CbioProtocolException -> topology: it is the
catch-all for an unexpected error, and every deliberate protocol rejection is
already thrown with its own code at the throw site. Splitting topology by
characteristic would be a new taxonomy decision rather than a fix, so it is left
alone here.

Tests added

  • a write the radio refuses fails the setup with its own code - stage, code
    and phase.
  • an unusable credential is never reported as a refused one - the link
    resolves its credential before it asks the sensor, so those two codes cannot
    swap.
  • a closed CBio failure reaches the user as a sentence - loops all seven
    codes and fails if any reaches the card as cbio.*.

Verification

  • cd packages/cgm_cbio && flutter test - exit 0, +77: All tests passed!
  • cd openhealth && flutter test - exit 0, +481: All tests passed!
  • flutter analyze - No issues found! in both packages
  • dart format on every line this branch adds - no change

Formatter note: packages/cgm_cbio/test/cbio_glucose_session_test.dart already
carried unrelated formatter drift at 17db5b4 (verified against a clean archive
of the base commit), so only the added lines are kept format-stable here.

shroominic added a commit that referenced this pull request Sep 18, 2026
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.
shroominic added a commit that referenced this pull request Sep 18, 2026
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.
@shroominic
Copy link
Copy Markdown
Owner Author

Rebase reminder (comment only, no edits to this branch).

The lane head is now 05785b0 (#192 merged). This PR is still based on 17db5b4; the merge-base is fine, but expect a conflict in
packages/cgm_cbio/lib/src/cbio_glucose_session.dart around credential resolution. Resolve it by keeping the injected path:

  • the session resolves CbioCredentials once per session into _resolved, before the transport is touched, and every mask/unmask/builder call receives _streamKey/the material explicitly;
  • CbioCompiledAuthMaterialProvider and the com 8000 piled constants are gone; a build without material fails closed with cbio.auth.material;
  • the lane also reads _clockReferenceEpochSeconds (set in _writeClock) when it derives the record-index anchor, so keep that field and the _historyReadingsFor(anchor) / metadata spread when you resolve.

Rebase onto feature/cbio-gs1-app-live before review so CI runs against the lane head.

@shroominic
shroominic force-pushed the fix/cbio-failure-taxonomy branch from 375055b to ced53af Compare September 18, 2026 09:42
@shroominic
shroominic merged commit 6ec9318 into feature/cbio-gs1-app-live Sep 18, 2026
5 of 10 checks passed
@shroominic
Copy link
Copy Markdown
Owner Author

Rebased onto the lane and merged as 6ec9318. One rebase artifact worth recording: the conflict-free hunk took your CbioFrameWrite return type, but #192 had since added an early if (resolved == null) return false; inside _sendMasked that your diff never saw, so cgm_cbio analyzed with return_of_invalid_type. It now returns CbioFrameWrite.unavailable - the credentials path reaches that branch only before the session resolved its material, and nothing is written, which is exactly what unavailable means. Two test blocks from #182/#188 that git interleaved with yours were kept whole rather than merged line by line. Evidence at the merged tip: cgm_cbio 96 passed / 2 skipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0