- каждая запись каталога задач получила тип вместо тега kind: и префикса заголовка; секция роадмапа «Разработка» стала «Сопровождением», порядок секций канонический - поправлены протухшие факты: нереализованные маршруты Read API, MCP и `healthlog import`, словарь слоёв в инварианте, семантика гейта по покрытию диффа, периметр перестал дублировать security.md - замер слияния переведён с находки 49 на находку 54, заполнены Purpose спек storage и parsing
70 lines
5.6 KiB
Markdown
70 lines
5.6 KiB
Markdown
# ✨ Назвать механизм отката релиза после наката миграции
|
|
|
|
- **Тип:** feature
|
|
- **Категория:** Инфра
|
|
- **Зачем:** Страж версии схемы делает возврат старого бинаря отказом, а понизить схему нечем — аварийный путь пришлось бы изобретать в аварии
|
|
- **Теги:** goal:deploy
|
|
|
|
**Решение принято владельцем 2026-08-02: вариант (2) — копия файла базы перед
|
|
накатом.** Entrypoint контейнера копирует файл базы рядом до старта бинаря,
|
|
откат = подмена файла. `Down`-блоки миграций при этом честно называются
|
|
декорацией для локальной разработки, а не аварийным путём: ни один из них не
|
|
исполнялся ни разу. Осталось решить при взятии — сколько копий держим и где.
|
|
Задача естественно склеивается с [деплоем](deploy-rivendell.md). Ниже —
|
|
исходная постановка блокера, она же ТЗ.
|
|
|
|
Вынуто ревью кода задачи «Дозакрыть находки ревью по слиянию сущностей»
|
|
(проходы `ops` и `negative`, профиль `deep`).
|
|
|
|
Двигает строку «Завершения» цели: «Откат релиза после наката миграции имеет названный механизм».
|
|
|
|
## Что именно решить
|
|
|
|
Та задача перенесла в `store.Open` стража версии схемы: база новее бинаря —
|
|
отказ на старте. Решение принято владельцем и здесь не пересматривается. Но у
|
|
него есть следствие, которое до сих пор нигде не было записано:
|
|
|
|
**после того как новый бинарь накатил миграцию, возврат старого бинаря приёма
|
|
не чинит.** Он теперь отказывается стартовать, а понизить схему нечем:
|
|
|
|
- подкоманды миграции у бинаря нет (`serve`, `reindex`, `healthcheck`);
|
|
- `goose` CLI в образ не кладётся;
|
|
- блоки `-- +goose Down` в миграциях написаны, но ни один тест их не исполняет,
|
|
и на рабочей базе они не выполнялись ни разу (`DROP COLUMN` в SQLite через
|
|
`modernc.org/sqlite` не проверялся вовсе);
|
|
- `restart: unless-stopped` превращает отказ в цикл перезапуска, а телефон всё
|
|
это время шлёт в закрытый порт и **не перешлёт** потом.
|
|
|
|
То есть аварийный путь придётся изобретать в момент аварии, при остановленном
|
|
приёме. Цена простоя для метрик закрывается широким и глубоким проходами
|
|
синхронизации; для `stateOfMind` не закрывается ничем — у него доставки HAE
|
|
единственный источник.
|
|
|
|
## Варианты и цена
|
|
|
|
1. **Подкоманда `healthlog migrate --down-to N`.** Цена: новая поверхность CLI
|
|
плюс тест на `Down` каждой миграции (сейчас их нет, и `DROP COLUMN` в SQLite
|
|
ведёт себя не так, как в постгресе). Зато откат становится операцией, а не
|
|
импровизацией.
|
|
2. **Копия файла базы перед накатом** — entrypoint контейнера делает `cp` рядом,
|
|
откат = подмена файла. Цена: место (база растёт), плюс правило «сколько копий
|
|
держим». Зато не требует ни кода, ни доверия к `Down`, а база производна от
|
|
архива — потеря копии не смертельна.
|
|
3. **`goose` CLI в образ.** Цена: образ перестаёт быть одним статическим
|
|
бинарём, появляется вторая точка, знающая про схему.
|
|
4. **Ничего, но записать вслух**: «понижение схемы не поддерживается, лечение —
|
|
только выкатка вперёд». Цена: в аварии выбора нет.
|
|
|
|
## Рекомендация
|
|
|
|
(2) плюс уже сделанная запись из (4). Копия файла — единственный вариант,
|
|
который не требует доверять непроверенному коду ровно в тот момент, когда
|
|
проверять некогда; а `Down`-блоки при этом честно называются декорацией для
|
|
локальной разработки.
|
|
|
|
## Что стоит, пока решения нет
|
|
|
|
Ничего: страж работает, и это правильно. Стоит только аварийный сценарий —
|
|
он существует ровно в том виде, в каком описан выше. Строка «понижение схемы не
|
|
поддерживается» уже записана в `docs/architecture.md` (раздел «Деплой»).
|