Files
healthlog/docs/tasks/items/delivery-headers-in-archive.md
T
av d33f37249c docs: документация переведена на канон av-dev-pm 3
- роадмап отвечает «что умеет и чего не умеет»: PLAN.md → ROADMAP.md, четыре
  канонические секции, достигнутые звенья строками в «Готово», цели
  переформулированы возможностями приложения
- задачи: род работы и «Затрагивает» набору спринта, 34 заголовка в форму
  действия, «Завершение» целей перечнями со ссылкой из каждой задачи
- вычитка проходами task-form и doc-wording, починены протухшие факты в README,
  паспорте и review.md
2026-08-04 20:48:30 +03:00

45 lines
3.8 KiB
Markdown

# Класть заголовки доставки в архив рядом с телом
- **Секция:** Ядро
- **Зачем:** Заголовки живут только в базе — потеря базы навсегда ломает вывод слоя при пересборке
- **Теги:** 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`.
Двигает строку «Завершения» цели: «Пересборка восстановима без базы: заголовки доставки лежат в архиве рядом с телом».