Тема
config.db v3 — migration, rehearsal и rollback
Этот runbook не является разрешением на VPS mutation. Production cutover выполняется только после отдельного подтверждения оператора и только через scripts/deploy-vps.sh; ручной rsync/build/restart запрещён.
1. Offline rehearsal на production-shaped копии
Остановить writer копии и сделать SQLite-consistent snapshot (
VACUUM INTOлибо.backup), не копировать живые-wal/-shmкак обычные файлы.Записать до миграции:
sha256sum, размер, owner/mode, schema version,PRAGMA integrity_check, список строк (id,label,type,enabled) и JSON validity. Копия обязана содержать current engine row, disabled invalid legacy row и большойstrategy_audit.На отдельной рабочей копии запустить новый CLI read path.
open()сначала создаёт<config.db>.pre-v3.bak, затем одной транзакцией создаёт v3 и snapshots. Прервать один пробный процесс до commit и повторить: исходная v2 DB должна остаться открываемой, backup — неизменным, повтор — идемпотентным.Проверить:
sqlPRAGMA foreign_keys; PRAGMA integrity_check; SELECT value FROM schema_meta WHERE key='schema_version'; SELECT s.id,s.label,s.latest_config_version,s.published_config_version, v.version,v.validation_state,v.origin,v.content_sha256 FROM strategies s JOIN strategy_config_versions v ON v.strategy_id=s.id ORDER BY s.id,v.version;Ожидается v3,
latest=published=1, ровно один migration snapshot на старую строку, отсутствие реконструкции из audit и 64 lower-hex символа hash.Прогнать новый engine startup на копии с production selectors/ключами, но изолированными network/order endpoints. Именно engine-owned typed opener выполняет миграцию: выбранная валидная строка становится
validv1 с текущим contract fingerprint и сообщает stable label + version 1 + тот же hash; disabled invalid legacy остаётсяlegacy_unvalidatedи не публикуется. Storage-only opener без typed validator обязан отказать.Создать draft v2, выполнить nonzero-order
replay --config-version 2, затем replay без номера (published v1). В обоих отчётах проверить version/hash; published pointer после draft replay остаётся 1.Rollback drill: остановить новые процессы, отложить v3 DB и sidecars, восстановить точный
.pre-v3.bak, сверить исходный SHA-256/integrity/schema и запустить соответствующий старый binary на копии. Новый v3 DB старому binary не передавать.
2. Production preflight — только drained и flat
- Зафиксировать текущие image/binary digests и путь instance.
- Остановить создание config versions. Перевести engine в drain, отменить открытые BUY, дождаться durable
open_orders=0иactive_positions=0. - Сделать SQLite-consistent backup и сохранить SHA-256, owner/mode и
PRAGMA integrity_check. Не продолжать при любом расхождении. - Убедиться, что rehearsal выше и все Rust/frontend gates зелёные.
3. Cutover и smoke
- Выполнить только утверждённую цель
scripts/deploy-vps.sh, поставляющую совместимые engine/dashboard/CLI/SPA вместе. - Проверить v3 SQL-инварианты из §1 и projection parity.
- Запустить version-pinned nonzero replay опубликованной версии; version/hash отчёта должны совпасть с DB.
- Выполнить контролируемый engine restart после drain/flat. В
/api/local/seedпроверитьsession.strategy,config_versionиconfig_content_sha256; dashboard должен показатьloaded=publishedбез pending-restart. - Проверить, что legacy PUT без CAS/mode получает 409, draft не меняет projection, enable/disable не создаёт config version.
4. Rollback — DB и binary являются одной парой
- Немедленно остановить новые engine и dashboard writers.
- Не открывать v3 старым бинарём. Отложить v3 DB и
-wal/-shmс UTC marker. - Восстановить exact pre-v3 backup, owner/mode и сверить сохранённый hash +
integrity_check+ schema v2. - Вернуть matching old binaries только штатным deploy script, затем выполнить обычный smoke и проверить selectors/flat state.
- Сохранить отложенную v3 DB для форензики; не «чинить» её ручным UPDATE.