Files
crank/docs/migrations.md
T

8.1 KiB
Raw Blame History

Миграции PostgreSQL

Crank использует единственную append-only migration authority в crank-registry. admin-api и mcp-server выполняют только read-only preflight. DDL применяет one-shot binary crank-migrate, который Community Compose запускает до readiness сервисов.

Безопасная последовательность оператора

Для source Compose замените <compose> на:

docker compose -f deploy/community/docker-compose.yml --env-file deploy/community/.env.example

Для image Compose используйте docker compose -f deploy/community/docker-compose.images.yml --env-file .env. Перед обновлением уже работающей установки выполните строго:

  1. Read-only preflight: <compose> run --rm migrate crank-migrate preflight. Exit 0 означает current, exit 2 — ожидаемую migration_required; exit 1 запрещает mutation до устранения причины.
  2. Создайте и проверьте согласованный backup PostgreSQL и artifact storage. Для первой пустой установки зафиксируйте, что восстанавливать нечего.
  3. Проверьте immutable plan: cargo run -p admin-api --bin crank-migrate -- plan --check в source checkout либо <compose> run --rm migrate crank-migrate plan для образа.
  4. Примените sequence: <compose> run --rm migrate crank-migrate apply.
  5. Повторите preflight и убедитесь в {"status":"current","version":3}.
  6. Только теперь запускайте long-running services: <compose> up -d.

Обычный up также содержит обязательный migration job, но при upgrade он не заменяет предварительные preflight и backup. Migrator делает до десяти bounded попыток подключения с секундной паузой и затем безопасно завершается ошибкой.

Команда читает только CRANK_DATABASE_URL/POSTGRES_*. Master key, session secret, bootstrap password, MCP credentials и другие service secrets не входят в её config projection.

Фактический brownfield inventory

Источник Исторический владелец/lock Известный контракт
__crank_core_migrations crank-registry, session lock 0x4352414e4b columns version, description, checksum, applied_at; v1 checksum crank-community-baseline-v1
__crank_mcp_migrations MCP session store, session lock 0x4352414e4b4d4350 columns version, checksum, applied_at; v1 checksum mcp-transport-sessions-v1
__crank_ext_migrations прежний RegistryExtension, без общего lock legacy columns extension_name, version, applied_at; checksum отсутствовал
__crank_migrations canonical MigrationAuthority, transaction lock 0x4352414e4b4d4947 append-only sequence с version/name/checksum/phase/compatibility
__crank_migration_legacy_audit canonical MigrationAuthority только доказуемо сопоставленное legacy provenance

Legacy extension row без зарегистрированного exact (name, version, checksum) несовместим. Community пока не публиковала extension migrations, поэтому authority не выдумывает им checksum и блокирует такие строки с legacy_conflict.

Контракт sequence

Machine plan находится в schemas/migration-sequence.json и проверяется командой:

cargo run -p admin-api --bin crank-migrate -- plan --check
  • V1 — immutable brownfield baseline с историческим ledger token и отдельным exact-source SHA-256.
  • V2 — единый exact-byte expand SQL artifact, создающий canonical ledgers и MCP session schema; его SHA-256 закреплён в executable descriptor.
  • V3 — append-only expand для независимого nullable invocation_logs.trace_id, canonical-format constraint и partial request/trace indexes; исторические строки остаются NULL без fabricated backfill.
  • Каждая версия имеет contiguous i64 version, стабильное имя, lowercase SHA-256, owner, phase, explicit readable schema min/max и backfill policy.
  • migrate требует bounded cursor/batch policy; contract дополнительно требует tracked compatibility evidence и закрытого окна.
  • Добавление descriptor без executable implementation блокируется invalid_contract до DB I/O.

Legacy ledgers остаются readable. Down migration, destructive automatic rollback, ledger rewrite, --force и arbitrary SQL/path input отсутствуют. Полная N/N-1 upgrade/rollback qualification остаётся Story 7.2.

Диагностика и восстановление

CLI/stderr возвращают bounded JSON: code, stage, nullable numeric version, recovery. Database URL, credentials, raw SQL/driver body, row values и host paths не выводятся.

Code Значение Безопасное действие
schema_missing Service startup увидел пустую schema Запустить controlled migration; не разрешать runtime DDL
migration_required Schema отстаёт; preflight CLI завершает работу с exit 2 Проверить backup и выполнить controlled apply
checksum_mismatch Artifact и ledger не совпали Сначала проверить immutable application image/release manifest; восстанавливать БД только после доказанной ledger corruption
partial_sequence Relation/ledger/structural fingerprint неполон Не чинить вручную; сопоставить backup и matching artifact
future_version База новее приложения Установить matching application; не откатывать schema автоматически
legacy_conflict Legacy provenance невозможно доказать Сохранить backup и привлечь оператора
lock_timeout Другой migration runner удерживает canonical lock Дождаться завершения и повторить preflight
apply_failed Transaction migration откатилась Проверить matching artifact/backup, затем повторить preflight
storage_unavailable PostgreSQL/transport недоступен Проверить сеть/TLS/права; секреты в diagnostic не копировать
config_invalid Database-only config невалиден Исправить указанный config contract
invalid_command Неизвестная CLI команда/аргумент Использовать только plan, preflight, apply
contract_drift Committed machine plan расходится с Rust authority Перегенерировать только для новой append-only version и проверить diff
invalid_contract Descriptor/implementation/window/evidence несовместимы Исправить authoring contract до любого DB I/O

Правила разработчика

  • DDL, SQL migration assets и canonical advisory lock разрешены только в crank-registry::migrations.
  • Schema развивается expand → bounded/resumable migrate → evidence-gated contract.
  • Опубликованные source bytes/checksums не редактируются: добавляется новая version.
  • Для каждой version обязательны fresh/current/concurrent/corrupt/rollback/data-preservation tests и explicit Community scope scan.