8000 feat(cbio): anchor the GS1 record index to the clock the app set by shroominic · Pull Request #197 · shroominic/OpenGlucose · GitHub
[go: up one dir, main page]

Skip to content

feat(cbio): anchor the GS1 record index to the clock the app set - #197

Merged
shroominic merged 1 commit into
feature/cbio-gs1-app-livefrom
feature/cbio-index-time-anchor
Sep 18, 2026
Merged

shroominic merged 1 commit into
feature/cbio-gs1-app-livefrom
feature/cbio-index-time-anchor

Conversation

@shroominic
Copy link
Copy Markdown
Owner

Closes #196. Gate G2b on the app-live lane, on top of 05785b0.

What changed

The GS1 surface had no time at all: the 08 counter is epoch-less (#146), so
recordedAt stayed null and the hero showed only the protocol position. This
adds the one reference the app establishes itself - the sensor clock it writes
once per session - and nothing more:

  • CbioIndexTimeAnchor (new, packages/cgm_cbio) is an index-to-absolute-time
    reference: anchor position, that position's own stamp, the covered range, the
    written clock reference, the source, and a one-record uncertainty.
  • deriveCbioIndexTimeAnchor publishes one only when the session wrote the
    clock and the newest stored record's own stamp agrees with the app's clock
    within 3 minutes. Older positions step 60 s per index, as the vendor layout
    reports the counter (base + 60 * i), and the covered range ends at the first
    hole or counter jump.
  • CbioGlucoseSession records the written epoch in _writeClock, derives the
    anchor on every publication, stamps recordedAt only for covered positions,
    puts the anchor in the snapshot metadata, and names it in diagnostics.
  • The hero gains cbioClockState: Sensor clock set by this app · latest 10:05 (±1 min) when anchored, Sensor clock unsynced · ordered by sensor index, not by clock when not - never a placeholder --, never a
    counter-derived minute.

RED

Both halves failed before the implementation:

cd openhealth && flutter test test/cbio_clock_anchor_surface_test.dart
Error: Method not found: 'cbioClockStateText'.
Error: Method not found: 'cbioAnchorForSnapshot'.
00:00 +0 -1: Some tests failed.
cd packages/cgm_cbio && flutter test test/cbio_index_time_anchor_test.dart
lib/src/cbio_index_time_anchor.dart:161:17: Error: Type 'CbioRawGlucoseRecord' not found.
00:00 +0 -1: Some tests failed.

GREEN

cd packages/cgm_cbio && flutter test        -> 91 passed, 2 skipped (base 81)
cd packages/cgm_cbio && flutter analyze     -> No issues found!
cd openhealth && flutter test               -> 485 passed (base 480)
cd openhealth && flutter analyze            -> No issues found!
cd openhealth && flutter analyze integration_test -> No issues found!

The refused case is the #146 capture: 448 stored records, 7 h 28 m away from
the clock the app set, publishes no anchor and leaves every recordedAt null
(CbioGlucoseSession clock anchor group). The accepted case is asserted to
step 60 s per anchored position, not from the counter.

The #193 guard still passes

#193's fixture carries no anchor metadata, so its expectations are unchanged.
Checked on this branch with that 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 guard file is not part of this branch; it stays with #193.

UI evidence

Layout captures of the dashboard hero (flutter test renders test-font glyphs,
so the copy below is read out of the widget tree, not the image):

  • hero, anchored: 5.5 | Live | Sensor raw value · index 10067 | 3 readings stored · sensor minutes 10065–10067 | Sensor clock set by this app · latest 10:05 (±1 min) | Provisional reading. Sensor raw / 10, scale unverified.
  • hero, unsynced: identical except Sensor clock unsynced · ordered by sensor index, not by clock.

10:05 is 03:05Z in the device zone, and the anchored copy is asserted
against DateFormat('HH:mm').format(instant.toLocal()), so the localisation is
covered by the test rather than the screenshot. A device re-capture of the
anchored copy is still pending (the current capture in
docs/testing/cbio-gs1-app-live.md predates the anchor and shows the unsynced
copy); the doc records that and the rule.

Not touched

The other lane PRs (#175, #177, #182, #186, #188) still need the rebase onto
05785b0; nothing here edits their branches. G5 (#195) builds on this anchor -
noted on that issue.

CI: the known reds (format-check drift, private_bench_test on Linux,
make test-integration root mixing, Apple-silicon preview) are unchanged and
pre-existing on this lane.

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