Files
orchestrator/docs/work-items/ORCH-058/01-brd.md
claude-bot 282636fedb
All checks were successful
CI / test (push) Successful in 16s
analyst(ET): auto-commit from analyst run_id=262
2026-06-07 07:06:10 +00:00

7.0 KiB
Raw Permalink Blame History

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-образ не пересобрали из нового mainstaging_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.md
  • src/self_deploy.py, scripts/orchestrator-deploy-hook.sh, src/config.py
  • docs/operations/STAGING.md, docs/operations/DEPLOY_HOOK.md, docs/operations/INFRA.md