отработаны находки ревью кода

Триаж свёл 62 сырые находки девяти проходов к 33 причинам: 3 блокера,
4 «сейчас», 2 развилки. Все закрыты регрессионными тестами.

- схема точки сна определяется по самой точке, а не по индексу в исходном
  массиве: одна пропущенная точка меняла эпизод и сводку местами
- доставка сворачивается одной транзакцией: частичное состояние было
  недетерминированным (восемь прогонов — семь состояний)
- граница размера на распакованном теле: 400 КиБ gzip разворачивались в
  400 МиБ мимо max_body_mb
- столкновение — расхождение канонических форм, а не байтов; WARN с
  координатами объекта; payload без HTML-экранирования
- выравнивание по местной метке: получасовые зоны уводили часовую выгрузку
  в minute
- доставка из одних суточных сводок больше не отвергается целиком
- единицы не переписываются молча; счётчик считает сохранённые точки
- все выходы Fold логируются, исход пишется на переживающем отмену контексте

Четыре развилки вынесены блокерами в беклог.
This commit is contained in:
av
2026-08-01 19:02:05 +03:00
parent 32f21044e4
commit cd7a4c1493
23 changed files with 1340 additions and 175 deletions
@@ -0,0 +1,58 @@
# Судьба доставки, у которой разобрана не вся секция data
**Приоритет:** блокеры
Вынуто ревью кода задачи `razbor-metrik-v-obekty` (профиль `deep`, проход
негативного пространства). **Решить до реализации ретеншена.**
## Что решить
Разбор читает только `data.metrics`. Доставка, состоящая из `workouts`,
`stateOfMind`, `symptoms` или `ecg`, помечается `parse_status=parsed` с нулём
точек — неотличимо от доставки с пустой секцией метрик.
## Почему это блокер, а не задача
Само по себе это некритично: секции пока не разбираются сознательно, тела
лежат в архиве. Опасность в **сцепке с ретеншеном**.
Ретеншен по замыслу срезает архив до следующего проверенного экспорта. Если он
будет ориентироваться на `parse_status`, он снесёт тела, которые числятся
разобранными, — а для `stateOfMind` это необратимо: **в экспорте Apple его
нет** (находка 46), доставки HAE для него единственный источник.
То есть цена ошибки здесь не «придётся пересобрать», а «истории состояния
разума больше не существует».
## Варианты и цена
**(1) Разбор возвращает список верхнеуровневых ключей `data`, которые он не
покрыл; статус `partial`.**
Цена: малая — один `json.Decoder` по верхнему уровню, без чтения содержимого.
Ретеншен и `reindex` получают честный признак, а в логе появляется момент,
когда поток принёс новую секцию (ровно то, ради чего заведена задача
`proverka-novyh-sekcij`).
**(2) Считать `parsed` только доставку, у которой разобрано всё; остальные —
`pending`.**
Цена: малая, но `pending` перестаёт означать «ещё не смотрели», и подбор
зависших доставок теряет свой признак.
**(3) Ничего не менять, но ретеншену запретить смотреть на `parse_status`
резать только по дате экспорта.**
Цена: нулевая сейчас, но ретеншен становится тупым и не защищает от «тело
разобрано неверно, а мы его уже срезали».
## Рекомендация
**(1).** Список непокрытых ключей — дешёвая честность, и он же закрывает
задачу «не пропустить момент, когда поедет новая секция».
## Что стоит без решения
Ничего: сегодня ретеншена нет, тела не удаляются. Задача — не дать сцепке
сложиться позже.
Связано: [retenshen-syrogo-arhiva](retenshen-syrogo-arhiva.md) — решить **до**
неё; [proverka-novyh-sekcij](proverka-novyh-sekcij.md) — тот же признак закрыл
бы и её.