8000 test(cbio): pin the GS1 surface to the timestamp-free reading it publishes by shroominic · Pull Request #193 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content

test(cbio): pin the GS1 surface to the timestamp-free reading it publishes - #193

Merged
shroominic merged 1 commit into
feature/cbio-gs1-app-livefrom
test/cbio-timestamp-guard
Sep 18, 2026
Merged

shroominic merged 1 commit into
feature/cbio-gs1-app-livefrom
test/cbio-timestamp-guard

Conversation

@shroominic
Copy link
Copy Markdown
Owner

Refs #146. Answers the open G2 question: no rendered timestamp on the GS1 lane is wrong today.

Verdict

The skew is gone because the GS1 lane renders no clock derived from the record
counter at all. Three independent checks:

  1. CbioGlucoseSession._historyReadings publishes recordedAt: null for every
    08 record - pinned by cbio_glucose_session_test.dart (expect(latest.recordedAt, isNull)).
  2. The hero has no time to show: its subtitle for a GS1 session is
    Sensor raw value · index 10070, and the stored-range caption is in sensor
    minutes. readingTimeText returns -- for a timestamp-free reading.
  3. The chart's _axisLabel and its tooltip both key off recordedAt == null,
    so a GS1 point renders m<minute> / Minute <n>, never HH:mm.

The arithmetic from #146 still holds as the shape of the trap: 448 stored
records x 60 s is exactly the 01:36 -> 09:04 (+7 h 28 m) the screen showed for
a 448-record fetch, while the phone clock did not move.

RED

Mutation check on this branch's base (05785b0). Reinstating the removed
projection in CbioGlucoseSession._historyReadings:

recordedAt: DateTime.fromMillisecondsSinceEpoch(record.rawTime * 1000, isUtc: true),
cd packages/cgm_cbio && flutter test test/cbio_glucose_session_test.dart
Expected: null
  Actual: DateTime:<2026-09-18 05:29:56.000Z>
00:00 +17 -1: Some tests failed.

The mutated source is restored; the only change on this branch is the new test
file.

GREEN

cd openhealth && flutter test test/cbio_timestamp_guard_test.dart
00:00 +3: All tests passed!

Tests added

openhealth/test/cbio_timestamp_guard_test.dart, three tests:

  • the counter-to-clock formula #146 removed is the on-screen skew - pins
    448 * 60 == 7 h 28 m and that the removed formula produces exactly it.
  • a GS1 reading has no wall clock for any surface to render - recordedAt is
    null and readingTimeText / clampedDisplayRecordedAt refuse to invent one.
  • the hero and the chart carry no counter-derived clock - renders the real
    dashboard, finds Sensor raw value · index 10070, asserts no HH:mm and no
    Latest reading at in the hero, and asserts only timestamp-free readings
    reach CgmDashboardChart. The chart's null-label branch has no seam to assert
    directly (_axisLabel is private and paints to a canvas), so this pins the
    input contract on top of the source pin in (1).

Observed, not fixed here

openhealth/test/cbio_app_surface_test.dart builds its GS1 fixture with
recordedAt: DateTime.now().subtract(...), which is not what the session
publishes. It has not hidden the skew (no assertion there depends on it), but a
fixture that invents timestamps cannot detect a regression in this area. Left
alone to avoid colliding with #188, which edits the same file.

Verification

  • cd openhealth && flutter test - exit 0, +483: All tests passed! (was +480)
  • flutter analyze - No issues found!
  • dart format --output=none --set-exit-if-changed test/cbio_timestamp_guard_test.dart - clean

…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.
@shroominic
Copy link
Copy Markdown
Owner Author

No rebase needed for this PR: the anchor branch (#197) keeps the guard green unchanged, because its fixture carries no anchor metadata.

Verified on feature/cbio-index-time-anchor with this PR's test file applied:

cd openhealth && flutter test test/cbio_timestamp_guard_test.dart
the counter-to-clock formula #146 removed is the on-screen skew
a GS1 reading has no wall clock for any surface to render
the hero and the chart carry no counter-derived clock
00:00 +3: All tests passed!

The hero's new clock line is a separate Text (cbioClockState), so Sensor raw value · index 10070 and the chart's recordedAt == null expectations still hold. When an anchor is present the surface is allowed a per-record time, from the app-set clock and not from the counter.

@shroominic
shroominic merged commit ba9057f into feature/cbio-gs1-app-live Sep 18, 2026
5 of 10 checks passed
shroominic added a commit that referenced this pull request Sep 18, 2026
The GS1 surface published no time at all: the `08` counter is epoch-less, so
#146/`#193` forbid rendering a wall clock from it. That left the hero with
`Sensor raw value · index 10070` and nothing else, and any surface that did ask
for a time showed a placeholder.

The one reference the app establishes itself is the sensor clock it writes
once per session. `CbioIndexTimeAnchor` turns that into absolute time honestly:

- an anchor exists only when the session wrote the clock and the sensor's own
  newest record stamp agrees with the app's clock within
  `cbioAnchorTolerance` (3 min);
- the anchored position carries its own stamp, and every older position steps
  60 s per index, as the vendor layout reports the counter (`base + 60 * i`);
- the range the anchor speaks for ends at the first hole or counter jump, so
  positions the archive cannot support keep no timestamp;
- the anchor travels in the snapshot metadata (`anchorIndex`,
  `anchorEpochSeconds`, `anchorCoveredFrom`, `referenceEpochSeconds`) and the
  diagnostics name it, so provenance is readable without the radio.

The counter is never the source: a sensor that did not take the written clock
(the 7 h 28 m skew of #146) publishes no anchor, and the hero says
`Sensor clock unsynced · ordered by sensor index, not by clock` instead of a
placeholder or an invented minute. With an anchor the hero reads
`Sensor clock set by this app · latest 10:05 (±1 min)`, localised by the device.

Refs #146, #193.

Tests: cgm_cbio 91 passed (2 skipped), openhealth 485 passed; `flutter analyze`
clean in both, including `openhealth/integration_test`.
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