## ADDED Requirements

### Requirement: Учёт частично разобранной доставки

Система SHALL отличать доставку, разобранную целиком, от доставки, в теле
которой остались непокрытые разбором секции. Доставка с непустым списком
непокрытых ключей MUST получать статус `partial`, а не `parsed`.

Статусы разбора:

```
pending  этим разбором ещё не смотрели
parsed   разобрано всё, что в теле было
partial  разобрано покрытое; в теле остались непокрытые секции
failed   разобрать не удалось, точек нет
```

Источник истины — список непокрытых ключей; статус производен от него и от
факта отказа, в порядке `failed` → `partial` → `parsed`. Приоритет назван явно,
чтобы читатели (ретеншен, статистика) спрашивали статус, а не сравнивали список
со строкой.

Список непокрытых ключей SHALL сохраняться рядом с доставкой — именами ключей,
без содержимого секций. Он же ответ на вопрос «что останется потерянным, если
тело удалить»: для `stateOfMind` доставки HAE единственный источник, в экспорте
Apple его нет (находка 46). Поэтому список MUST сохраняться и при отказе
разбора, если разбор успел его собрать: `failed` с непустым списком — законное
состояние.

Запись списка MUST замещать прежнее значение целиком, включая замещение пустым:
иначе доставка, все секции которой стали покрытыми, осталась бы `partial`
навсегда.

Список — снимок покрытия **на момент свёртки**. Задача, которая начинает
разбирать секцию, тем же изменением SHALL переводить `partial`-строки с этим
ключом в `pending`; ретеншену позволено смотреть на `partial` только при
соблюдении этого правила.

Статусы, поставленные разбором, который частичного исхода не различал, доверия
не заслуживают: под `parsed` у них лежат и полностью разобранные доставки, и
доставки без метрик вовсе. Такие строки MUST переводиться в `pending` — «этим
разбором ещё не смотрели». Число точек у них до пересвёртки остаётся прежним: оно
производно от объектов витрины, которые никуда не делись.

#### Scenario: Доставка с непокрытой секцией отмечается частичной

- **WHEN** разбор доставки вернул непустой список непокрытых ключей
- **THEN** `parse_status` доставки равен `partial`
- **AND** список непокрытых ключей сохранён вместе с доставкой
- **AND** точки покрытой секции сохранены как обычно

#### Scenario: Доставка без непокрытых секций остаётся `parsed`

- **WHEN** разбор доставки не дал непокрытых ключей
- **THEN** `parse_status` равен `parsed`
- **AND** сохранённый список непокрытых ключей пуст

#### Scenario: Отказ разбора сильнее частичности

- **WHEN** разбор доставки завершился ошибкой
- **THEN** `parse_status` равен `failed`
- **AND** список непокрытых ключей сохранён, если разбор успел его собрать

#### Scenario: Пересвёртка после того, как секция стала покрытой

- **WHEN** доставка со статусом `partial` сворачивается повторно разбором,
  который эту секцию уже покрывает
- **THEN** её статус становится `parsed`
- **AND** сохранённый список непокрытых ключей пуст

#### Scenario: Строки прежнего разбора переводятся в неразобранные

- **WHEN** база содержит доставки со статусом `parsed`, свёрнутые до появления
  частичного статуса
- **THEN** после миграции их статус равен `pending`
- **AND** тела остаются в архиве, а повторная свёртка даёт то же состояние

## MODIFIED Requirements

### Requirement: Значения точек не попадают в логи

Данные о здоровье чувствительнее токенов. Система MUST NOT писать значения
точек и тела доставок в записи лога уровня выше `DEBUG`.

Непокрытые секции называются в логе **именами ключей**: имя секции — это форма
пакета, а не измерение. Содержимое секции в лог не попадает ни при каком уровне
выше `DEBUG`. Имена идут структурным атрибутом, а не склейкой в текст сообщения:
кодировщик экранирует управляющие символы, и имя из чужого тела не разрывает
построчный разбор логов.

Частичный разбор уровня записи не повышает: `partial` — установившееся состояние
половины потока (48 доставок из 99), и постоянный `WARN` обесценил бы уровень.
Повышает уровень другое — срабатывание границ списка: тело с сотнями секций или
с именем длиннее предела на HAE не похоже вовсе.

#### Scenario: Разбор доставки логируется без значений

- **WHEN** доставка разобрана
- **THEN** запись лога содержит счётчики (метрик, точек, объектов) и
  идентификатор доставки
- **AND** не содержит ни значений точек, ни имён устройств

#### Scenario: Непокрытые секции названы именами ключей

- **WHEN** доставка содержит непокрытую секцию
- **THEN** запись лога содержит имена непокрытых ключей отдельным атрибутом
- **AND** не содержит ничего из содержимого этих секций
- **AND** уровень записи из-за одной лишь частичности не повышается

#### Scenario: Границы списка сработали

- **WHEN** список непокрытых ключей усечён по числу имён или по длине имени
- **THEN** запись лога имеет уровень `WARN`
- **AND** содержит число отброшенных имён
