Files
healthlog/docs/tasks/items/apple-export-import.md
T
av d33f37249c docs: документация переведена на канон av-dev-pm 3
- роадмап отвечает «что умеет и чего не умеет»: PLAN.md → ROADMAP.md, четыре
  канонические секции, достигнутые звенья строками в «Готово», цели
  переформулированы возможностями приложения
- задачи: род работы и «Затрагивает» набору спринта, 34 заголовка в форму
  действия, «Завершение» целей перечнями со ссылкой из каждой задачи
- вычитка проходами task-form и doc-wording, починены протухшие факты в README,
  паспорте и review.md
2026-08-04 20:48:30 +03:00

5.8 KiB
Raw Blame History

Импортировать родной экспорт Apple Health

  • Секция: Ядро
  • Зачем: Слой sample пуст: полная история и точные сэмплы лежат в zip-архиве и никуда не едут
  • Теги: goal:native-export-import

Слой sample пуст: настоящих сэмплов HealthKit в потоке нет вовсе — HAE отдаёт посекундную развёртку, а не измерения (находка 34). Полная история и точные сэмплы лежат в zip родного экспорта.

Это же основание для устаревания нижнего слоя и единственный способ поднять историю глубже недели: дыра старше недели проходами синхронизации не чинится.

Формат разобран на девяти экспортах за 5.5 лет (находки 42–45), гадать не придётся:

  • версии 11 → 13 → 14, на 14 стоит больше года; за всё время ни один тип записи не исчез, только добавлялись. Значит незнакомый тип — новый тип, а не сломанный парсер: падать на нём нельзя;
  • Correlation — обёртка из двух записей, ею приезжает давление. Появилась только в 2026 году. Парсер по одним <Record> разберёт давление как две несвязанные метрики и потеряет их парность;
  • WorkoutStatistics внутри тренировки — с 2024 года;
  • имя файла локализовано: экспорт.xml, не export.xml — так во всех девяти архивах;
  • DTD расходится с данными (в v11 у <Me> на атрибут больше объявленного) — валидировать документ его же DTD нельзя;
  • объём: 1.6 ГБ XML и 3.6 млн записей в свежем экспорте — только потоковый разбор, документ целиком в память не влезет.

Шаги:

  • потоковый разбор экспорт.xml в слой sample, включая Correlation;
  • HeartRateVariabilityMetadataList с InstantaneousBeatsPerMinute — это тот же heartbeatSeries, что в HAE (находка 39), 1.25 млн ударов;
  • маршруты GPX и ЭКГ отдельными файлами — их в XML нет;
  • заливка кусками по годам, идемпотентно: повторный импорт того же архива не должен ничего менять;
  • export_cda.xml игнорируем — это клинический формат тех же данных.

Двигает строку «Завершения» цели: «Слой sample наполнен историей с 2019 года, повторный импорт того же экспорта ничего не меняет».

Импорт выставляет пометку покрытия

Импорт — единственный, кто знает, какой период каким слоем обеспечен, поэтому пометку ставит он, а не отдельный проход задним числом.

Форма пометки решена в lower-layer-expiry: одна строка на диапазонметрика + слой + период + «покрыто проверенным экспортом». Провенанс на каждую точку не заводим: вопрос диапазонный, а поле у точки стоило бы того же объёма, который устаревание нижнего слоя и приходит экономить.

Два условия, оба из ограничителей той задачи:

  • пометка ставится по проверенному импорту, а не по факту запуска команды. Проверка та же, что уже названа в приёмке: непрерывность по дням и сходимость сумм с часовым слоем HAE на пересечении периодов. Не сошлось — пометки нет, и это не отказ импорта, а честный отказ от обещания;
  • пометка ничего не удаляет. Она только даёт устареванию нижнего слоя основание; само удаление включается отдельно и позже.

stateOfMind пометку не получает никогда — его в экспорте Apple нет ни одним типом (находка 42), источник у него единственный, и устаревание к нему неприменимо. Это надо записать явно, а не оставить следовать из отсутствия данных.

Готово, когда история за несколько лет лежит в слое sample, повторный импорт не меняет ничего, суммы по слою сходятся с часовым слоем HAE на пересечении периодов, а покрытые периоды помечены и видны без пересборки.

Архивы: /home/av/MediaEverything/HealthData/apple_health/ — девять штук, 2021-12 … 2026-08. Старые версии формата годятся как регрессионный набор.