11 KiB
ТЗ — ORCH-071: Верификация merge-в-main как условие done
Документ фиксирует ТРЕБОВАНИЯ к изменениям (WHAT). Конкретный дизайн (HOW: новый leaf-модуль vs расширение существующего, где разместить шаг merge, формат sentinel'ов) — за архитектором (ADR
06-adr/). ТЗ задаёт инварианты, точки врезки и контракты, которые дизайн обязан удовлетворить.
0. Резюме root cause (вход для дизайна)
Для self-hosting (orchestrator) стадия deploy идёт детерминированным путём
_handle_self_deploy_phase_b → initiate_deploy → run_deploy_finalizer, который
не содержит шага merge PR в main (merge делает только LLM-deployer, не
запускаемый на self-hosting). done достигается по deploy_status: SUCCESS без
верификации main. Требуется: (A) выполнить/докатить merge в main детерминированно
до перехода в done; (B) верифицировать факт merge ПОСЛЕ деплоя; (C) запретить
done без подтверждённого merge.
1. Задействованные модули src/
| Модуль | Роль в фиксе | Характер изменения |
|---|---|---|
src/stage_engine.py |
run_deploy_finalizer (Phase C), терминал-блок next_stage == "done", _handle_self_deploy_phase_b |
Врезка шага merge-в-main + пост-merge верификация; блокировка перехода в done при неподтверждённом merge. |
src/merge_gate.py |
Уже содержит pr_already_merged (ORCH-065, read-only guard) |
Добавить детерминированный merge-актор для self-hosting (выполнить merge PR через Gitea API) + helper верификации «SHA предок origin/main». Опора на существующие pid_alive/reclaim_stale_lease. |
src/self_deploy.py |
Sentinel-state Phase A/B/C | Возможный новый sentinel-маркер merged (restart-safe), если дизайн выносит merge в отдельный переживающий рестарт шаг (G3). |
src/qg/checks.py |
Реестр QG_CHECKS, check_deploy_status |
Возможный новый под-чек верификации merge (например check_merged_to_main) ЛИБО усиление условия перехода deploy→done. check_deploy_status НЕ менять по контракту парсинга. |
src/config.py |
Флаги | Новый kill-switch (напр. merge_verify_enabled / merge_verify_repos), таймауты merge/verify. Дефолт — область self-hosting (как ORCH-35/43/58). |
.openclaw/agents/deployer.md |
Промпт deployer'а (non-self merge) | Уточнить: для self-hosting merge выполняет детерминированный код; non-self путь без изменений. |
src/main.py (/queue) |
Наблюдаемость | Опционально: блок/счётчики верификации merge (merge_verified_total, not_merged_alerts_total). |
2. Функциональные требования
FR-1 (G3) — Детерминированный merge-в-main для self-hosting
- Для self-hosting репо merge PR ветки в
mainДОЛЖЕН выполняться детерминированным кодом (не LLM-агентом), т.к.deployer-агент на self-hostingdeployне запускается. - Merge выполняется через Gitea PR-merge API (как сегодня делает агент), НИКОГДА не force-push / не прямой push в
main(INV-4). - ПЕРЕД merge консультироваться
merge_gate.pr_already_merged(repo, branch)— уже слит → no-op (INV-5, переиспользовать ORCH-065). - G3 — порядок относительно рестарта: merge ДОЛЖЕН быть завершён и подтверждён ДО рестарта прод-контейнера, ЛИБО вынесен в шаг, переживающий рестарт (паттерн
requeue_running_jobs/finalizer-defer): если процесс умер во время Phase B, шаг merge докатывается после рестарта (re-drive finalizer'а или отдельный merge-job). Дизайн выбирает один из двух вариантов; выбранный обязан быть restart-safe (sentinel/jobs, без миграции БД — §4).
FR-2 (G1) — Пост-деплой верификация merge
- ПОСЛЕ деплоя (в Phase C / финализации, ДО фиксации
done) выполнить детерминированную верификацию: задеплоенный commit (validated SHA) — предокorigin/main(git merge-base --is-ancestor <sha> origin/main) ИЛИPR.merged == true(Gitea API). - Верификация never-raise (INV-1): любая ошибка git/HTTP → трактуется как «не подтверждено» → alert, НЕ падение.
- При неподтверждённой верификации — alert «deploy succeeded but not merged» (Telegram + Plane-коммент) и задача НЕ переходит в
done(FR-3).
FR-3 (G2) — done только при подтверждённом merge
- Переход
deploy → doneдля self-hosting ДОЛЖЕН быть обусловлен подтверждённым merge (verify из FR-2 зелёный). Наличиеdeploy_status: SUCCESS+ post-deployHEALTHY— недостаточно. - При
SUCCESS-маркере деплоя, но неподтверждённом merge: задача удерживается (неdone), Plane-статус — не терминальный (например текущийDeploying/AwaitingилиBlockedпо решению дизайна), шлётся alert. Конвейер НЕ откатывается наdevelopmentавтоматически из-за not-merged (это инфраструктурный, не код-дефект) — реакция = alert + ручное вмешательство (согласовать с дизайном; по умолчанию ALERT-only, как ORCH-021 self-hosting).
FR-4 (G4) — Диагностический runbook
- В
docs/operations/добавить runbook с 4 проверками из постмортема (метод однозначной локализации фантома):- Gitea API: список PR + флаги
merged. - md5 прод-файлов vs
git show origin/main:<file>. git merge-baseветки vsmain.- Таймлайн деплой-логов.
- Gitea API: список PR + флаги
- Включить готовые команды (copy-paste) и критерий «фантом подтверждён».
FR-5 — Условность раската (как ORCH-35/43/58)
- Новая логика merge+verify реальна для self-hosting (
is_self_hosting_repo/merge_verify_repos); прочие репо — поведение БЕЗ изменений (non-self merge остаётся за агентомdeployer). - Kill-switch (env, дефолт
true) →falseвосстанавливает строго прежнее поведение.
3. Изменения API
- Внешний HTTP API сервиса (
/health,/status,/queue,/webhook/*) — без новых endpoint'ов. Допустимо обогащение ответаGET /queueблоком наблюдаемости merge-verify (счётчики), по образцу блоковreaper/post_deploy. - Gitea API (исходящие вызовы): новый детерминированный вызов
POST /repos/{owner}/{repo}/pulls/{index}/merge(merge-актор, FR-1) + чтениеGET /repos/{owner}/{repo}/pulls?...(уже используется вpr_already_merged). Через существующий httpx-клиент иsettings.gitea_*.
4. Изменения схемы БД
- НЕТ. Schema-changes запрещены (не-цель). Restart-safe состояние нового шага merge — через sentinel-файлы (
.deploy-state-<repo>/<wi>/, как ORCH-036) и/или существующую очередьjobs(finalizer-defer). Колонкаjobs.pid(ORCH-065) уже есть, при необходимости переиспользуется.
5. Требования к новым QG checks
- Допускается ввести детерминированный под-чек верификации merge (напр.
check_merged_to_main), регистрируемый вQG_CHECKS, ЛИБО встроить верификацию как условие в логику переходаdeploy→doneбез нового чека — на усмотрение дизайна. В любом случае:- Контракт
check_deploy_status/_parse_deploy_status(читает толькоdeploy_status:frontmatter) НЕ меняется. STAGE_TRANSITIONSНЕ меняется (verify — это условие/под-гейт ребра/финализации, не новая стадия).- Вердикт (если артефакт) — строго YAML-frontmatter (канон гейтов), never проза.
- Контракт
6. Артефакты, создаваемые/обновляемые по pipeline
14-deploy-log.md— существующий; дизайн может добавить поле статуса merge (напр.merged_to_main: true|false) во frontmatter (машиночитаемо), не ломаяdeploy_status:.- Новый runbook в
docs/operations/(FR-4). - Обязательно (CLAUDE.md §2): обновить
docs/architecture/README.md(раздел Phase B / merge-gate / executable self-deploy — описать новый merge+verify шаг),CHANGELOG.md, при сквозном решении — ADR (docs/work-items/ORCH-071/06-adr/ADR-001-*.mdи/или globaldocs/architecture/adr/).
7. Совместимость / регресс
- Happy-path не-self репо (enduro-trails): merge остаётся за агентом
deployer→ поведение без изменений. - Happy-path self-hosting: при штатном merge задача
doneставится как раньше (после добавления verify, который зелёный). - Все существующие контракты неизменны:
STAGE_TRANSITIONS, реестрQG_CHECKS(кроме возможного нового under-чека),check_deploy_status, БАГ-8, terminal-sync, merge-gate (ORCH-043),Confirm Deploy(ORCH-059), exit-коды хука (0/1/2), схема БД.