## 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`
