Files
healthlog/docs/adr/ADR-2026-08-03-kod-ryadom-so-strokoj-reestrom.md
T
av 3d24248075 docs: документация приведена к канону av-dev-pm 4
- каждая запись каталога задач получила тип вместо тега kind: и префикса
  заголовка; секция роадмапа «Разработка» стала «Сопровождением», порядок
  секций канонический
- поправлены протухшие факты: нереализованные маршруты Read API, MCP и
  `healthlog import`, словарь слоёв в инварианте, семантика гейта по покрытию
  диффа, периметр перестал дублировать security.md
- замер слияния переведён с находки 49 на находку 54, заполнены Purpose спек
  storage и parsing
2026-08-05 19:09:35 +03:00

65 lines
5.6 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 кладётся реестром рядом, а не полем внутри точки
- **Дата:** 2026-08-03
- **Источник:** openspec/changes/archive/2026-08-03-slovar-kategorialnyh-znachenij/design.md
## Решение
Стабильный код HealthKit для локализованной строки хранится **отдельной строкой
таблицы `category_value`** с ключом `(метрика, поле, значение)`, а не полем
`value_code` внутри точки, как рисовал `architecture.md`. Словарь и таблица
синонимов живут в бинаре (`internal/healthkit`), а не в базе. Наблюдение входит
в отпечаток витрины, выведенный код — **нет**.
## Почему
Рассматривались три формы, и отвергнутые названы вместе с ценой.
**Поле внутри точки** — отвергнуто. Цитата источника: «Точка хранится
**исходными байтами**; дописать в неё ключ можно только пересериализацией, а она
теряет литерал (`1.0``1`, целые больше 2^53 сдвигаются, невалидный UTF-8 →
U+FFFD) — ровно то, от чего `Point.Raw` защищает. Побайтовая врезка в чужой
JSON — фокус, а не решение. Параллельный массив кодов в `bucket` завёл бы
производную величину в путь слияния и хеширования: правило полноты, тай-брейк и
`content_hash` пришлось бы учить носить код, не давая ему влиять на исход.
Правка на поверхности `critical`-инвариантов ради нуля новых сведений — код есть
**функция** от того, что уже лежит».
**Код нигде не хранится, выводится на чтении** — отвергнуто по одной причине:
«тогда код недостижим ничем, кроме бинаря. Владелец сегодня читает витрину
`sqlite` на хосте (`Read API` ещё нет), а вся задача затевается против того, что
„клиент угадывает словарь“. Реестр без кода сообщает только „такая строка
была“ — это половина ответа».
**Словарь в базе, а не в бинаре** — отвергнуто: «словарь стал бы входом,
которого нет в журнале, и `import + replay` перестал бы задавать состояние
однозначно. `stateOfMind` уже единственная дыра в журнале; вторую заводить
незачем».
**Код вне отпечатка** — обратная сторона того же решения: «Ключ и провенанс —
функция журнала; `code` — функция журнала **и версии словаря в бинаре**. Включи
его в отпечаток, и он перестал бы отвечать на свой единственный вопрос („дал ли
повтор журнала то же состояние“) ровно тогда, когда его задают: всякое
пополнение словаря — а оно объявлено рабочим циклом — давало бы расхождение при
побайтно совпавшем журнале, и человек, принимающий необратимое решение о
подмене базы, читал бы это как дефект».
Prior art: FHIR `ConceptMap` (отображение «чужая система значений → своя») и
`CodeSystem` с `replaced-by` для устаревших имён — те же два отношения,
разведённые по разным сущностям. Форма взята, реализация FHIR отвергнута ценой.
## Последствия
- `+` Инвариант «точки хранятся дословно» не тронут вовсе: точка не меняется ни
байтом, обратное преобразование возможно всегда.
- `+` Пути слияния, тай-брейка и `content_hash` не знают о кодах — правки на
поверхности `critical`-инвариантов не потребовалось.
- `+` Пополнение словаря меняет десяток строк реестра, а не каждый объект с
фазами сна; отпечаток при этом не двигается, потому что код в него не входит.
- `` Потребитель обязан делать соединение по `(метрика, поле, значение)` вместо
чтения одного поля. Форма ответа Read API это скроет, когда он появится.
- `` Код в базе отстаёт от словаря в бинаре для строк, переставших приезжать.
Лечится пересборкой; на сходимость не влияет.
- `` Ключ реестра зафиксирован миграцией `00010`: смена формы ключа стоит
второй миграции и пересборки.