блокеры разобраны замером: три стали задачами, один закрыт

- находки 48 и 49: единицы не менялись ни разу; настоящих столкновений 0.65%,
  несравнимых наборов полей нет, тай-брейк берёт меньшее в 96% случаев
- edinicy-metriki-v-razreze закрыт: гипотеза не подтвердилась замером
- тай-брейк отложен до каталога рода агрегации
This commit is contained in:
av
2026-08-01 19:33:47 +03:00
parent 37413bb551
commit 349a227ab1
8 changed files with 211 additions and 165 deletions
+42 -40
View File
@@ -1,58 +1,60 @@
# Судьба доставки, у которой разобрана не вся секция data
# Непокрытые секции доставки видны в статусе разбора
**Приоритет:** блокеры
**Приоритет:** высокий
Вынуто ревью кода задачи `razbor-metrik-v-obekty` (профиль `deep`, проход
негативного пространства). **Решить до реализации ретеншена.**
Была блокером, вынутым ревью кода задачи `razbor-metrik-v-obekty` (профиль
`deep`, проход негативного пространства). **Решение принято** — ниже задача.
## Что решить
## Что не так сегодня
Разбор читает только `data.metrics`. Доставка, состоящая из `workouts`,
`stateOfMind`, `symptoms` или `ecg`, помечается `parse_status=parsed` с нулём
точек — неотличимо от доставки с пустой секцией метрик.
## Почему это блокер, а не задача
Само по себе некритично: секции пока не разбираются сознательно, тела лежат в
архиве. Опасность в **сцепке с ретеншеном**. Ретеншен по замыслу срезает архив
до следующего проверенного экспорта. Если он будет ориентироваться на
`parse_status`, он снесёт тела, которые числятся разобранными, — а для
`stateOfMind` это необратимо: **в экспорте Apple его нет** (находка 46),
доставки HAE для него единственный источник.
Само по себе это некритично: секции пока не разбираются сознательно, тела
лежат в архиве. Опасность в **сцепке с ретеншеном**.
Цена ошибки здесь не «придётся пересобрать», а «истории состояния разума больше
не существует».
Ретеншен по замыслу срезает архив до следующего проверенного экспорта. Если он
будет ориентироваться на `parse_status`, он снесёт тела, которые числятся
разобранными, — а для `stateOfMind` это необратимо: **в экспорте Apple его
нет** (находка 46), доставки HAE для него единственный источник.
## Что решено
То есть цена ошибки здесь не «придётся пересобрать», а «истории состояния
разума больше не существует».
Вариант (1): **разбор возвращает список верхнеуровневых ключей `data`, которые
он не покрыл; статус доставки — `partial`.**
## Варианты и цена
Почему он, а не альтернативы:
**(1) Разбор возвращает список верхнеуровневых ключей `data`, которые он не
покрыл; статус `partial`.**
Цена: малая — один `json.Decoder` по верхнему уровню, без чтения содержимого.
Ретеншен и `reindex` получают честный признак, а в логе появляется момент,
когда поток принёс новую секцию (ровно то, ради чего заведена задача
`proverka-novyh-sekcij`).
- Считать `parsed` только полностью разобранную доставку, а остальные держать
в `pending` — дёшево, но `pending` перестаёт означать «ещё не смотрели», и
подбор зависших доставок теряет свой признак. А подбор `pending` как раз
появляется задачей [otvet-i-svyortka](otvet-i-svyortka.md).
- Запретить ретеншену смотреть на `parse_status` — нулевая цена сейчас, но
ретеншен становится тупым и не защищает от «тело разобрано неверно, а мы его
уже срезали».
**(2) Считать `parsed` только доставку, у которой разобрано всё; остальные —
`pending`.**
Цена: малая, но `pending` перестаёт означать «ещё не смотрели», и подбор
зависших доставок теряет свой признак.
Список непокрытых ключей — дешёвая честность, и он же закрывает задачу «не
пропустить момент, когда поедет новая секция».
**(3) Ничего не менять, но ретеншену запретить смотреть на `parse_status`
резать только по дате экспорта.**
Цена: нулевая сейчас, но ретеншен становится тупым и не защищает от «тело
разобрано неверно, а мы его уже срезали».
## Что делать
## Рекомендация
1. `hae.Parse`: перечислить верхнеуровневые ключи `data` и вернуть те, что
разбор не покрыл. Один `json.Decoder` по верхнему уровню, **без чтения
содержимого** — секции доходят до десятков МиБ.
2. Статус `partial` рядом с `parsed`/`failed`; миграция, если статус хранится
ограниченным набором.
3. Свёртка пишет непокрытые ключи в исход доставки и логирует их один раз —
именами ключей, без содержимого.
4. Тест на фикстуре с секцией, которой разбор не знает: статус `partial`,
ключ в списке, точки метрик при этом сохранены.
**(1).** Список непокрытых ключей — дешёвая честность, и он же закрывает
задачу «не пропустить момент, когда поедет новая секция».
## Связано
## Что стоит без решения
Ничего: сегодня ретеншена нет, тела не удаляются. Задача — не дать сцепке
сложиться позже.
Связано: [retenshen-syrogo-arhiva](retenshen-syrogo-arhiva.md) — решить **до**
неё; [proverka-novyh-sekcij](proverka-novyh-sekcij.md) — тот же признак закрыл
бы и её.
- [retenshen-syrogo-arhiva](retenshen-syrogo-arhiva.md) — решить **до** неё.
- [proverka-novyh-sekcij](proverka-novyh-sekcij.md) — тот же признак закрывает
и её: момент появления новой секции становится событием в логе.
- [trenirovki-i-zapisi](trenirovki-i-zapisi.md) — по мере разбора секций список
непокрытых сокращается сам.