- беклог и план переехали в docs/tasks (38 задач, 11 целей), слаги переименованы с транслита на английские, 85 ссылок поправлены - conventions.md разобран в docs/conventions/, local-research.md — в docs/research/, review-journal.md — в docs/review.md с разделом настройки конвейера; заведены security.md, adr/ и .pm.json - шаг docs.py check добавлен в task gate; поведение в architecture.md помечено девятью маркерами долга, database.md получил настройки с числовым значением
59 lines
4.7 KiB
Markdown
59 lines
4.7 KiB
Markdown
## Why
|
||
|
||
Разбор читает только `data.metrics`. Доставка, целиком состоящая из другой
|
||
секции, получает `parse_status=parsed` с нулём точек — неотличимо от доставки с
|
||
пустой секцией метрик. Измерено на живом архиве: из 99 доставок 48 не содержат
|
||
`metrics` вовсе (24 `workouts`, 24 `stateOfMind`), то есть почти половина потока
|
||
сейчас числится разобранной, не будучи разобранной.
|
||
|
||
Само по себе это некритично — тела лежат в архиве. Опасность в сцепке с
|
||
ретеншеном: он по замыслу срезает архив до следующего проверенного экспорта, и
|
||
если станет опираться на `parse_status`, снесёт тела, которые числятся
|
||
разобранными. Для `stateOfMind` это необратимо — в экспорте Apple его нет
|
||
(находка 46), доставки HAE единственный его источник. Ретеншен — следующая
|
||
задача, поэтому признак нужен до неё.
|
||
|
||
## What Changes
|
||
|
||
- `hae.Parse` перечисляет верхнеуровневые ключи `data` и возвращает те, что
|
||
разбор не покрыл. Перечисление идёт **без чтения содержимого секций**: тела
|
||
доходят до 42 МиБ, и удержание кучи здесь — часть контракта.
|
||
- Появляется статус доставки `partial` рядом с `parsed`/`failed`: тело
|
||
разобрано в той части, которую разбор покрывает, и в нём остались
|
||
непокрытые секции.
|
||
- Свёртка сохраняет список непокрытых ключей в исход доставки и называет их
|
||
**именами ключей** в своём единственном логирующем чекпоинте. Содержимого
|
||
секций в логе нет и быть не может.
|
||
- Число ключей и длина имени в записи ограничены: ключи приходят из тела,
|
||
которым отправитель управляет целиком; усечение видно счётчиком и маркером.
|
||
- **Миграция переписывает `parse_status` у всех накопленных доставок:**
|
||
существующие `parsed` становятся `pending` — «этим разбором ещё не смотрели».
|
||
Статус, поставленный кодом, который частичного разбора не различал, ничего не
|
||
доказывает, а ретеншен собирается на него опираться. Цена: 99 строк живой базы
|
||
меняют статус на первом старте нового бинаря, и до появления подбора `pending`
|
||
(задача `otvet-i-svyortka`) никто их не пересвернёт; тела при этом остаются в
|
||
архиве, объекты витрины — на месте, и `Down` прежние статусы не восстановит.
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
|
||
Новых нет.
|
||
|
||
### Modified Capabilities
|
||
|
||
- `parsing`: разбор обязан перечислять непокрытые верхнеуровневые ключи `data`,
|
||
не читая их содержимого, и отдавать их вызывающему.
|
||
- `storage`: у доставки появляется статус `partial` и список непокрытых секций;
|
||
учёт обязан отличать «разобрано целиком» от «разобрано частично».
|
||
|
||
## Impact
|
||
|
||
- `internal/hae` — перечисление ключей в том же проходе, что и разбор метрик.
|
||
- `internal/store` — константа статуса, колонка `uncovered_sections`, миграция.
|
||
- `internal/fold` — исход свёртки, статус и атрибут лога.
|
||
- `docs/database.md`, `docs/architecture.md`, `docs/local-research.md` —
|
||
схема, статусы и находка о наборах секций в живом потоке.
|
||
- Ретеншен сырого архива (задача `raw-archive-retention`) получает признак,
|
||
на который ему можно опираться.
|