Files
healthlog/docs/tasks/items/categorical-value-dictionary.md
T
av 3df42afeca tasks: разобраны вопросы и набран спринт 2026-08-03
- открытых вопросов не осталось: три решения владельца доведены до берущегося
  вида, по entity-without-parsed-label принято хранить с NULL-меткой после Read API
- unseen-sections-check сжата до остатка — активная проверка появления секции;
  разбор невиденных секций из неё вынут, вслепую он не пишется
- спринт под целью parsing-and-storage: categorical-value-dictionary и
  unseen-sections-check, обеим написаны критерии приёмки с оракулами
2026-08-03 17:47:41 +03:00

68 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Словарь категориальных значений → коды HealthKit
- **Секция:** ядро
- **Зачем:** Фазы сна и типы тренировок приходят строками русской локали — с экспортом Apple их не сверить
- **Теги:** goal:parsing-and-storage
HAE отдаёт перечислимые значения строками локали телефона: «БДГ», «Сидячий
образ жизни», «В помещении Ходьба». Родной экспорт Apple при этом говорит
кодами (`HKCategoryValueSleepAnalysisAsleepREM`) — источники несопоставимы
(находка 37).
Три следствия, и третье решающее: клиент угадывает словарь; смена языка
телефона молча расколет историю; сверить покрытие экспортом нечем — а на этой
сверке стоит устаревание нижнего слоя.
Решение (вариант «б»): строка хранится **дословно**, рядом кладётся выведенный
код. Словарь ключуется парой `(локаль, строка)`, локаль берётся из
`Accept-Language`. Незнакомая строка → пустой код, а не догадка.
**Словарь фаз сна уже выведен** сопоставлением потока с экспортом за тот же
период (находка 43) — составлять руками не нужно:
```
Основная → AsleepCore Бодрствование → Awake БДГ → AsleepREM
Глубокий → AsleepDeep В кровати → InBed Во сне → AsleepUnspecified
```
Тем же способом добираются `heart_rate.context` и типы тренировок.
Осложнение, всплывшее на истории экспортов: **коды тоже не вечны.** Одни и те
же записи сна приезжают как `…Asleep` в экспорте 2021 года и как
`…AsleepUnspecified` в экспорте 2026-го: Apple переименовала значение и
переписывает историю при выгрузке (находка 43). Значит словарь должен
переживать переименование самих кодов, иначе после обновления iOS история
расколется вторично — уже на «стабильной» стороне. Простейшее решение: хранить код как есть, а
эквивалентность старых и новых имён держать отдельной таблицей синонимов.
`stateOfMind` в словаре не нуждается — он и так шлёт коды HealthKit.
## Критерии приёмки
- фаза сна из потока («БДГ») и из экспорта Apple
(`HKCategoryValueSleepAnalysisAsleepREM`) за один период сопоставляются
напрямую — оракул: запрос на живой базе за период с известным перекрытием,
ноль несопоставимых строк
- строка сохранена **дословно**, код лежит рядом отдельным полем — оракул: тест
разбора на реальном пакете HAE из `internal/hae/testdata`
- незнакомая строка даёт пустой код, разбор не падает, а событие попадает в
счётчик — оракул: тест на выдуманной фазе сна плюс проверка счётчика
- переименование кода самой Apple (`…Asleep``…AsleepUnspecified`, находка 43)
не раскалывает историю — оракул: тест на паре синонимов, обе формы сходятся
в один код
- повторный прогон живого архива даёт то же состояние — оракул:
`task verify:archive`
Критерий «`/stats` показывает строки без кода» снят при переоценке 2026-08-03:
`/stats` ещё нет ([stats-endpoint](stats-endpoint.md)), и вешать приёмку на
несуществующий оракул значит либо блокировать задачу, либо принять её
непроверенной. Наблюдаемость закрывается счётчиком; показ в `/stats` — строка
задачи наблюдаемости, а не этой.
## Рамки
Схема трогается: у категориального значения появляется поле кода, плюс таблица
синонимов. Дословную строку не заменяем и не нормализуем — инвариант «точки
хранятся дословно». Пересборка обязана оставаться детерминированной, оракул
тот же `task verify:archive`.