Repository navigation
feat(cbio): anchor the GS1 record index to the clock the app set - #197
Merged
shroominic merged 1 commit intoSep 18, 2026
Merged
Conversation
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`.
This was referenced Sep 18, 2026
This was referenced Sep 18, 2026
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.
Closes #196. Gate G2b on the app-live lane, on top of
05785b0.What changed
The GS1 surface had no time at all: the
08counter is epoch-less (#146), sorecordedAtstayed null and the hero showed only the protocol position. Thisadds 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-timereference: anchor position, that position's own stamp, the covered range, the
written clock reference, the source, and a one-record uncertainty.
deriveCbioIndexTimeAnchorpublishes one only when the session wrote theclock 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 firsthole or counter jump.
CbioGlucoseSessionrecords the written epoch in_writeClock, derives theanchor on every publication, stamps
recordedAtonly for covered positions,puts the anchor in the snapshot metadata, and names it in diagnostics.
cbioClockState:Sensor clock set by this app · latest 10:05 (±1 min)when anchored,Sensor clock unsynced · ordered by sensor index, not by clockwhen not - never a placeholder--, never acounter-derived minute.
RED
Both halves failed before the implementation:
GREEN
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
recordedAtnull(
CbioGlucoseSession clock anchorgroup). The accepted case is asserted tostep 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:
The guard file is not part of this branch; it stays with #193.
UI evidence
Layout captures of the dashboard hero (
flutter testrenders test-font glyphs,so the copy below is read out of the widget tree, not the image):
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.Sensor clock unsynced · ordered by sensor index, not by clock.10:05is03:05Zin the device zone, and the anchored copy is assertedagainst
DateFormat('HH:mm').format(instant.toLocal()), so the localisation iscovered 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.mdpredates the anchor and shows the unsyncedcopy); 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_teston Linux,make test-integrationroot mixing, Apple-silicon preview) are unchanged andpre-existing on this lane.