Strap log: surface WHERE offloaded rows landed + WHY (stale-RTC "missed sleep", #67)#69
Merged
Merged
Conversation
…le-RTC "missed sleep" (#67) A reset/stale strap RTC banks last night's sleep with a years-old timestamp, so the offload files it far in the past — off the recent timeline, where it reads as "missed sleep". The log showed the strap was stale and that rows persisted, but NOT where those rows landed or what clock reference decoded them, so the misdating was invisible. Logging only — no BLE/offload behaviour change: - Backfiller: new "Backfill: rows landed on <date(s)>" session line, plus the effective clock state — "IDENTITY fallback (GET_CLOCK never correlated) - stale-record correction OFF", "strap clock Nd behind wall - correction engaged", or "clock ref in sync". The dates are the ACTUAL post-correction landing days (the same night-keys the persist tally builds), so a night that landed in 2024 is self-evident. Captures the decode ref on the first chunk; reset in begin(). - DebugDataDiagnostics: the existing "Strap clock: Nd behind wall" line now notes recent sleep may be filed ~Nd in the past (#67), not just that the alarm is unreliable. - Tests: cover the new formatter — identity-fallback past-date signature, correlated-stale "correction engaged", in-sync, multi-night UTC range, and the no-em-dash convention shared with the sibling strap-log lines. Pairs with the root-cause investigation on #67: on a reset-RTC strap the offload falls back to an identity clock ref (Backfiller.swift), which zeroes the offset FIX #72's correctedWall needs, so stale records are stored verbatim. This makes that failure mode visible before touching the BLE clock handshake.
tanarchytan
pushed a commit
to tanarchytan/noop
that referenced
this pull request
Jul 8, 2026
The Live Body Console derives every status from activeConnection (= live.connected && live.bonded). `bonded` carries WHOOP encrypted-bond semantics and is deliberately never set by the Oura path (ryanbr#69), so a connected, authenticated, streaming ring fell through every WHOOP branch to "Radio connected, stream not yet trusted." — even while HR was live. Add a display-only `ringStreaming` predicate (live.connected && live.streamingLiveHR) and route the status layer through it: mode detail, connection pill, mode badge, mode color, and the Heart rate / Connection signal-trust tiles now read a ring stream as an active, trusted stream. activeConnection itself is untouched, so bond-only feature gates (buzz, alarm, HRV snapshot, encrypted control) still correctly key off the WHOOP bond. Wear/Worn stats stay gated on activeConnection to avoid a false "On wrist" until the ring's wear signal is confirmed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tanarchytan
pushed a commit
to tanarchytan/noop
that referenced
this pull request
Jul 8, 2026
…ecode", not "never" (ryanbr#67 follow-up) The identity-fallback diagnostic line (ryanbr#69) asserted "(GET_CLOCK never correlated)", but sessionUsedIdentityRef is captured on the FIRST chunk. In the normal flow the correlation lands before chunk 1, and in the reset-RTC case it never lands — both fine. But on a slow link GET_CLOCK can reply late: chunk 1 decodes on the identity fallback, later chunks on the real ref, so "never" is false. First-chunk capture is still the right choice (it flags that the early rows landed misdated), only the absolute word overreached — reword to "(no clock correlation at decode)", true regardless of any later reply. Doc comment + test assertion updated to match.
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.
Diagnostic instrumentation for #67 ("Missed sleep"). Logging only — no BLE/offload behaviour change.
The bug it exposes
Jenssaibe's strap has a reset RTC (
Strap clock: 835d behind wall, newest banked record2024-03-24). Last night's sleep was banked by the strap with that stale clock, so the offload persisted it under ~2024 — off the recent timeline, so it reads as "missed sleep" (Analytics funnels: no sleep session in the last 14 days).The root cause: on a reset-RTC strap the offload falls back to an identity clock ref (
Backfiller.swift:357,clockRef ?? ClockRef(device: now, wall: now)), which zeroes the offset that FIX #72'scorrectedWallneeds to re-base stale timestamps — so the 2024 stamps are stored verbatim. The log gave no way to see this: it showed the strap was stale and that rows persisted, but not where they landed or what ref decoded them.What this adds
Backfiller— a new session line after the persist summary:Backfill: rows landed on 2024-03-24 · clock ref: IDENTITY fallback (GET_CLOCK never correlated) - stale-record correction OFFThe dates are the actual post-correction landing days (the same night-keys the tally already builds), so a night filed in the past is self-evident. Also emits
strap clock Nd behind wall - correction engaged(stale-but-correlated) orclock ref in sync. Captures the decode ref on the first chunk; reset inbegin().DebugDataDiagnostics— the existingStrap clock: Nd behind wallline now flags that recent sleep may be filed ~Nd in the past (Missed sleep #67), not just that the alarm is unreliable.en_US_POSIXlocale so non-Gregorian device calendars don't corrupt the year), and the no-em-dash convention shared withnoCursorLine/futureRtcLine.Scope
This is deliberately just the log. The actual fix (preserve the stale offset for offload re-basing — either capture the pre-SET_CLOCK correlation or derive the offset from
GET_DATA_RANGE) touches the BLE clock handshake and needs on-strap validation; it's tracked separately on #67. One instrumented log from Jenssaibe confirms identity-fallback vs post-set-zeroed before we change any BLE behaviour.Files:
Strand/Collect/Backfiller.swift,Strand/BLE/BLEManager.swift,Strand/System/DebugDataDiagnostics.swift,StrandTests/BackfillerSessionTallyTests.swift.