fix(backend): convert Health Connect blood glucose from mmol/L to mg/dL#1123
fix(backend): convert Health Connect blood glucose from mmol/L to mg/dL#1123knowald wants to merge 3 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughDetects incoming blood_glucose records whose record.unit starts with "mmol" (case-insensitive) and multiplies their numeric value by 18.0182 to store mg/dL; tests updated to cover Health Connect conversion and HealthKit pass-through. ChangesBlood Glucose Unit Conversion
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
backend/app/services/apple/healthkit/import_service.py (1)
140-143: ⚡ Quick winMove conversion factor to module-level constant.
The
Decimal("18.0182")conversion factor is allocated on every call to_build_statistic_bundles, which processes all incoming records. Based on learnings, constant data structures should be defined at module or class level to avoid repetitive allocations in hot paths.♻️ Suggested refactor
At module level (e.g., after imports, around line 40):
+# Unit conversion constants +MMOL_L_TO_MG_DL = Decimal("18.0182") # Blood glucose conversion factor + class ImportService:Then in the conversion logic:
# Health Connect reports blood glucose in mmol/L; the series unit is mg/dL. if series_type == SeriesType.blood_glucose and (rjson.unit or "").lower().startswith("mmol"): - value = value * Decimal("18.0182") + value = value * MMOL_L_TO_MG_DL🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/services/apple/healthkit/import_service.py` around lines 140 - 143, Move the hard-coded conversion factor Decimal("18.0182") to a module-level constant and use that constant inside the _build_statistic_bundles function: define a descriptive constant (e.g., BLOOD_GLUCOSE_MGDL_PER_MMOLL) near the top of the module and replace the inline Decimal("18.0182") in the SeriesType.blood_glucose conversion branch (the block that checks (rjson.unit or "").lower().startswith("mmol")) to reference the new constant so the Decimal is allocated once at import time rather than on every call.Source: Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/tests/integrations/test_apple_sdk_import.py`:
- Around line 376-403: The test payload in
test_healthkit_blood_glucose_stored_unchanged is missing the "source" object
which causes import_service._build_statistic_bundles to call
extract_device_info(rjson.source) with None; update the test record to include a
minimal "source" object (matching other tests) such as {"name": "...",
"bundleIdentifier": "..."} so extract_device_info receives a populated source
and the test no longer fails due to a missing attribute.
---
Nitpick comments:
In `@backend/app/services/apple/healthkit/import_service.py`:
- Around line 140-143: Move the hard-coded conversion factor Decimal("18.0182")
to a module-level constant and use that constant inside the
_build_statistic_bundles function: define a descriptive constant (e.g.,
BLOOD_GLUCOSE_MGDL_PER_MMOLL) near the top of the module and replace the inline
Decimal("18.0182") in the SeriesType.blood_glucose conversion branch (the block
that checks (rjson.unit or "").lower().startswith("mmol")) to reference the new
constant so the Decimal is allocated once at import time rather than on every
call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 86bcf0d5-40d1-4ab9-ac46-2e83aa0c74dd
📒 Files selected for processing (2)
backend/app/services/apple/healthkit/import_service.pybackend/tests/integrations/test_apple_sdk_import.py
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/app/services/apple/healthkit/import_service.py`:
- Line 42: Add an explicit type annotation for the module-level constant
MMOL_L_TO_MG_DL: declare it as a Decimal (e.g., MMOL_L_TO_MG_DL: Decimal =
Decimal("18.0182")) so static type checkers and IDEs recognize its type; update
the import if Decimal is not already imported and ensure the constant remains
unchanged otherwise.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0b0447ea-ddf4-46a7-80c0-69f88e5b90f0
📒 Files selected for processing (2)
backend/app/services/apple/healthkit/import_service.pybackend/tests/integrations/test_apple_sdk_import.py
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/tests/integrations/test_apple_sdk_import.py
Description
Blood glucose values synced from Android via Health Connect arrive in mmol/L (Health Connect's canonical unit for
BloodGlucoseRecord), but_build_statistic_bundlesstored them verbatim while theblood_glucoseseries unit ismg_dl. A 110 mg/dL reading was stored as 6.111.The conversion is gated on the unit string the SDK already sends (
unitstarts withmmol, case-insensitive), so SDK paths that send mg/dL (the iOS SDK reads glucose with a fixed mg/dL HKUnit) and any other source already sending mg/dL are unaffected. The factor lives in a module constantMMOL_L_TO_MG_DL = Decimal("18.0182").Tests live in
TestSDKImportUnitConversionnext to the existing body-fat/height conversion tests: parametrized overmmol/L/MMOL/L(converted, exactDecimal("110.1092202")) andNone/""(stored unchanged), plus a HealthKit mg/dL passthrough test.Resolves #1119
Notes
apple_xml/xml_service.py) has the same class of bug for users whose Health app displays glucose in mmol/L (Apple writes the export in the display unit, e.g.unit="mmol<180.15588...>/L"); that path never reads the record's unit attribute. Filed separately so it can be fixed for all affected series types at once rather than special-cased here._normalize_unithelper (it then needs the record'sunitpassed in). For feat(backend): centralized unit conversion service (concept for #424) #1120: its registry needs a(blood_glucose, mmol/L)entry plus unit-token normalization, since it currently skips samples with unrecognized units.store_raw_payloadkeeps the original records incl. theunitfield), matching onexternal_id. Happy to add that migration on request, here or as a follow-up.Checklist
General
docs/(or no docs update needed)Backend Changes
You have to be in
backenddirectory to make it work:uv run pre-commit run --all-filespasses (ruff + ty pass; prettier hook needs frontendnode_modules, no frontend files touched)Testing Instructions
Steps to test:
cd backend && uv run pytest tests/integrations/test_apple_sdk_import.pyBLOOD_GLUCOSErecord withunit: "mmol/L"and inspect the stored sample.Expected behavior:
Stored
blood_glucosevalue is in mg/dL (6.111 mmol/L -> 110.1092202); HealthKit mg/dL values unchanged.Summary by CodeRabbit
Release Notes
New Features
Tests