Files
healthlog/openspec/changes/archive/2026-08-01-nerazobrannye-sekcii-dostavki/tasks.md
T
av 34e5109b6d непокрытые секции доставки видны в статусе разбора
- половина потока (50 доставок из 104) не несёт metrics вовсе и до сих пор
  числилась parsed: ретеншен, поверив статусу, срезал бы тела stateOfMind,
  которых в экспорте Apple нет
- разбор перечисляет верхнеуровневые ключи data, непокрытые проглатываются
  декодированием: тело 40 МиБ из непокрытой секции удерживает 0 МиБ
- статус partial и колонка delivery.uncovered_sections; миграция переводит
  прежние parsed в pending — им верить нельзя
- витрина не изменилась: отпечаток совпал с прогоном до изменения
2026-08-01 21:25:59 +03:00

85 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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`