## 1. Разбор: перечисление непокрытых ключей - [x] 1.1 `decodeMetrics` → `decodeEnvelope`: один `json.Decoder` идёт по верхнему уровню, имя члена читается `Token()`, значение покрытого ключа декодируется на месте, значение непокрытого проглатывается декодированием в выбрасываемый `json.RawMessage` (ограничитель вложенности stdlib при этом работает, в отличие от ручного счёта глубины) - [x] 1.2 Покрытость — функция рядом с разбором, а не изменяемая пакетная карта; `Result.Uncovered` отдаёт непокрытые отсортированными и без повторов - [x] 1.3 Границы: не больше 32 имён (`Result.UncoveredDropped` считает отброшенные), имя длиннее 64 байт декодированного имени обрезано по границе рун, маркер `…` приписывается сверх предела - [x] 1.4 Повтор ключа `metrics` даёт объединение секций; повтор непокрытого ключа даёт одно имя. Тело без `data`, `data` не объект, `data` пустой, `metrics` неверного типа — прежнее поведение (ошибка ровно там, где была) - [x] 1.5 Ошибка после разобранной секции `metrics` точек не отдаёт ## 2. Хранилище: статус и список - [x] 2.1 Константа `store.ParsePartial`; док-комментарий `ParsePending` переписан на «этим разбором ещё не смотрели» - [x] 2.2 Миграция: колонка `uncovered_sections TEXT NOT NULL DEFAULT '[]'` и перевод существующих `parsed` в `pending`; в комментарии миграции сказано, что по данным она односторонняя — `Down` снимает колонку, прежние статусы не восстанавливает - [x] 2.3 Исход разбора пишется структурой (`store.ParseOutcome`), а не растущим списком позиционных параметров; список замещает прежнее значение целиком, включая замещение пустым; `nil` и пустой срез записываются как `[]` ## 3. Свёртка: исход и лог - [x] 3.1 `Stats.Uncovered` и `Stats.UncoveredDropped`; статус `partial` при непустом списке, `failed` сильнее; при отказе список сохраняется, если разбор успел его собрать - [x] 3.2 Атрибуты `uncovered` (структурным `[]string`) и `uncovered_dropped` в единственном логирующем чекпоинте; уровень из-за одной лишь частичности не растёт, срабатывание границ даёт `WARN` ## 4. Тесты (приёмочные критерии) - [x] 4.1 Фикстура `uncovered_sections.json`: точки метрик сохранены, ключи `workouts` и `stateOfMind` в списке, статус `partial` - [x] 4.2 Доставка из одной непокрытой секции: разбор без ошибки, ноль точек, ключ в списке, статус `partial` - [x] 4.3 Доставка из одних метрик: список пуст, статус `parsed` - [x] 4.4 Детерминизм: тот же набор секций в разном порядке и с повтором ключа даёт тот же список - [x] 4.5 Границы: 40 ключей → 32 имени и счётчик отброшенных; длинное имя → обрезка с маркером - [x] 4.6 Удержание кучи: тело в десятки мегабайт, состоящее преимущественно из непокрытой секции, удерживает не больше четырёх тел; тело из вложенных скобок отвергается, а не съедает память - [x] 4.7 Отказ всё или ничего: тело оборвано после секции метрик — ошибка, ноль точек, `failed` - [x] 4.8 Лог свёртки: имена ключей есть, содержимого секций нет; уровень при обычной частичности не повышен - [x] 4.9 Миграция: строка со статусом `parsed` становится `pending`, колонка получает `[]` - [x] 4.10 Пересвёртка: доставка `partial`, у которой список опустел, становится `parsed` с пустым списком - [x] 4.11 Прогон живого архива (`task verify:archive`): доставки без метрик получают `partial` с непустым списком, повторный прогон состояния не меняет - [x] 4.12 Сверка с состоянием ДО изменения: витрина, собранная из живого архива новым кодом, совпадает по объектам, точкам и метрикам со снимком, снятым до изменения ## 5. Документация - [x] 5.1 `docs/database.md`: колонка, полный набор статусов, новый смысл `pending` - [x] 5.2 `docs/architecture.md`: частичный разбор в разделе приёма - [x] 5.3 `docs/local-research.md`: находка о наборах секций в живом потоке (99 доставок: 51 `metrics`, 24 `workouts`, 24 `stateOfMind`, секции не смешиваются, пустых нет) ## 6. Замеры после реализации - [x] 6.1 Живой архив (104 доставки): частично разобрано **50** — 25 `stateOfMind` и 25 `workouts`. Отпечаток витрины `a59b38ea…` совпал с прогоном ДО изменения на том же архиве: переписанный разбор конверта — строгий no-op для витрины - [x] 6.2 Удержание кучи: тело 40 МиБ, из которых почти всё — непокрытая секция, удерживает **0 МиБ**; тело из 100 000 уровней вложенности отвергается - [x] 6.3 Живой сервис разобрал пришедшие с телефона доставки (5 штук) — заодно закрыт пункт 6.3a задачи `razbor-metrik-v-obekty`