Files
healthlog/docs/tasks/items/delivery-headers-in-archive.md
T
av 3d24248075 docs: документация приведена к канону av-dev-pm 4
- каждая запись каталога задач получила тип вместо тега kind: и префикса
  заголовка; секция роадмапа «Разработка» стала «Сопровождением», порядок
  секций канонический
- поправлены протухшие факты: нереализованные маршруты Read API, MCP и
  `healthlog import`, словарь слоёв в инварианте, семантика гейта по покрытию
  диффа, периметр перестал дублировать security.md
- замер слияния переведён с находки 49 на находку 54, заполнены Purpose спек
  storage и parsing
2026-08-05 19:09:35 +03:00

3.8 KiB

🐞 Класть заголовки доставки в архив рядом с телом

  • Тип: fix
  • Категория: Ядро
  • Зачем: Заголовки живут только в базе — потеря базы навсегда ломает вывод слоя при пересборке
  • Теги: goal:journal-and-rebuild

Состояние объявлено свёрткой по журналу, а журналом — сырой архив. Но в архиве лежит только тело: заголовки запроса (automation-id, automation-aggregation, Accept-Language и всё незадокументированное) живут единственной копией — в колонке delivery.headers.

Отсюда дыра, которую пересборка обнажила, а не создала. healthlog reindex читает учёт из рабочей базы именно потому, что восстановить заголовки неоткуда. Пока база цела, это работает. Если базу потерять, весь журнал становится «телами без учётной записи»: automation-id пуст, наследовать слой не от чего, заголовок не подтверждает ничего — и доставки без плотных метрик не сохранятся никогда, сколько ни пересобирай. То есть «пересобираемо из архива» верно с оговоркой, которой в инварианте нет.

Prior art прямой: WARC (формат веб-архивов) хранит запрос вместе с его заголовками именно потому, что тело без метаданных запроса события не воспроизводит. Смотреть у него стоит на устройство записи «заголовки + тело» и на то, что заголовки лежат рядом текстом, а не в отдельной базе.

Развилка формы (решать при взятии, не сейчас):

  • заголовки внутрь того же .json.gz отдельным первым объектом — одна запись и одна операция, но файл перестаёт быть «телом как пришло»;
  • файл-спутник <ulid>.headers.json — тело остаётся дословным, зато на доставку два файла и два fsync, а атомарность пары надо обеспечивать самому;
  • отдельный журнал заголовков (файл на сутки, дописыванием) — дешевле всего по операциям, но появляется третья сущность.

Цена ошибки высокая: правится путь приёма, а доставка, не попавшая в архив, теряется навсегда. Значит менять надо так, чтобы старые тела без заголовков продолжали читаться.

Готово, когда пересборка на архиве, у которого рабочей базы нет вовсе, даёт то же состояние, что пересборка с базой.

Связано: docs/architecture.md → «Сырой архив и восстановление состояния», internal/replay.

Двигает строку «Завершения» цели: «Пересборка восстановима без базы: заголовки доставки лежат в архиве рядом с телом».