Files
healthlog/openspec/changes/archive/2026-08-01-nerazobrannye-sekcii-dostavki/proposal.md
T
av d79189be18 docs: документация переведена на канон av-dev-pm
- беклог и план переехали в 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 получил настройки с числовым значением
2026-08-03 17:14:53 +03:00

59 lines
4.7 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.
## 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`) получает признак,
на который ему можно опираться.