Files
healthlog/openspec/changes/archive/2026-08-01-nerazobrannye-sekcii-dostavki/proposal.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

4.7 KiB
Raw Blame History

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 — схема, статусы и находка о наборах секций в живом потоке.
  • Ретеншен сырого архива (задача retenshen-syrogo-arhiva) получает признак, на который ему можно опираться.