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

127 lines
11 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.
# ТЗ — 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.