Files
crank/docs/migrations.md
T

81 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Миграции 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>` на:
```bash
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`](schemas/migration-sequence.json) и проверяется командой:
```bash
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.