добавлен словарь категориальных значений HAE → коды HealthKit
- фазы сна, контекст пульса и имена тренировок попадают в реестр `category_value` (миграция 00010): строка хранится дословно, выведенный код лежит рядом отдельной записью, а не полем внутри точки - словарь и синонимы кодов живут в бинаре (`internal/healthkit`); локаль из `Accept-Language` сужает поиск, но в ключ реестра не входит — заголовков в сыром архиве нет - наблюдение входит в отпечаток витрины, выведенный код — нет: он производная от словаря, а не от журнала
This commit is contained in:
@@ -46,6 +46,17 @@ SQLite (`modernc.org/sqlite`, чистый Go), миграции — goose, фа
|
||||
│ created_at TEXT │ └──────────────────────────┘
|
||||
│ updated_at TEXT │
|
||||
└──────────────────────────┘
|
||||
|
||||
┌────────────────────────────┐
|
||||
│ category_value │
|
||||
│ ───────────────────────── │
|
||||
│ metric TEXT ┐ │
|
||||
│ field TEXT ├PK │
|
||||
│ value TEXT ┘ │
|
||||
│ code TEXT │
|
||||
│ first_seen_utc TEXT │
|
||||
│ first_delivery_id TEXT │
|
||||
└────────────────────────────┘
|
||||
```
|
||||
|
||||
Связь `bucket.first_delivery_id → delivery.id` **внешним ключом не объявлена**
|
||||
@@ -156,6 +167,47 @@ ROWID` строка целиком, вместе со сжатым `payload`, ж
|
||||
журнала, а не свёрнутая последней. Подробности и обоснование — в
|
||||
`architecture.md`, раздел «Тренировки и прочие секции».
|
||||
|
||||
## `category_value` — реестр категориальных значений
|
||||
|
||||
Какие перечислимые строки поток приносил и какой у них стабильный код
|
||||
HealthKit. HAE отдаёт фазу сна как «БДГ», контекст пульса как «Сидячий образ
|
||||
жизни», тип тренировки как «В помещении Ходьба» — строками локали телефона, а
|
||||
родной экспорт Apple говорит кодами; без словаря источники не сходятся
|
||||
(находка 37). Словарь фаз сна выведен сопоставлением потока с экспортом за тот
|
||||
же период (находка 43).
|
||||
|
||||
| Колонка | Смысл |
|
||||
|---|---|
|
||||
| `metric` | имя метрики или секции, **то же**, которым адресуется единица хранения (`sleep_analysis_summary` после разделения схем, `workouts` у тренировок). Второе имя для того же понятия развело бы наблюдение и объект по разным ключам |
|
||||
| `field` | имя поля внутри точки или сущности дословно как у HAE: `value`, `context`, `name` |
|
||||
| `value` | строка **дословно**, как прислал HAE. Код приписывается рядом, а не подменяет её: инвариант «точки хранятся дословно» это и означает |
|
||||
| `code` | канонический код HealthKit. Пустая строка — законное состояние: «словарь этой строки не знает», и перечень таких строк есть заявка на пополнение словаря. **Это кэш**: код производен от словаря в бинаре, а не от журнала, и потому в отпечаток витрины не входит. Строка, переставшая приезжать, держит код прежнего словаря до пересборки |
|
||||
| `first_seen_utc`, `first_delivery_id` | провенанс **первой** встречи, минимум по журналу `(received_at, id)`. Минимум идемпотентен при повторной свёртке той же доставки; счётчик встреч не идемпотентен и потому не заводится вовсе. Отвечает на вопрос «когда сменился язык телефона», а язык доставки восстанавливается по `delivery.headers` |
|
||||
|
||||
Ключ — тройка без локали, и это решение, а не упущение. Локаль приезжает
|
||||
заголовком `Accept-Language`, а заголовков в сыром архиве нет: они были
|
||||
заголовками запроса, а не телом. Доставка, восстановленная из осиротевшего
|
||||
тела, приходит без локали — ключ с локалью положил бы вторую строку на то же
|
||||
значение, то есть состояние стало бы функцией от того, уцелела ли учётная
|
||||
строка. Локаль при выводе кода сужает поиск по словарю; её отсутствие вывода не
|
||||
отменяет, если строка однозначна.
|
||||
|
||||
Таблица `WITHOUT ROWID`: обращение всегда по полному первичному ключу, а строк
|
||||
единицы — на живом потоке различных значений по всем трём полям около
|
||||
одиннадцати. Индексов нет: чтение идёт целиком, в порядке ключа.
|
||||
|
||||
Границы разбора не дают доставке положить больше 64 различных значений и
|
||||
значение длиннее 128 байт (измерено: ~11 значений, самое длинное 36 байт).
|
||||
Слишком длинное **отбрасывается со счётчиком, а не обрезается** — обрезанная
|
||||
строка неотличима от настоящей и стала бы самостоятельным ключом; сама точка
|
||||
при этом хранится целиком.
|
||||
|
||||
Data-миграции у таблицы нет и быть не может: коды выводятся из тел, а тела
|
||||
лежат в архиве. Реестр рабочей витрины наполняется по мере свёртки новых
|
||||
доставок и целиком — пересборкой. Отсюда первое расхождение отпечатков после
|
||||
выкатки: оно законно, и отчёт `reindex` называет его ожидаемым классом
|
||||
«появилась единица хранения».
|
||||
|
||||
## Представление данных
|
||||
|
||||
- **Точки часового объекта лежат сжатым BLOB** (`gzip`) в колонке `payload`.
|
||||
|
||||
Reference in New Issue
Block a user