## Why Разбор пишется по реальным данным и будет ошибаться — это норма. Без пересборки ошибка разбора становится потерей данных: исправленный код не применится к тому, что уже разобрано неверно, а точки из объекта не удаляются никогда. Сегодня журнал есть (116 тел в архиве), а кода, который его проигрывает, нет: после миграции 00005 доставки числятся `pending`, и подобрать их некому. Оговорка, которую легко прочитать наоборот: пересборка точнее приёма **не тем, что видит более длинный ряд**. Слой обязан быть функцией префикса журнала, и наследование «от последней доставки вообще» уже ловили дефектом — 1737 объектов против 1742. Точнее она ровно тем, что применяет **исправленный** разбор к тому, что уже разобрано неверно. ## What Changes - Новая подкоманда `healthlog reindex`: собирает витрину из журнала — `import(снапшот) + replay(доставки по received_at)` — и пишет её в **отдельный файл базы**, не трогая рабочую. Снапшот в этой дельте пуст: `import` появится вместе с задачей про родной экспорт Apple, и та встроится сюда же, а не заведёт вторую операцию. - Журналом считается **архив**, а не таблица доставок: тела, у которых учётной записи нет (приём успел записать тело и упал на вставке строки), заводятся заново по имени файла. Это обещание, уже записанное в `internal/ingest`. - Порядок проигрывания — строго `(received_at, id)`, а не порядок обхода каталога: слой наследуется от предшествующей доставки той же автоматизации, и порядок входит в результат. - Оракул сходимости встроен в команду: отпечаток пересобранной витрины печатается рядом с отпечатком рабочей, и команда прямо говорит, совпали они или нет. Отпечаток значений точек не раскрывает. - Подмена рабочей базы пересобранной **остаётся за человеком** и в команду не входит: сервис держит открытый дескриптор, и `rename` поверх него оставил бы процесс писать в отвязанный inode — молча. - Границы, названные вслух: `sealed` в пересобранной витрине пуст (правила его выставления ещё нет), а заголовки доставок берутся из рабочей базы — в архиве их нет вовсе. - Прогон живого архива (`task verify:archive`) переезжает на новый код: сегодня он **второй проигрыватель журнала** со своим порядком и своим синтезом учёта, и после появления настоящей пересборки зеленел бы, проверяя путь, которым команда не ходит. ## Capabilities ### New Capabilities - `reindex`: пересборка витрины проигрыванием журнала — состав журнала, порядок, детерминированность, отчёт и его оракул, граница «что не восстанавливается». ### Modified Capabilities Изменённых нет. Правило «тело без учётной записи заводится заново» могло бы показаться правилом учёта, но оно описывает состав журнала при проигрывании и живёт в `reindex`; дублировать его в `storage` значило бы завести два места, где сказано одно и то же. Схема БД, слияние точек и вывод слоя не меняются: вся дельта — новый потребитель существующей свёртки. ## Impact - Новый пакет `internal/replay` — проигрывание журнала поверх существующего `internal/fold`; собственного разбора и собственного слияния не заводит. - Новый файл `cmd/healthlog/reindex.go`, строка в `main.go`. - `internal/store`: перечисление доставок в порядке журнала, очистка витрины, чтение отпечатка (уже есть). - `internal/ident`: время создания из ULID — метка приёма для тела без учётной записи. - Схема БД не меняется, миграций нет. - `README.md` (`reindex` перестаёт быть «в планах»), `docs/architecture.md` (почему подмена базы не автоматизируется), `docs/plan.md`, `docs/backlog`.