Проблема плана миграции в том, что он часто начинается с красивой целевой схемы и заканчивается словом «cutover». Между ними исчезают инвентарь, владелец маршрута, перевод трафика, состояние записей и решение об откате. Цена такого пропуска не абстрактный риск: в момент сбоя нельзя быстро ответить, что именно вернуть, кто принимает решение и какие новые записи уже нельзя трактовать как прежние. Архитектура остаётся на доске, а переход превращается в спор о памяти участников.
Рабочая альтернатива — не общий список шагов, а маленькая decision-gated карточка. Каждая фаза принимает named fixed synthetic literal, добавляет один проверяемый факт и либо отдаёт точный stop reason, либо делает возможным только synthetic-migration-review-hand-off. Это не разрешение начать, продолжить или завершить миграцию. Это дисциплина описания: следующий вопрос нельзя открыть, пока текущая граница не названа.
Начать не с цели, а с карты того, что переходит
Целевая архитектура отвечает «куда». Migration card обязана сначала ответить «что сейчас связано». В учебном literal есть один route route-ledger-read, один owner, один record и две зависимые границы. Такой масштаб намеренно мал. Он не представляет репозиторий или сервис. Зато на нём видно правило: route без владельца и dependency — это не неполная таблица, а невозможность ответственно определить последствия перехода.
Инвентарь не должен изображать каталог файлов. Для перехода достаточно четырёх типов связей: входной route, запись или ресурс, читатель и писатель, внешняя зависимость. Если route обращается к record, но не известно, кто формирует запись, план не умеет описать data transition. Если известна запись, но нет читателя, нельзя формулировать evidence о совместимости. Стоп здесь экономит самый дорогой вид работы: позднее обнаружение обязательной связи внутри окна изменений.
| Фаза | Вход | Проверяемое условие | Точный отказ |
|---|---|---|---|
| inventory | route, owner, record, dependency | все имена связаны | stop-missing-inventory |
| data state | copy, reconciliation, restore state | состояние обратимо в модели | stop-irreversible-data-state |
| traffic slice | control, candidate, window | маршрут и сравнение названы | stop-unbounded-traffic-slice |
| rollback | trigger, owner, traffic/data return | решение воспроизводимо | stop-unnamed-rollback-trigger |
| review | полная карточка | вывод ограничен hand-off | stop-disallowed-positive-result |
Фаза data не равна слову «копия»
Запись copy-complete говорит только о том, что в модели есть копия. Она не говорит, как вернуть дальнейшие записи, чем сверять границы и куда должен вернуться write state. Поэтому accepted literal требует copy-verified-reversible, named reconciliation и named restore state. Это не рецепт для конкретной базы данных. Это минимальная форма вопроса, который не позволяет выдать перенос байтов за обратимый переход данных.
Особенно опасна подмена: «трафик можно направить назад, значит rollback есть». Для read-only примера она может выглядеть правдоподобно, но в модели записи трафик и данные — разные оси. Возврат control route не отменяет новых записей и не создаёт их обратного преобразования. Kubernetes Documentation о Deployment полезна здесь именно как граница: rollback его revision относится к Pod template. Из этого не следует, что он отменяет эффект данных, внешний контракт или любой иной transition.
Срез трафика требует контрольной стороны
Десять процентов candidate без control boundary — это число без вопроса. Нельзя понять, с чем его сопоставлять, какой маршрут остался прежним и одинаково ли определены условия наблюдения. В fixed record control и candidate имеют один и тот же route id, разные shares и один named observation window. Эти числа не изображают настоящий балансировщик и не выражают совет о долях. Они делают сравнение типизированным: у наблюдения есть две стороны, а не только интересный новый путь.
Наблюдаемость в карточке тоже не телеметрия. fixed-error-ratio и fixed-contract-mismatch — имена полей literal, не метрики системы. Их задача — не доказать здоровье, а не позволить написать «посмотрим внимательно». Когда окно и критерий не названы, проверка возвращает stop-unbounded-traffic-slice. Такой отказ полезнее зелёной галочки: он указывает ровно на отсутствующую control boundary.
Исполняемая карточка фаз
import { createFixedMigrationRecord, reviewFixedMigrationPlaybook } from './upgrade-2026-07.mjs';
const record = createFixedMigrationRecord('fixed-migration-ready-v1');
const result = reviewFixedMigrationPlaybook(record);
console.log({ status: result.status, route: result.transition.inventory.routeId, recovery: result.transition.data.restoreState });
// { status: 'synthetic-migration-review-hand-off', route: 'route-ledger-read', recovery: 'fixed-source-write-resume-v1' }
Пример буквально читает immutable teaching object в памяти Node. Он не делает DNS change, не открывает соединение, не копирует record и не запрашивает метрики. Даже положительный status несёт effect: no-system-change. Это важнее красивого имени функции: reader должен видеть в данных тот же запрет, который сформулирован в тексте. Code проверяет полноту модели, а не готовность среды.
Rollback — отдельное решение, не хвост списка
У rollback есть четыре собственных имени: trigger, условие, return state трафика и return state данных; рядом стоит decision owner. Формулировка «при проблеме вернём назад» не содержит ни одной из них. Она не определяет, какая проблема достаточна, что именно возвращается и кто может различить fix-forward от возврата. Fixed trigger fixed-contract-mismatch-is-present-in-window узок специально: он не притворяется универсальным сигналом.
Google SRE Book описывает каскадный отказ как рост сбоя из положительной обратной связи. Из этого текста здесь берётся не production-вывод и не порог для команды, а инженерская осторожность: поздняя, расплывчатая реакция усиливает неопределённость. В учебной карте named trigger обрывает риторику «подождём ещё немного». Он позволяет фиксировать, что именно отсутствует или что именно переводится в stop state, не назначая действие в реальной среде.
Последовательность, которую можно рецензировать
- Выбрать один named route и связать с ним owner, record, reader, writer и dependency; при пустом звене завершить review статусом stop-missing-inventory.
- Назвать data transition, reconciliation и restore state; не считать copy достаточным доказательством обратимости.
- Сформировать control и candidate с одинаковым route boundary, а затем назвать observation window и его поля.
- Записать trigger, condition, owner и оба return states; определить только форму stop, не действие в окружении.
- Проверить, что positive status остаётся synthetic hand-off, а открытый вопрос и effect остаются видимы.
Язык ворот должен быть точнее цели
RFC 2119 различает обязательность словом MUST и возможность словом MAY. В migration card это полезно не для игры в нормативность, а для редакторской проверки. «Нужно иметь rollback» слишком расплывчато. «Для hand-off MUST быть named trigger» можно проверить на поле literal. В то же время нельзя писать «система обязана перейти»: package не видит систему. Требование относится только к данным учебной карточки и должно завершаться механически видимым reason.
У каждой фазы своя ответственность. Автор карточки не подтверждает фактическое состояние сервисов; он отвечает, что имена не скрывают разные сущности. Рецензент инвентаря ищет отсутствующую связь. Рецензент перехода смотрит на control/candidate и data recovery. Рецензент решения следит, чтобы сильный глагол не вылез за evidence. Разделение ролей не создаёт бюрократию: оно не даёт одному «готово» заменить три разных вопроса.
Пределы модели и следующий шаг
Этот playbook не измеряет задержку, не знает фактические схемы, не моделирует конкурентные записи и не валидирует deployment. Он не предлагает процент rollout, способ репликации или protocol rollback. Даже source о Kubernetes не делает package Kubernetes migration plan. Ограничение честное: fixed literals учат сохранять связи между решением и evidence, но не заменяют discovery, rehearsal или инженерное согласование в реальном контексте.
Следующий безопасный шаг — добавить один новый fixed counterexample, например route с двумя records или recovery state, который не соответствует transition. Затем снова выполнить public export и проверить точный stop reason. Не расширять accepted result до разрешения, не придумывать реальные показатели и не достраивать скрытый inventory. Хороший migration plan растёт по наблюдаемым связям, а не по объёму диаграммы.
Проверяемые источники
- Kubernetes Documentation: Deployments — версия: Kubernetes v1.33 versioned documentation snapshot, 23 April 2025. Использован только узкий факт: revision и rollback Deployment относятся к Pod template, поэтому они не являются доказательством обратимости данных. Граница: Не доказывает поведение конкретного кластера, rollout, data transition или rollback.
- Google SRE Book: Addressing Cascading Failures — версия: Wayback immutable capture, 23 January 2025 16:42:19 UTC. Использована только идея положительной обратной связи у каскадного отказа как аргумент называть stop condition заранее. Граница: Не задаёт пороги, SLO, нагрузку или свойства учебного literal.
- RFC 2119: Key words for use in RFCs to Indicate Requirement Levels — версия: RFC 2119, March 1997, immutable RFC text. Использовано определение требований MUST/MAY для различения проверяемого gate и необоснованного приказа среде. Граница: Не превращает synthetic правила в внешний стандарт миграции.