Skip to content

Vital detail screens: readings table below the chart + cross-strap provenance fix - #190

Merged
ryanbr merged 3 commits into
ryanbr:mainfrom
TheBoroer:feat/vital-readings-table
Jul 12, 2026
Merged

ryanbr merged 3 commits into
ryanbr:mainfrom
TheBoroer:feat/vital-readings-table

Conversation

@TheBoroer

@TheBoroer TheBoroer commented Jul 10, 2026 •

Copy link
Copy Markdown

What this PR does

Two things, one per commit:

1. Vital detail screens: readings table below the chart

Every vital detail screen (Steps, HR, SpO2, Skin Temp, Vitality, Calories, …) now shows a scrollable readings table below the chart — one row per day with the formatted value, unit, and the source/device that reading actually came from. Previously the detail screens were chart-only; there was no way to inspect individual readings or see which source contributed a given day.

  • Android: HealthScreen.kt — VitalDetailModel gains readings: List<VitalReading> (day, value, source); each metric key maps its resolved series into rows. steps_est reads through resolvedSeries(...) with the strap-anchored resolver (strapDeviceId = vm.activeStrapId), so rows carry per-day provenance and respect the active strap after a swap.
  • iOS twin: MetricExplorerView.swift — same table, same per-row source labels, mirrored layout so both platforms stay in lockstep.
  • Source labels in rows resolve through the same provenance mapping as the Today badges (below) — a -noop row shows "On-device", not the raw device id.

2. Cross-strap provenance fix ("On-device" instead of raw device id)

Scores banked under a previous strap id showed the raw device id in the Today provenance badge instead of "On-device". provenanceDisplayLabel compared against the current strap's exact "$deviceId-noop", so after a strap swap (e.g. WHOOP 4.0 → 5.0) any -noop-suffixed source from the old strap fell through to the verbatim fallback. Both twins (Kotlin resolver in TodayScreen.kt and the Swift twin) now suffix-match -noop and resolve to "On-device".

Note on the TEST_HOST / test-infra repair: an earlier revision of this branch also fixed project.yml's TEST_HOST/BUNDLE_LOADER, which still pointed at NOOP.app after the 8.5.2 rename to "NOOP Staging". That repair has since landed upstream independently (#241). After merging main, this PR no longer touches project.yml: the fix is already on main, so this PR is scoped to the two features above.

Screenshot

Resting Heart Rate detail screen on-device — readings table below the chart, one row per day with per-row provenance (mix of "Whoop" and "On-device" labels resolving correctly):

Resting Heart Rate detail screen with readings table showing per-row Whoop and On-device source labels

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation
  • CI / tooling

How it was tested

Not on the BLE path — UI + resolution only. Both features pinned in twin suites so the platforms can't drift:

  • Android: VitalReadingsTableTest.kt (table rows, per-row source labels, strap-anchored steps series) + TodayExplainabilityTest.kt (cross-strap sibling cases) — ./gradlew testFullDebugUnitTest passes
  • iOS: VitalReadingsTableTests.swift + TodayExplainabilityTests.swift — StrandTests run under the upstream TEST_HOST fix (Fix sleep-merge richness precedence + sourceCandidates canonical-import order (iOS twin of #240) #241); new suites pass
  • Re-verified after merging upstream main (strap-anchored resolvedSeries signature): :app:testFullDebugUnitTest --tests '*VitalReadingsTableTest' — BUILD SUCCESSFUL

Note: testScoreState_carryWithinCap_isFreshLastNight and testScoreState_staleCarry_relabelsLatestSleep fail, but this is pre-existing latent breakage (LocalizedStringKey formatting) unmasked once StrandTests can run at all (the TEST_HOST fix, now upstream via #241) — unrelated to this diff. Follow-up PR incoming.

Checklist

  • Swift package tests pass for any package I touched (swift test in Packages/<name>)
  • Android unit tests pass if I touched android/ (./gradlew testFullDebugUnitTest)
  • No new build warnings introduced
  • UI changes use only StrandDesign tokens — no hardcoded colors, fonts, or spacing
  • No hardcoded hex frame bytes; protocol facts live in the schema / decoders
  • Follows the conventions in docs/CONTRIBUTING.md
  • I did not commit generated output (Strand.xcodeproj/) or any secrets/keystores

Related issues

@TheBoroer
TheBoroer force-pushed the feat/vital-readings-table branch 2 times, most recently from 194cca0 to 2ffed5e Compare July 10, 2026 05:11
@TheBoroer
TheBoroer marked this pull request as ready for review July 10, 2026 05:11
@TheBoroer TheBoroer changed the title fix: resolve cross-strap -noop provenance to On-device + repair StrandTests TEST_HOST Vital detail screens: readings table below the chart + cross-strap provenance fix (task #8) Jul 10, 2026
@TheBoroer TheBoroer changed the title Vital detail screens: readings table below the chart + cross-strap provenance fix (task #8) Vital detail screens: readings table below the chart + cross-strap provenance fix Jul 10, 2026
@TheBoroer
TheBoroer force-pushed the feat/vital-readings-table branch from 2ffed5e to e0519bf Compare July 10, 2026 05:19
@ryanbr
ryanbr merged commit f659f92 into ryanbr:main Jul 12, 2026
DX23876 pushed a commit to DX23876/noop that referenced this pull request Jul 22, 2026
…ovenance fix (ryanbr#190)

* Vital detail screens: readings table below the chart

* fix: resolve cross-strap -noop siblings to On-device + repair StrandTests TEST_HOST
simoncad7 pushed a commit to simoncad7/noop that referenced this pull request Aug 17, 2026
…ovenance fix (ryanbr#190)

* Vital detail screens: readings table below the chart

* fix: resolve cross-strap -noop siblings to On-device + repair StrandTests TEST_HOST
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.

2 participants