mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(apple-health): extend HK identifier mapping with iOS-17 + iOS-18 long-tail
Adds 32 HKQuantity / HKCategory identifiers to HK_QUANTITY_TYPE_DEFERRED
so the batch ingest endpoint logs a "deferred, not unknown" signal when
the iOS app passes a sample type HealthLog hasn't surfaced yet. None
currently have a HealthLog MeasurementType counterpart; mapping them
through requires the enum extension to land first (separate wave).
Buckets covered, with iOS version they shipped in:
- Cardiovascular clinical (iOS 16): AFib burden, peripheral perfusion
- Mobility (iOS 14/15): walking steadiness, falls, steadiness event
- Pulmonary clinical (iOS 17): FEV1, FVC, peak expiratory flow,
inhaler usage
- Other quantity types: insulin delivery, UV exposure, electrodermal
activity, blood-alcohol content, legacy Nike fuel
- Heart-rhythm event flags (iOS 9+/17 refresh): low/high heart-rate
events, irregular rhythm, low cardio fitness event
- Audio-exposure event flags + environmental sound reduction
- Behavioural: handwashing, toothbrushing
- Reproductive / fertility / pregnancy: contraceptive, lactation,
pregnancy, pregnancy/progesterone test, sexual activity, sleep
changes, persistent intermenstrual bleeding, prolonged / irregular
/ infrequent menstrual cycles
Tests gain explicit coverage that every long-tail identifier sits in
the deferred set and that no identifier is duplicated.
This commit is contained in:
1 parent
41147bd76a
commit
b4df3ae8cd
2 files changed
+116
No files matched your search
@@ -119,6 +119,69 @@ describe("HK_QUANTITY_TYPE_DEFERRED", () => {
|
||||
}
|
||||
});
|
||||
|
||||
// v1.4.25 W16a — explicit coverage gate for the iOS-17 + iOS-18
|
||||
// long-tail. The brief flagged these as "the iOS app may emit them
|
||||
// when the user has the relevant HealthKit category enabled"; the
|
||||
// deferred set means the batch endpoint treats them as
|
||||
// skipped-but-known rather than unknown-and-dropped.
|
||||
it("covers the iOS-17 + iOS-18 long-tail identifiers", () => {
|
||||
const expectedLongTail = [
|
||||
// Cardiovascular / clinical
|
||||
"HKQuantityTypeIdentifierAtrialFibrillationBurden",
|
||||
"HKQuantityTypeIdentifierPeripheralPerfusionIndex",
|
||||
// Mobility
|
||||
"HKQuantityTypeIdentifierAppleWalkingSteadiness",
|
||||
"HKQuantityTypeIdentifierNumberOfTimesFallen",
|
||||
"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent",
|
||||
// Respiratory / pulmonary
|
||||
"HKQuantityTypeIdentifierForcedExpiratoryVolume1",
|
||||
"HKQuantityTypeIdentifierForcedVitalCapacity",
|
||||
"HKQuantityTypeIdentifierPeakExpiratoryFlowRate",
|
||||
"HKQuantityTypeIdentifierInhalerUsage",
|
||||
// Other quantity identifiers
|
||||
"HKQuantityTypeIdentifierInsulinDelivery",
|
||||
"HKQuantityTypeIdentifierUVExposure",
|
||||
"HKQuantityTypeIdentifierElectrodermalActivity",
|
||||
"HKQuantityTypeIdentifierBloodAlcoholContent",
|
||||
"HKQuantityTypeIdentifierNikeFuel",
|
||||
// Heart-rhythm event flags
|
||||
"HKCategoryTypeIdentifierLowHeartRateEvent",
|
||||
"HKCategoryTypeIdentifierHighHeartRateEvent",
|
||||
"HKCategoryTypeIdentifierIrregularHeartRhythmEvent",
|
||||
"HKCategoryTypeIdentifierLowCardioFitnessEvent",
|
||||
// Audio-exposure events
|
||||
"HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent",
|
||||
"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent",
|
||||
"HKCategoryTypeIdentifierEnvironmentalSoundReduction",
|
||||
// Behavioural / habit
|
||||
"HKCategoryTypeIdentifierHandwashingEvent",
|
||||
"HKCategoryTypeIdentifierToothbrushingEvent",
|
||||
// Reproductive / fertility / pregnancy
|
||||
"HKCategoryTypeIdentifierContraceptive",
|
||||
"HKCategoryTypeIdentifierLactation",
|
||||
"HKCategoryTypeIdentifierPregnancy",
|
||||
"HKCategoryTypeIdentifierPregnancyTestResult",
|
||||
"HKCategoryTypeIdentifierProgesteroneTestResult",
|
||||
"HKCategoryTypeIdentifierSexualActivity",
|
||||
"HKCategoryTypeIdentifierSleepChanges",
|
||||
"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding",
|
||||
"HKCategoryTypeIdentifierProlongedMenstrualPeriods",
|
||||
"HKCategoryTypeIdentifierIrregularMenstrualCycles",
|
||||
"HKCategoryTypeIdentifierInfrequentMenstrualCycles",
|
||||
];
|
||||
for (const id of expectedLongTail) {
|
||||
expect(
|
||||
HK_QUANTITY_TYPE_DEFERRED.has(id),
|
||||
`${id} should be in the deferred set`,
|
||||
).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("does not duplicate any deferred identifier", () => {
|
||||
const ids = Array.from(HK_QUANTITY_TYPE_DEFERRED);
|
||||
expect(new Set(ids).size).toBe(ids.length);
|
||||
});
|
||||
|
||||
it("converts oxygen saturation from 0..1 fraction to 0..100 percent", () => {
|
||||
const mapping =
|
||||
APPLE_HEALTH_TYPE_MAP.HKQuantityTypeIdentifierOxygenSaturation;
|
||||
|
||||
@@ -382,6 +382,59 @@ export const HK_QUANTITY_TYPE_DEFERRED = new Set<string>([
|
||||
// Scored assessments (iOS 18) — v1.5 (PHQ-9 / GAD-7 mapping TBD)
|
||||
"HKScoredAssessmentTypeIdentifierGAD7",
|
||||
"HKScoredAssessmentTypeIdentifierPHQ9",
|
||||
// ── v1.4.25 W16a — iOS-17 + iOS-18 long-tail closure ──
|
||||
// Cardiovascular / clinical (iOS 16+) — no HealthLog counterpart yet;
|
||||
// clinical decision-support territory, defer behind a stricter user
|
||||
// opt-in than the existing Health-share prompt.
|
||||
"HKQuantityTypeIdentifierAtrialFibrillationBurden",
|
||||
"HKQuantityTypeIdentifierPeripheralPerfusionIndex",
|
||||
// Mobility (iOS 15+) — surface as a wellness signal in v1.5 once the
|
||||
// Insights cardio sub-page has room for a steadiness gauge.
|
||||
"HKQuantityTypeIdentifierAppleWalkingSteadiness",
|
||||
"HKQuantityTypeIdentifierNumberOfTimesFallen",
|
||||
"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent",
|
||||
// Respiratory / pulmonary clinical (iOS 17) — pair with FHIR clinical
|
||||
// bucket; no Measurement enum mapping today.
|
||||
"HKQuantityTypeIdentifierForcedExpiratoryVolume1",
|
||||
"HKQuantityTypeIdentifierForcedVitalCapacity",
|
||||
"HKQuantityTypeIdentifierPeakExpiratoryFlowRate",
|
||||
"HKQuantityTypeIdentifierInhalerUsage",
|
||||
// Other quantity identifiers — explicit hold (privacy / not in scope).
|
||||
"HKQuantityTypeIdentifierInsulinDelivery",
|
||||
"HKQuantityTypeIdentifierUVExposure",
|
||||
"HKQuantityTypeIdentifierElectrodermalActivity",
|
||||
"HKQuantityTypeIdentifierBloodAlcoholContent",
|
||||
"HKQuantityTypeIdentifierNikeFuel", // legacy Nike+iPod fitness points
|
||||
// Heart-rhythm event flags (iOS 9+ but watch-detected; iOS 18
|
||||
// refreshed surfaces) — would land as Measurement annotations rather
|
||||
// than rows; defer until the annotation column lands.
|
||||
"HKCategoryTypeIdentifierLowHeartRateEvent",
|
||||
"HKCategoryTypeIdentifierHighHeartRateEvent",
|
||||
"HKCategoryTypeIdentifierIrregularHeartRhythmEvent",
|
||||
"HKCategoryTypeIdentifierLowCardioFitnessEvent",
|
||||
// Audio-exposure events (iOS 13+) — the continuous AUDIO_EXPOSURE_*
|
||||
// quantity identifiers ARE mapped above; these are the
|
||||
// "loud-event-fired" flags that pair with them. Defer until we
|
||||
// surface event chips in the Insights audio sub-page.
|
||||
"HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent",
|
||||
"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent",
|
||||
"HKCategoryTypeIdentifierEnvironmentalSoundReduction",
|
||||
// Behavioural / habit category-types — not in HealthLog scope yet.
|
||||
"HKCategoryTypeIdentifierHandwashingEvent",
|
||||
"HKCategoryTypeIdentifierToothbrushingEvent",
|
||||
// Reproductive / fertility / pregnancy — explicit privacy hold
|
||||
// (matches the menstrual-flow stance already encoded above).
|
||||
"HKCategoryTypeIdentifierContraceptive",
|
||||
"HKCategoryTypeIdentifierLactation",
|
||||
"HKCategoryTypeIdentifierPregnancy",
|
||||
"HKCategoryTypeIdentifierPregnancyTestResult",
|
||||
"HKCategoryTypeIdentifierProgesteroneTestResult",
|
||||
"HKCategoryTypeIdentifierSexualActivity",
|
||||
"HKCategoryTypeIdentifierSleepChanges",
|
||||
"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding",
|
||||
"HKCategoryTypeIdentifierProlongedMenstrualPeriods",
|
||||
"HKCategoryTypeIdentifierIrregularMenstrualCycles",
|
||||
"HKCategoryTypeIdentifierInfrequentMenstrualCycles",
|
||||
] as const);
|
||||
|
||||
/** Input to `mapAppleHealthEntry()`. */
|
||||
|
||||
Reference in new issue
Block a user