Files
orchestrator/docs/work-items/ORCH-058/02-trz.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

11 KiB
Raw Permalink Blame History

ТЗ — ORCH-058: провенанс staging-образа перед BUILD-ONCE retag в прод

Work Item ID: ORCH-058

Примечание: ТЗ фиксирует ТРЕБУЕМЫЕ изменения и точки в коде. Выбор стратегии (пересборка из HEAD main ПЕРЕД валидацией vs. fail-fast по провенансу образа, либо их комбинация) — решение архитектора (ADR в 06-adr/). Ниже перечислены точки касания для обеих стратегий; архитектор выбирает и при необходимости сужает.

1. Инвариант, который нужно обеспечить

INV-FRESH: образ, передаваемый хуку как SOURCE_IMAGE для BUILD-ONCE retag в прод, собран из ТОГО ЖЕ git-коммита, что прошёл deploy-staging для этой задачи. Если это недоказуемо — деплой fail-fast (deploy_status: FAILED → откат на development, БАГ-8), прод не трогается.

Якорь «провалидированного коммита» (architect фиксирует точно в ADR): SHA HEAD ветки задачи после merge-gate rebase на origin/main (то, что валидировал deploy-staging + merge-gate).

2. Текущее поведение (что чинить)

Место Сейчас Проблема
scripts/orchestrator-deploy-hook.sh шаг 2b docker tag $SOURCE_IMAGE → $TARGET_IMAGE без проверки происхождения образа промоутит любой образ под именем orchestrator-orchestrator-staging, даже устаревший
Стадия deploy-staging (.openclaw/agents/deployer.md + staging_check.py) гоняет e2e против уже запущенного 8501, не пересобирая образ валидирует не тот артефакт, что уедет в прод
src/self_deploy.py::build_deploy_command передаёт SOURCE_IMAGE, TARGET_*, COMPOSE_PROFILE, PREV_IMAGE_FILE; провенанс/SHA не передаёт хук не знает, какой коммит ожидать
Dockerfile без OCI-лейбла revision/git-SHA у образа нет машиночитаемого происхождения для проверки

3. Задействованные модули src/ и файлы

  • src/self_deploy.py — основной (provenance-helpers + проброс ожидаемого SHA в команду хука).
  • src/config.py — новые настройки (ORCH_-префикс обязателен, урок ORCH-36 п.2).
  • scripts/orchestrator-deploy-hook.sh — fail-fast по провенансу и/или пересборка перед retag.
  • Dockerfile — лейбл происхождения образа (для стратегии «провенанс по labels/sha»).
  • src/qg/checks.py — опц. новый детерминированный под-чек свежести (если стратегия «гейт»).
  • src/stage_engine.py — опц. точка вызова под-чека на ребре deploy-staging → deploy (рядом с merge-gate, строки ~262288). Реестр STAGE_TRANSITIONS не меняется.
  • .openclaw/agents/deployer.md — шаги стадии deploy-staging (если выбран rebuild-перед-валидацией).
  • docker-compose.yml — опц. build-args/labels для staging-сервиса (если стратегия rebuild).

4. Требуемые изменения — стратегия A (пересборка из HEAD main перед валидацией)

A1. Перед прогоном staging_check.py стадия deploy-staging для orchestrator пересобирает образ orchestrator-orchestrator-staging из провалидированного коммита (worktree ветки после merge-gate rebase) и пересоздаёт контейнер 8501 на свежем образе. A2. staging_check.py гоняется против свежего контейнера; на SUCCESS ровно ЭТОТ образ становится SOURCE_IMAGE для прод-retag (loop closed). A3. Детерминированно (без LLM в критическом пути): сборку/recreate выполняет код стадии или host-хук в staging-режиме, не агент-деплойер «руками». A4. Безопасность: операция трогает ТОЛЬКО staging (8501), НИКОГДА прод (8500).

5. Требуемые изменения — стратегия B (fail-fast по провенансу образа)

B1. Dockerfile: добавить лейбл происхождения, напр. LABEL org.opencontainers.image.revision=$GIT_SHA через ARG GIT_SHA (build-arg). B2. Сборка staging-образа (ручная или из стратегии A) проставляет GIT_SHA = коммит сборки. B3. src/self_deploy.py::build_deploy_command: вычислить ожидаемый SHA провалидированного коммита и пробросить в команду хука новым env (напр. EXPECTED_REVISION=<sha>). Новый pure-helper, напр. expected_revision(repo, branch) -> str (never-raise). B4. scripts/orchestrator-deploy-hook.sh шаг 2b: ПЕРЕД docker tag прочитать лейбл $SOURCE_IMAGE (docker image inspect --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}') и сравнить с $EXPECTED_REVISION. Несовпадение / пустой лейбл / пустой ожидаемый SHA → log + exit 1 (fail-fast). Поведение обратносовместимо: при незаданном EXPECTED_REVISION — текущее поведение (без проверки), чтобы не сломать не-self репо. B5. exit 1 хука уже маппится map_exit_code_to_status → FAILED (контракт не меняется), Phase C пишет 14-deploy-log.md deploy_status: FAILED → откат на development (БАГ-8).

6. Требуемые изменения — опц. под-гейт (если архитектор выберет gate-side для B)

  • Новый детерминированный (без LLM) под-чек, напр. check_staging_image_fresh, по образцу check_branch_mergeable (ORCH-043): pure verdict-logic + условность (self_deploy_applies / is_self_hosting_repo), never-raise, для прочих репо → (True, "N/A").
  • Вызов на ребре deploy-staging → deploy ПЕРЕД Phase A (рядом с merge-gate, stage_engine ~268288). FAIL → откат на development (как merge-gate). Реестр стадий неизменен — это под-гейт ребра, не новая стадия.
  • Если выбран чисто хуковый fail-fast (раздел 5) — под-гейт не нужен.

7. Изменения API

Нет. Эндпоинты (/health, /status, /queue, /webhook/*) не меняются. Опц.: в снимок GET /queue можно добавить диагностическое поле о свежести образа — НЕ обязательно.

8. Изменения схемы БД

Нет. Состояние deploy — sentinel-файлы (.deploy-state-<repo>/<wi>/, ORCH-36). Миграции запрещены (как ORCH-36/43/53).

9. Конфигурация (src/config.py, ВСЕ с префиксом ORCH_)

Кандидаты (architect финализирует имена и дефолты):

  • image_freshness_enabled: bool = True — kill-switch проверки (поэтапный раскат).
  • image_freshness_repos: str = "" — CSV; пусто → только self-hosting (как self_deploy_repos).
  • (для стратегии B) проброс EXPECTED_REVISION строится в build_deploy_command, отдельной настройки может не требоваться.
  • (для стратегии A) при необходимости — имя/тег staging-образа уже есть (deploy_prod_source_image).

Урок ORCH-36 п.2: любая настройка, читаемая pydantic Settings, ОБЯЗАНА иметь префикс ORCH_.

10. Новые QG checks (если применимо)

  • Опц. check_staging_image_fresh (см. §6) — добавить в реестр QG_CHECKS и в snapshot-тест реестра (tests/test_qg_registry_snapshot.py). Только если выбран gate-side.

11. Артефакты pipeline (создать/обновить В ТОМ ЖЕ PR)

  • 06-adr/ADR-001-<slug>.md — выбор стратегии (A / B / A+B), якорь «провалидированного коммита», точки fail-fast, условность, never-raise, отсутствие deadlock (BR-5).
  • docs/operations/DEPLOY_HOOK.md — описание провенанс-проверки / пересборки и новых env.
  • docs/operations/STAGING.md — как и когда пересобирается staging-образ в конвейере.
  • docs/operations/INFRA.md — обновить топологию/риск self-deploy (закрыт п.4 каскада).
  • docs/architecture/README.md — секция ORCH-36/58 (свежесть артефакта в BUILD-ONCE).
  • CHANGELOG.md — запись ORCH-058.
  • При выборе стратегии A: bootstrap-чеклист (урок ORCH-36 «сквозной»: реальный staging-прогон до мержа).

12. Инварианты / ограничения (self-hosting safety)

  • Никогда не рестартовать/ронять прод 8500 в рамках задачи (CLAUDE.md). Любая сборка/recreate — только staging 8501.
  • Никогда не пушить/форс-пушить main (как merge-gate).
  • Контракты НЕ меняются: exit-code хука (0/1/2), map_exit_code_to_status, check_deploy_status/_parse_deploy_status, БАГ-8 rollback, terminal-sync, merge-gate.
  • Fail-closed: на любом сомнении (нет лейбла, нет ожидаемого SHA, ошибка inspect) — трактовать как несоответствие → FAILED, никогда не промоутить «на авось».
  • never-raise: helpers и под-чек не должны пробрасывать исключение в stage_engine.