Repository navigation
Fitness Age / Vitality permanently "not ready" on live-BLE straps (#349) - #359
Merged
Merged
Conversation
… hardcoded id Fitness Age / Vitality / Body Age stayed permanently "not ready" (tiles showed "No Data") for anyone paired over live Bluetooth (#349). IntelligenceEngine writes the weekly computed scores under "<activeStrapId>-noop", but HealthScreen (COMPUTED_SOURCE) and the Today "Your cards" tiles read a hardcoded "my-whoop-noop". Import installs match by luck (activeStrapId == "my-whoop"); a live-BLE strap writes "whoop-<mac>-noop", so every read missed it — and the refresh toast lied ("Fitness Age updated." while the card never re-read the source it had just written). Read the computed metricSeries through the active-strap UNION instead (WhoopRepository.metricSeriesComputedUnion): the active strap's "-noop" sibling + the canonical "my-whoop-noop", deduped per day with the active strap winning — the same resolver every other read already uses, and the layering iOS's Repository.exploreSeries already does (iOS was unaffected). Import users collapse to the single canonical id, byte-identical to before. - HealthScreen: 6 read sites (fitness_age / vo2max_est / vitality / body_age + the two vital-detail tables). - TodayScreen: the pinned Fitness age / Vitality cards had the same hardcoded read — fixed too (the issue only cited HealthScreen). - New pure companion mergeComputedSeriesUnion + ResolverUnionTest coverage. Android-only; iOS already resolves the computed union.
ryanbr
added a commit
that referenced
this pull request
Jul 14, 2026
…s no longer export an empty zip (#458) (#468) Android (the reported bug, verified at HEAD): exportZip defaulted deviceId="my-whoop", but a live-BLE install's engine banks computed scores under "<strapId>-noop" - every read hit ids owning zero rows and the toast said 'Exported 0 days, 0 sleeps, 0 journal entries' while the app displayed months of history. It survived the #359 sweep because that grep targeted the hardcoded "my-whoop-noop" string, not DEFAULT PARAMETERS. - The default is REMOVED (compiler-enforced decision at every call site); Settings threads the registry's active strap id. - Every read resolves through the #814 active-union helpers: daysMerged/sleepSessionsMerged already did once handed the active id; workouts move to workoutsUnion/detectedWorkoutsUnion; the imported-days set, journal, cycles metricSeries and the sidecar union inline with active-first dedup on each row's natural key ((day), (day, question), (startTs, sport)). - New reads are a strict SUPERSET of the old ones: nothing that previously exported can be lost, and a single-canonical install collapses to one id per side, byte-identical to before. Apple (mirror-image of the same class): CsvExport read repo.deviceId (the ACTIVE id, #814) plus its -noop sibling only, so a strap remove+re-add orphaned the canonical "my-whoop" rows (prior CSV import + canonical engine history) from the export. Reads now union importedReadIds/computedReadIds (de-privatized, same module) with the same active-first natural-key dedups; workoutSource takes the computed-id LIST since a detected row can carry either union id. NOT in this PR (separate concern): the sibling audit of the 7 remaining '= "my-whoop"' default parameters on WhoopRepository methods. Verification: Android compileFullDebugKotlin + testFullDebugUnitTest = 2709 tests, 0 failures (union resolvers pinned by ResolverUnionTest; no Robolectric/in-memory Room in the JVM suite for an exportZip repro). Swift is app-target: on-demand app-build gates the merge. Reporter (MasterSMax12) has offered on-device verification on the live-BLE 4.0 setup that confirmed #349/#359.
DX23876
pushed a commit
to DX23876/noop
that referenced
this pull request
Jul 22, 2026
… hardcoded id (ryanbr#359) Fitness Age / Vitality / Body Age stayed permanently "not ready" (tiles showed "No Data") for anyone paired over live Bluetooth (ryanbr#349). IntelligenceEngine writes the weekly computed scores under "<activeStrapId>-noop", but HealthScreen (COMPUTED_SOURCE) and the Today "Your cards" tiles read a hardcoded "my-whoop-noop". Import installs match by luck (activeStrapId == "my-whoop"); a live-BLE strap writes "whoop-<mac>-noop", so every read missed it — and the refresh toast lied ("Fitness Age updated." while the card never re-read the source it had just written). Read the computed metricSeries through the active-strap UNION instead (WhoopRepository.metricSeriesComputedUnion): the active strap's "-noop" sibling + the canonical "my-whoop-noop", deduped per day with the active strap winning — the same resolver every other read already uses, and the layering iOS's Repository.exploreSeries already does (iOS was unaffected). Import users collapse to the single canonical id, byte-identical to before. - HealthScreen: 6 read sites (fitness_age / vo2max_est / vitality / body_age + the two vital-detail tables). - TodayScreen: the pinned Fitness age / Vitality cards had the same hardcoded read — fixed too (the issue only cited HealthScreen). - New pure companion mergeComputedSeriesUnion + ResolverUnionTest coverage. Android-only; iOS already resolves the computed union.
DX23876
pushed a commit
to DX23876/noop
that referenced
this pull request
Jul 22, 2026
…s no longer export an empty zip (ryanbr#458) (ryanbr#468) Android (the reported bug, verified at HEAD): exportZip defaulted deviceId="my-whoop", but a live-BLE install's engine banks computed scores under "<strapId>-noop" - every read hit ids owning zero rows and the toast said 'Exported 0 days, 0 sleeps, 0 journal entries' while the app displayed months of history. It survived the ryanbr#359 sweep because that grep targeted the hardcoded "my-whoop-noop" string, not DEFAULT PARAMETERS. - The default is REMOVED (compiler-enforced decision at every call site); Settings threads the registry's active strap id. - Every read resolves through the ryanbr#814 active-union helpers: daysMerged/sleepSessionsMerged already did once handed the active id; workouts move to workoutsUnion/detectedWorkoutsUnion; the imported-days set, journal, cycles metricSeries and the sidecar union inline with active-first dedup on each row's natural key ((day), (day, question), (startTs, sport)). - New reads are a strict SUPERSET of the old ones: nothing that previously exported can be lost, and a single-canonical install collapses to one id per side, byte-identical to before. Apple (mirror-image of the same class): CsvExport read repo.deviceId (the ACTIVE id, ryanbr#814) plus its -noop sibling only, so a strap remove+re-add orphaned the canonical "my-whoop" rows (prior CSV import + canonical engine history) from the export. Reads now union importedReadIds/computedReadIds (de-privatized, same module) with the same active-first natural-key dedups; workoutSource takes the computed-id LIST since a detected row can carry either union id. NOT in this PR (separate concern): the sibling audit of the 7 remaining '= "my-whoop"' default parameters on WhoopRepository methods. Verification: Android compileFullDebugKotlin + testFullDebugUnitTest = 2709 tests, 0 failures (union resolvers pinned by ResolverUnionTest; no Robolectric/in-memory Room in the JVM suite for an exportZip repro). Swift is app-target: on-demand app-build gates the merge. Reporter (MasterSMax12) has offered on-device verification on the live-BLE 4.0 setup that confirmed ryanbr#349/ryanbr#359.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
… hardcoded id (ryanbr#359) Fitness Age / Vitality / Body Age stayed permanently "not ready" (tiles showed "No Data") for anyone paired over live Bluetooth (ryanbr#349). IntelligenceEngine writes the weekly computed scores under "<activeStrapId>-noop", but HealthScreen (COMPUTED_SOURCE) and the Today "Your cards" tiles read a hardcoded "my-whoop-noop". Import installs match by luck (activeStrapId == "my-whoop"); a live-BLE strap writes "whoop-<mac>-noop", so every read missed it — and the refresh toast lied ("Fitness Age updated." while the card never re-read the source it had just written). Read the computed metricSeries through the active-strap UNION instead (WhoopRepository.metricSeriesComputedUnion): the active strap's "-noop" sibling + the canonical "my-whoop-noop", deduped per day with the active strap winning — the same resolver every other read already uses, and the layering iOS's Repository.exploreSeries already does (iOS was unaffected). Import users collapse to the single canonical id, byte-identical to before. - HealthScreen: 6 read sites (fitness_age / vo2max_est / vitality / body_age + the two vital-detail tables). - TodayScreen: the pinned Fitness age / Vitality cards had the same hardcoded read — fixed too (the issue only cited HealthScreen). - New pure companion mergeComputedSeriesUnion + ResolverUnionTest coverage. Android-only; iOS already resolves the computed union.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…s no longer export an empty zip (ryanbr#458) (ryanbr#468) Android (the reported bug, verified at HEAD): exportZip defaulted deviceId="my-whoop", but a live-BLE install's engine banks computed scores under "<strapId>-noop" - every read hit ids owning zero rows and the toast said 'Exported 0 days, 0 sleeps, 0 journal entries' while the app displayed months of history. It survived the ryanbr#359 sweep because that grep targeted the hardcoded "my-whoop-noop" string, not DEFAULT PARAMETERS. - The default is REMOVED (compiler-enforced decision at every call site); Settings threads the registry's active strap id. - Every read resolves through the ryanbr#814 active-union helpers: daysMerged/sleepSessionsMerged already did once handed the active id; workouts move to workoutsUnion/detectedWorkoutsUnion; the imported-days set, journal, cycles metricSeries and the sidecar union inline with active-first dedup on each row's natural key ((day), (day, question), (startTs, sport)). - New reads are a strict SUPERSET of the old ones: nothing that previously exported can be lost, and a single-canonical install collapses to one id per side, byte-identical to before. Apple (mirror-image of the same class): CsvExport read repo.deviceId (the ACTIVE id, ryanbr#814) plus its -noop sibling only, so a strap remove+re-add orphaned the canonical "my-whoop" rows (prior CSV import + canonical engine history) from the export. Reads now union importedReadIds/computedReadIds (de-privatized, same module) with the same active-first natural-key dedups; workoutSource takes the computed-id LIST since a detected row can carry either union id. NOT in this PR (separate concern): the sibling audit of the 7 remaining '= "my-whoop"' default parameters on WhoopRepository methods. Verification: Android compileFullDebugKotlin + testFullDebugUnitTest = 2709 tests, 0 failures (union resolvers pinned by ResolverUnionTest; no Robolectric/in-memory Room in the JVM suite for an exportZip repro). Swift is app-target: on-demand app-build gates the merge. Reporter (MasterSMax12) has offered on-device verification on the live-BLE 4.0 setup that confirmed ryanbr#349/ryanbr#359.
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.
Fixes #349.
The bug
Fitness Age / Vitality / Body Age stay permanently on the "not ready" checklist (every item green), and the Vitality/Body Age tile shows No Data, for anyone paired over live Bluetooth. Tapping refresh even toasts "Fitness Age updated." — because
recomputeFitnessAgeOnlygenuinely did write; the screen just never reads the source it wrote to.Excellent diagnosis in the issue (DB proof + exact lines), confirmed against the code:
IntelligenceEnginewrites the weekly computed scores under"<activeStrapId>-noop".HealthScreen(COMPUTED_SOURCE) and the Today "Your cards" tiles read a hardcoded"my-whoop-noop".activeStrapId == "my-whoop"). A live-BLE strap's registry id is"whoop-<mac>", so the engine writes"whoop-<mac>-noop"and every read misses it.The fix
Read the computed series through the active-strap union — the active strap's
"-noop"sibling + the canonical"my-whoop-noop", deduped per day with the active strap winning:This is the same resolver (
computedSourceIds) every other read already uses, and mirrors the layering iOS'sRepository.exploreSeriesalready does — so iOS was never affected; this brings Android back in line. Import users (activeStrapId == "my-whoop") collapse to the single canonical id, byte-identical to before.Scope — the report cited HealthScreen; the Today card had it too
Grepping the whole bug class (hardcoded
"my-whoop-noop"reads) surfaced the same bug in the pinned Today cards, so both are fixed:fitness_age/vo2max_est/vitality/body_age+ the two vital-detail tables). Removed the now-deadCOMPUTED_SOURCEconstant.FusionTypes.NOOP_COMPUTEDis an arbitration label, not a read source;AndroidDiagnosticsalready unions — both left as-is.)Verification
mergeComputedSeriesUnion+ResolverUnionTestcases (active strap wins per shared day, canonical fills gaps, single-source passthrough).compileFullDebugKotlinclean; fulltestFullDebugUnitTestsuite green.A live-BLE 4.0 reporter should confirm on-device, but the resolver + tests prove the id now resolves.