непокрытые секции доставки видны в статусе разбора
- половина потока (50 доставок из 104) не несёт metrics вовсе и до сих пор числилась parsed: ретеншен, поверив статусу, срезал бы тела stateOfMind, которых в экспорте Apple нет - разбор перечисляет верхнеуровневые ключи data, непокрытые проглатываются декодированием: тело 40 МиБ из непокрытой секции удерживает 0 МиБ - статус partial и колонка delivery.uncovered_sections; миграция переводит прежние parsed в pending — им верить нельзя - витрина не изменилась: отпечаток совпал с прогоном до изменения
This commit is contained in:
@@ -20,7 +20,6 @@
|
||||
- [Read API: точки, выбор слоя, свёртка по сетке](read-api-tochki.md) — Данные видны только через sqlite на хосте — ни один из трёх потребителей ничего прочитать не может
|
||||
- [OpenAPI-спека и Swagger UI](openapi-swagger.md) — Потребителей три и один из них агент — контракт должен читаться машиной, а не пересказываться в чате
|
||||
- [MCP-сервер поверх Read API](mcp-server.md) — Агент-медик — первый заказчик проекта, а подключить его сейчас нечем
|
||||
- [Непокрытые секции доставки видны в статусе разбора](nerazobrannye-sekcii-dostavki.md) — тело с одним stateOfMind числится parsed, а ретеншен снесёт его как разобранное — и в экспорте Apple его нет
|
||||
- [Разнести ответ приёма и свёртку доставки](otvet-i-svyortka.md) — синхронная свёртка не помещается в write_timeout: широкие проходы получают обрыв вместо 200
|
||||
|
||||
## средний
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# Непокрытые секции доставки видны в статусе разбора
|
||||
|
||||
**Приоритет:** высокий
|
||||
|
||||
Была блокером, вынутым ревью кода задачи `razbor-metrik-v-obekty` (профиль
|
||||
`deep`, проход негативного пространства). **Решение принято** — ниже задача.
|
||||
|
||||
## Что не так сегодня
|
||||
|
||||
Разбор читает только `data.metrics`. Доставка, состоящая из `workouts`,
|
||||
`stateOfMind`, `symptoms` или `ecg`, помечается `parse_status=parsed` с нулём
|
||||
точек — неотличимо от доставки с пустой секцией метрик.
|
||||
|
||||
Само по себе некритично: секции пока не разбираются сознательно, тела лежат в
|
||||
архиве. Опасность в **сцепке с ретеншеном**. Ретеншен по замыслу срезает архив
|
||||
до следующего проверенного экспорта. Если он будет ориентироваться на
|
||||
`parse_status`, он снесёт тела, которые числятся разобранными, — а для
|
||||
`stateOfMind` это необратимо: **в экспорте Apple его нет** (находка 46),
|
||||
доставки HAE для него единственный источник.
|
||||
|
||||
Цена ошибки здесь не «придётся пересобрать», а «истории состояния разума больше
|
||||
не существует».
|
||||
|
||||
## Что решено
|
||||
|
||||
Вариант (1): **разбор возвращает список верхнеуровневых ключей `data`, которые
|
||||
он не покрыл; статус доставки — `partial`.**
|
||||
|
||||
Почему он, а не альтернативы:
|
||||
|
||||
- Считать `parsed` только полностью разобранную доставку, а остальные держать
|
||||
в `pending` — дёшево, но `pending` перестаёт означать «ещё не смотрели», и
|
||||
подбор зависших доставок теряет свой признак. А подбор `pending` как раз
|
||||
появляется задачей [otvet-i-svyortka](otvet-i-svyortka.md).
|
||||
- Запретить ретеншену смотреть на `parse_status` — нулевая цена сейчас, но
|
||||
ретеншен становится тупым и не защищает от «тело разобрано неверно, а мы его
|
||||
уже срезали».
|
||||
|
||||
Список непокрытых ключей — дешёвая честность, и он же закрывает задачу «не
|
||||
пропустить момент, когда поедет новая секция».
|
||||
|
||||
## Что делать
|
||||
|
||||
1. `hae.Parse`: перечислить верхнеуровневые ключи `data` и вернуть те, что
|
||||
разбор не покрыл. Один `json.Decoder` по верхнему уровню, **без чтения
|
||||
содержимого** — секции доходят до десятков МиБ.
|
||||
2. Статус `partial` рядом с `parsed`/`failed`; миграция, если статус хранится
|
||||
ограниченным набором.
|
||||
3. Свёртка пишет непокрытые ключи в исход доставки и логирует их один раз —
|
||||
именами ключей, без содержимого.
|
||||
4. Тест на фикстуре с секцией, которой разбор не знает: статус `partial`,
|
||||
ключ в списке, точки метрик при этом сохранены.
|
||||
|
||||
## Связано
|
||||
|
||||
- [retenshen-syrogo-arhiva](retenshen-syrogo-arhiva.md) — решить **до** неё.
|
||||
- [proverka-novyh-sekcij](proverka-novyh-sekcij.md) — тот же признак закрывает
|
||||
и её: момент появления новой секции становится событием в логе.
|
||||
- [trenirovki-i-zapisi](trenirovki-i-zapisi.md) — по мере разбора секций список
|
||||
непокрытых сокращается сам.
|
||||
@@ -29,3 +29,10 @@
|
||||
`docs/local-research.md` как не пришедшая, и ни одна не числится в ошибках
|
||||
разбора.
|
||||
|
||||
## Что уже сделано
|
||||
|
||||
Разбор перечисляет непокрытые секции и пишет их в `delivery.uncovered_sections`
|
||||
(change `2026-08-01-nerazobrannye-sekcii-dostavki`). Момент, когда поток принесёт
|
||||
секцию, которой раньше не было, теперь **фиксируется** — остаётся научиться
|
||||
замечать его активно: один `SELECT DISTINCT` по колонке даёт список всего, что
|
||||
поток приносил, и сравнение с известным набором закрывает задачу.
|
||||
|
||||
@@ -26,3 +26,14 @@
|
||||
экспорта, записи `stateOfMind` не трогаются вовсе, а `/stats` показывает
|
||||
глубину архива и дату снапшота, до которой он подрезан.
|
||||
|
||||
## Предусловие снято
|
||||
|
||||
Признак, без которого ретеншен был опасен, готов: доставка с непокрытой секцией
|
||||
имеет статус `partial` и список непокрытых ключей
|
||||
(change `2026-08-01-nerazobrannye-sekcii-dostavki`). Ретеншен обязан спрашивать
|
||||
статус, а не считать `parsed` разрешением: тело `stateOfMind` восстановить
|
||||
неоткуда — в экспорте Apple секции нет.
|
||||
|
||||
Вместе с этим действует правило: задача, которая начинает разбирать секцию, тем
|
||||
же изменением переводит `partial`-строки с этим ключом в `pending`. Ретеншену
|
||||
позволено смотреть на `partial` только пока правило соблюдается.
|
||||
|
||||
Reference in New Issue
Block a user