7.0 KiB
BRD — ORCH-058: Self-deploy retag берёт устаревший staging-образ (риск тихого регресса)
Work Item ID: ORCH-058
Тип: bug / техдолг инфраструктуры self-deploy
Источник: docs/history/LESSONS_ORCH-036-selfdeploy.md п.4 (самый опасный из 4 багов bootstrap ORCH-36)
1. Контекст
ORCH-36 сделал стадию deploy исполняемой для self-hosting репозитория orchestrator:
- Phase B (
src/self_deploy.py::build_deploy_command) запускает детачед host-хукscripts/orchestrator-deploy-hook.shс параметромSOURCE_IMAGE=orchestrator-orchestrator-staging. - Хук (шаг 2b, BUILD-ONCE, ORCH-36 BR-6) делает
docker tag $SOURCE_IMAGE → $TARGET_IMAGEбезdocker build— «прод получает ровно тот артефакт, что прошёл staging».
Дизайн-предпосылка BUILD-ONCE: staging-образ свеж и провалидирован. На практике этой гарантии НЕТ.
2. Проблема (корень)
Конвейер нигде не пересобирает образ orchestrator-orchestrator-staging из текущего
кода (HEAD main / провалидированной ветки):
- Стадия
deploy-stagingзапускает толькоscripts/staging_check.py(e2e-проверка) против уже работающего контейнераorchestrator-staging(8501) — что бы в нём ни крутилось. Сборка staging-образа — ручная операция (STAGING.md / ORCH-34), вне конвейера. - Между «образ собран» и «retag в прод» нет провенанс-связи с провалидированным коммитом.
Следствие (инцидент ORCH-36): staging-образ не пересобрали из нового main →
staging_check прошёл против СТАРОГО кода → BUILD-ONCE retag промоутнул СТАРЫЙ образ в прод.
Деплой «зелёный» (result=0, health ok), но прод молча откатился на код 2-дневной давности:
пропал deploy-finalizer → задача не закрылась → бесконечная петля Phase B.
3. Почему это критично
Это самый опасный из четырёх багов self-deploy: он не падает, а тихо откатывает прод. Зелёный гейт = ложный позитив. Орк обслуживает все проекты (enduro-trails) из одного прод-инстанса → тихий регресс инструмента = групповой инцидент для всех проектов.
Текущая защита (staging-гейт, merge-gate, health-check хука) НЕ ловит этот класс: все они зелёные, потому что проверяют не тот артефакт, что уезжает в прод.
4. Бизнес-цель
Гарантировать инвариант: в прод никогда не промоутится образ, не собранный из провалидированного для данной задачи коммита; при невозможности это доказать — деплой fail-fast (вердикт FAILED → откат на development), а не «тихо зелёный».
5. Объём (scope)
В объёме:
- Привязка артефакта (staging-образ → прод-retag) к провалидированному коммиту.
- Fail-fast при рассинхроне образа и кода (никаких тихих промоутов устаревшего).
- Условность как ORCH-35/36/43: реально только для
orchestrator; прочие репо — no-op / прежнее поведение. - Контракт never-raise и fail-closed (на сомнении — не деплоить).
Вне объёма:
- Полный авто-approve прод-деплоя (ORCH-54).
- Изменение exit-code-контракта хука (0/1/2) и реестров
STAGE_TRANSITIONS/QG_CHECKSкак набора стадий. - Миграции схемы БД.
- Деплой/рестарт прод-контейнера
orchestrator(8500) в рамках задачи.
6. Бизнес-требования (BR)
- BR-1. Образ, который BUILD-ONCE retag промоутит в прод, ДОЛЖЕН соответствовать коду,
провалидированному стадией
deploy-stagingдля данной задачи (тот же git-коммит). - BR-2. Если соответствие НЕ доказуемо (staging-образ собран не из провалидированного
коммита, либо провенанс невозможно прочесть) — деплой ОБЯЗАН fail-fast: вердикт
FAILED, штатный откат наdevelopment(контракт БАГ-8), без рестарта прода. - BR-3.
staging_check.py(e2e-валидация) ДОЛЖЕН прогоняться против артефакта, соответствующего тому же провалидированному коммиту, что уедет в прод (нельзя валидировать один образ, а катить другой). - BR-4. Поведение условно: реально для
orchestrator; для прочих репозиториев — no-op / без регрессий прежнего синхронного деплоя. - BR-5. Выбранное решение НЕ должно приводить к вечной блокировке деплоя (если механизм свежести отсутствует — нужен путь, который доводит до зелёного, а не fail-fast'ит навсегда).
- BR-6. Контракт never-raise: сбой проверки свежести/провенанса не должен валить stage_engine; на любом сомнении — fail-closed (трактуем как несоответствие).
- BR-7. Документация-голден-сорс: INFRA / DEPLOY_HOOK / STAGING / architecture README + CHANGELOG обновляются в том же PR; решение оформляется ADR.
7. Связанные материалы
docs/history/LESSONS_ORCH-036-selfdeploy.md(п.4 — корень)docs/architecture/adr/adr-0007-executable-self-deploy.md,docs/work-items/ORCH-036/06-adr/ADR-001-executable-self-deploy.mdsrc/self_deploy.py,scripts/orchestrator-deploy-hook.sh,src/config.pydocs/operations/STAGING.md,docs/operations/DEPLOY_HOOK.md,docs/operations/INFRA.md