Fix Today score source badges#778
Conversation
|
Good PR. The migration half — the risky part — is right, and the atomicity claim holds. Verified:
Two notes, neither blocking: The new table rides The CI is green across the Swift packages and the i18n gate, and you built and manually checked the badge in the simulator, so the parts I can't verify here are covered. |
MARKETING_VERSION/versionName move together per the versioning rule; build numbers increment independently (207->208 Apple, 298->299 Android). The staging workflow reads MARKETING_VERSION for its title and asset names, so main has to carry 9.1.1 for the rolling testing-latest release to be labelled as such — the previous 9.1.1 staging build was cut from a commit that never landed on main. This is also the first compile of the app-target changes merged today (#783/#784/#785, #787, #788, #793, #795, #519/#798, #523, #778), which CI does not cover: app-build.yml and android.yml are disabled and only the Swift packages and the i18n gate run on PRs.
What this PR does
This PR fixes the source badge on the Today score card so it identifies the devices and imports that supplied the score inputs instead of always describing where NOOP performed the calculation.
Computed recovery, strain, and sleep-performance scores now persist their input provider in a dedicated local provenance table. The provenance update is committed atomically with the corresponding score update, while directly imported scores continue to resolve their provider from their existing source ID. Legacy computed scores without recorded provenance hide the badge rather than guessing.
The shared provider mapping covers paired device brands and stable import sources, including Whoop, Apple Watch, Health Connect, Oura, Fitbit, Garmin, Mi Band, Polar, and other registered devices. Mixed inputs are deduplicated and limited to two names in the compact badge. Carried Charge values resolve the provider from the exact day that supplied the displayed score.
The PR also restores the badge's intended position, centered on the top border and aligned with the Rest vessel, and applies the same behavior to the Classic Today view, Liquid Today view, and Android.
The new storage is documented and removed alongside its device or scoped user data. No BLE, protocol, or scoring-math behavior was changed.
Type of change
How it was tested
swift testinPackages/WhoopStore: 272 tests passed../gradlew testFullDebugUnitTestfor Android: passed.TodayExplainabilityTests: passed.NOOPiOSDebug configuration without signing for an iPhone 16 Pro simulator.python3 Tools/i18n_audit.py --ci upstream/main: Android and Apple localization checks passed.git diff --check: passed.BugReportTemplateTestsfile-read test hung; the affected Today test suite completed successfully.Checklist
swift testinPackages/<name>)android/(./gradlew testFullDebugUnitTest)StrandDesigntokens — no hardcoded colors, fonts, or spacingdocs/CONTRIBUTING.mdStrand.xcodeproj/) or any secrets/keystoresRelated issues
None.