reindex: пересборка витрины проигрыванием журнала
- `healthlog reindex` собирает витрину из журнала (тела архива + учёт доставок) в ОТДЕЛЬНЫЙ файл базы, строго по `(received_at, id)`; рабочую базу читает без наката миграций и не трогает вовсе. Подмену делает человек при остановленном сервисе: переименование поверх открытого дескриптора портит базу молча. - Журналом считается архив, а не таблица доставок: тело без учётной записи заводится заново (метка из ULID, размер и хеш по распакованному телу), запись без тела переносится, но не сворачивается. Оракул сходимости встроен — два отпечатка и «объектов было/стало»; пустой журнал успехом не считается. - Прогон живого архива переехал на новый пакет: второго проигрывателя журнала в проекте не осталось, а его утверждение о ключе сна перестало быть константой, протухающей с каждой доставкой.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
## 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`.
|
||||
Reference in New Issue
Block a user