feat: add mobility context for instrument applicability - #3
Merged
Conversation
Many Apple Health-derived metrics are produced by step and gait detection. When that detection cannot run the host does not receive a low value, it receives a value that does not describe the person: wearables have been reported as recording zero steps for someone walking with a walker. Scoring that as inactivity is a measurement error, and the calculator previously had no way to tell it apart from real data. Adds `FitnessAgeMobilityContext` and `FitnessAgeProfile.mobilityContext` with three values: `ambulatory` (unaided or cane), `assistedAmbulation` (walker or crutches) and `nonAmbulatory` (wheeled). Metrics the declared context cannot observe are unioned with `disabledMetricIds` before scoring, so they follow the documented disabled-metric path: the field is cleared and each domain divides by the observed local weights that remain. `FitnessAgeProfile.effectiveDisabledMetricIds` exposes that union. Boundaries follow the measurement literature rather than a diagnosis list. Step detection breaks under weight-bearing walking aids, while cane use stays within reported measurement noise, so cane users remain `ambulatory`. Standing is the only instrument that separates the two non-default contexts. Conditions where the instrument works but the expected value is debated are documented as out of scope, because changing a target there would be a scoring change presented as an applicability change. This is a measurement-applicability input, not a diagnosis or clinical classification. No threshold, curve, local weight, domain weight, or confidence rule changed. No result drift for existing callers: `mobilityContext` defaults to `ambulatory`, which removes nothing, and encoded profiles that omit the field decode to `ambulatory`. Golden fixtures are unchanged. Signed-off-by: Stefano Novelli <murdercode@gmail.com>
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.
Problem
Many Apple Health-derived metrics are produced by step and gait detection. When that detection cannot run, the host does not receive a low value — it receives a value that does not describe the person. Wearables have been reported as recording zero steps for someone walking with a walker. The calculator had no way to tell that apart from genuine inactivity, so a wheelchair user was scored on steps they cannot take.
What this adds
FitnessAgeMobilityContextonFitnessAgeProfile, declaring which movement instruments can be observed:ambulatory(default)assistedAmbulationnonAmbulatorystand_hoursInapplicable IDs are unioned with
disabledMetricIdsbefore scoring, so removal follows the already-documented path: the field is cleared, the domain divides by the observed local weights that remain, and data quality averages over observed components only.This is a measurement-applicability input, not a diagnosis or clinical classification. No threshold, curve, local weight, domain weight, or confidence rule changed.
Where the boundaries come from
Boundaries follow measurement literature rather than a diagnosis list:
ambulatory.activeEnergyandexerciseTimestay the applicable instruments instead of being replaced — Bull et al., BJSM 2020.Every anchor is in the methodology source table.
Deliberately out of scope
Conditions where the instrument works but the expected value is debated (fatigue-related, mental-health-related). Step count is measurable there; changing its target without an evidence anchor would be a scoring change presented as an applicability change. That needs an Algorithm RFC.
Compatibility
No result drift.
mobilityContextdefaults toambulatory, which removes nothing; encoded profiles omitting the field decode toambulatory. Golden fixtures unchanged.Verification
41 tests pass, 9 new. Two carry the weight:
inapplicableInstrumentsAreRemovedRatherThanScoredAsZero— a context-driven removal produces byte-identical results to an input that never supplied those metrics. That is the invariant that makes this correct rather than charitable.