- секции `workouts` и `stateOfMind` покрыты разбором: тренировка лежит одной строкой вместе с маршрутом и внутренними рядами, запись — по ключу `род + id`; миграция 00007 заводит обе таблицы и возвращает в очередь `partial`-доставки с этими ключами - сущность заменяется целиком, но условно: приехавшая побеждает, если не теряет содержания сохранённой (множество ключей и длины верхнеуровневых массивов), а при равном содержании выигрывает версия из более поздней доставки ЖУРНАЛА — «побеждает приехавшая» было бы функцией порядка свёртки, и живая витрина расходилась бы с пересборкой молча - отпечаток витрины покрывает тренировки и записи и снимается одним снимком базы; отчёт `reindex` считает «было и стало» по каждой единице хранения
6.9 KiB
6.9 KiB
Why
Половина живого потока разбором не покрыта. Замер по 118 доставкам архива:
65 несут metrics, 27 — workouts, 26 — stateOfMind. Тренировки и состояние
разума сохраняются в архив и числятся partial, но в витрину не попадают:
трекеру (второй потребитель паспорта) взять тренировку неоткуда, агенту-медику
состояние разума — тоже.
Для stateOfMind это дороже, чем для метрик: в родном экспорте Apple секции нет
ни одним типом (находка 46), то есть доставки HAE — её единственный источник,
и ретеншен архива без разобранной секции нельзя включать вовсе.
What Changes
- Разбор покрывает две новые секции тела:
workoutsиstateOfMind. Остальные секции с собственнымиid(ecg,symptoms,cycleTracking,medications,heartRateNotifications) остаются непокрытыми намеренно — живьём поток их не приносил ни разу, и модель под них закладывается, а разбор — нет. - Две новые таблицы:
workout(заголовок колонками, всё остальное, включая маршрут и внутренние ряды, —payloadдословно) иrecord(секции с собственнымid, ключkind + id). - Сущность с собственным
idзаменяется целиком, а не сливается по полям. Правило замены названо явно: приехавшая версия побеждает, если не теряет содержания сохранённой; иначе сохранённая остаётся, факт считается и идёт вWARN. При равных наборах полей выигрывает версия из более поздней доставки журнала, а не свёрнутая последней, — иначе живая витрина расходилась бы с пересборкой молча. - Сущность несёт провенанс — доставку своей версии и её метку приёма.
- Разбор метки времени принимает второй формат — RFC 3339 в UTC, которым HAE шлёт
stateOfMind(находка 16). - Отпечаток витрины (оракул сходимости
reindex) покрывает тренировки и записи, а не одни часовые объекты, и снимается одним снимком базы. Отчётreindexсчитает «до и после» по каждой единице хранения и называет «покрыта новая секция» ожидаемым классом расхождения. - «Отказ разбора — всё или ничего» распространяется на сущности явно, включая ветку невыводимого слоя и повтор ключа секции.
- Миграция переводит в
pendingдоставки, у которых в списке непокрытых секций стоят ставшие покрытыми имена, — правило «покрыли секцию — пересверните» уже записано в спеке хранения. - Не входит: отдача тренировок и записей наружу. Read API в проекте пока нет
вовсе; его форма (конверт ответа, выбор слоя, предел размера) проектируется
задачей
read-api-tochki, и вводить два эндпоинта раньше конверта значило бы задать контракт мимоходом.
Capabilities
New Capabilities
Новых нет: тренировка и запись — это то же хранилище и тот же разбор, только другая единица хранения. Отдельная capability создала бы второй словарь для того же домена.
Modified Capabilities
parsing: покрытых секций становится три вместо одной; появляется разбор сущностей с собственнымidи второй формат метки времени (RFC 3339), оставленный предыдущей дельтой явно ненормированным; «всё или ничего» распространяется на сущности.storage: появляется вторая единица хранения — сущность с собственнымid, со своим правилом замены версии; отпечаток витрины перестаёт быть отпечатком одних часовых объектов; запрет на данные о здоровье в логах распространяется на содержимое сущностей.reindex: счётчики отчёта покрывают все единицы хранения, а «покрыта новая секция» становится названным классом ожидаемого расхождения.
Impact
internal/hae— разбор двух секций, второй формат метки, новые счётчики пропусков.internal/store— таблицыworkoutиrecord, слияние доставки одной транзакцией вместе с точками, отпечаток витрины.internal/fold— счётчики и единственный логирующий чекпоинт свёртки.internal/replay— ничего, кроме того, что отпечаток стал шире: пересборка зовёт ту же свёртку.- Миграция
00007— две таблицы и переводpartial-доставок вpending. docs/database.md,docs/architecture.md,docs/local-research.md— схема, правило замены версии и находка о поведении тренировки при переприсылке.- Фикстуры
internal/hae/testdataи скрипт их сборкиtmp/research/fixtures.py: тренировка с маршрутом и состояние разума — на реальных пакетах с вычищенными измерениями.