Repository navigation
fix(widget): show HRV, resting HR and scores for a wearer with no Charge yet - #36
Merged
Merged
Conversation
…rge yet The widget anchor only accepted a day with a Charge, so a Garmin-only wearer still calibrating got "-" in every cell. - Anchor: when no day up to today has a Charge, fall back to the freshest day up to and including today that carries Effort, a night, HRV or resting HR. Same rule in Swift (Repository.widgetAnchor) and Kotlin (widgetAnchorRow), with a Swift-generated oracle pinned in the Kotlin test. - Vitals (iOS widget): HRV and resting HR now resolve the way the Today tiles do, today's row first then lastHrvDay / lastRestingHrDay, via Repository.widgetVitals instead of the Charge-gated anchor. - Diagnostics: one always-on strap-log line when the resolved App Group has no defaults store or no shared container, naming AppGroupIdentifier, ALTAppGroups and the resolved suite. Refs #34 Refs #31
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.
Refs #34
Refs #31
Problem
The widget anchored only on a day with a Charge. For a Garmin-only wearer whose Charge is still calibrating, no day qualifies, so every cell showed "–". HRV and resting HR were read off that same Charge-gated anchor.
Changes
Repository.widgetAnchor/widgetAnchorRowkeep the perf(ui): pose the animating surfaces still in battery saver (#909) ryanbr/noop#911 rule. Only when no day up to today has a Charge do they fall back to the freshest day up to and including today that has Effort, a night, HRV or resting HR (hasWidgetValueon both platforms). A future-dated row is still never picked.Repository.widgetVitalsresolves HRV and resting HR exactly like the Today tiles: today's row first, thenlastHrvDay/lastRestingHrDay(the same functionsTodayViewandLiquidTodayViewcall).WidgetPublishuses it instead of reading the anchor. The Android widget has no HRV or resting-HR cell, so there is nothing to wire there.WidgetSnapshot.appGroupDiagnostic()returns one strap-log line, logged at iOS launch, when the resolved suite has no defaults store, or has one but no shared container (containerURL(forSecurityApplicationGroupIdentifier:)is nil, which is the "silently unshared" case). The line namesAppGroupIdentifier,ALTAppGroupsand the resolved suite. A healthy build logs nothing.Battery (WHOOP/Oura only) and live HR (only while Live or a workout is open) are left as is, per the issue. Charge, Effort and Rest for imported history depend on #31.
Parity oracle
The Swift
resolveToday+widgetAnchor+hasWidgetValuewere lifted verbatim out ofRepository.swiftand compiled withswiftc -O. They ran over 2,058 cases: rows 17/18/19 each absent, empty, or carrying one of Charge / Effort / sleep / HRV / resting HR, plus a future row absent / scored / with Effort, under the daytime keys and the pre-04:00 carve-out keys. That stdout is pasted verbatim intoWidgetAnchorTest.anchorMatchesSwiftOracle, which runs the same enumeration through the Kotlin code. It never selected the future row.Local verification (Actions is disabled on this fork)
xcodebuild … -scheme Strand test -only-testing:StrandTests/WidgetAnchorTests -only-testing:StrandTests/WidgetSnapshotTestsran 30 tests with 0 failures. That covers new tests for no Charge, Charge on an older day, today with Charge (existing), the future-row guard, vitals carry and today-wins, plus the diagnostic line.BUILD SUCCEEDED). This machine lacks the watchOS 26.2 platform the scheme requires for its embedded Watch app. So the build used a scratch spec identical toproject.ymlminus theNOOPWatchembed dependency. The Watch targets are untouched by this PR../gradlew testFullDebugUnitTest --no-build-cache --rerun-taskspassesWidgetAnchorTest(14/14, including the oracle). Of 6,881 tests, 2 failures remain, both inRecoveryDriversTest(expected -0.5 but was -0.4999999999999929). They fail identically on a cleanorigin/maincheckout, so they predate this change.python3 Tools/parity_ratchet.py --base origin/main --offlinereportserrors=0.python3 Tools/doc_comment_lint.pyreports no new detached doc comments.python3 Tools/i18n_audit.py --ci origin/mainis OK. The new log line is diagnostic and not localized, like the other strap-log lines.Not verified
resolveSuiteNameresolves there. The new log line captures it on the next sideloaded launch where the group is not shared.