7.1 KiB
BRD — ORCH-071: Фантомный merge — деплой без слияния в main
1. Контекст и тип
- Тип: BUG CRITICAL (целостность
main/ надёжность деплоя, self-hosting). - Обнаружено: Слава + Стрим, 2026-06-08, при разборе «ORCH-067 не подхватился».
- Постмортем:
docs/history/LESSONS_2026-06-08_phantom-merge.md. - Подозрение на регресс: ORCH-065 (idempotent merge / lease-reclaim) — последний честный merge (PR#66).
- Связано: восстановление текущего
mainведётся ОТДЕЛЬНО (веткаinteg/restore-main-2026-06-08); эта задача — ROOT-FIX, чтобы фантом не повторялся.
2. Проблема (бизнес-формулировка)
Self-deploy (Phase B) для self-hosting репо orchestrator собирает прод-образ из ВЕТКИ задачи и рапортует finalize SUCCESS + post-deploy HEALTHY, но git-merge ветки в main НЕ происходит. PR остаётся open. Следующая задача срезает свою ветку от устаревшего main → теряет код незалитых предшественников.
Накопительно потеряны в main: ORCH-022, 059, 066, 068 (PR#67/68/69/70 — open). Последний реально слитый — ORCH-065 (PR#66).
3. Подтверждённый root cause (по результатам код-аудита)
Гипотеза A постмортема подтверждена аудитом кода ветки:
- В
src/НЕТ кода, выполняющего merge PR вmain(grepпоpulls/.../merge,/merge,merge_pr— 0 совпадений). Фактический merge выполняет ТОЛЬКО LLM-агентdeployerчерез Bash в начале стадииdeploy(см..openclaw/agents/deployer.md). - Для self-hosting (
orchestrator) стадияdeployоркеструется детерминированным кодом (stage_engine._handle_self_deploy_phase_b→self_deploy.initiate_deploy→ finalizerrun_deploy_finalizer), и агентdeployerНЕ запускается (так предписываетdeployer.md). Detached host-процесс делает retag staging-образа на прод-тег + рестарт 8500. Ни одна фаза A/B/C не вызывает merge ветки вmain. run_deploy_finalizerмаппит exit-code хука0→SUCCESS, пишет14-deploy-log.mdи вызываетadvance_stage(..., finished_agent="deployer"). Гейтcheck_deploy_statusчитает толькоdeploy_status:из артефакта →SUCCESS → done. Состояниеmainнигде не верифицируется.
Итог: для self-hosting путь deploy структурно НЕ содержит шага merge-в-main, а done достигается исключительно по deploy-маркеру. «Зелёный» деплой + здоровый прод (образ из рабочей ветки) маскируют отсутствие merge — сигнала о проблеме нет, пока следующая задача не потеряет код предшественника.
Вторичный фактор (усиливает риск даже если merge добавить наивно): Phase B рестартит прод-контейнер, поэтому любой держатель merge-lease / незавершённый git-шаг внутри процесса умирает до завершения merge (урок №3 постмортема).
4. Бизнес-цели
| ID | Цель |
|---|---|
| G1 | Деплой ВЕРИФИЦИРУЕТ, что задеплоенный commit реально влит в main ПОСЛЕ деплоя (deployed SHA — предок origin/main ИЛИ PR.merged==true). Иначе — alert, задача НЕ done. |
| G2 | Задача → done ТОЛЬКО при подтверждённом merge (PR.merged==true); маркеров finalize/post-deploy недостаточно. |
| G3 | Merge в main завершается и подтверждается ДО рестарта прод-контейнера, ЛИБО merge вынесен в шаг, переживающий рестарт (паттерн requeue_running_jobs для merge-в-main). |
| G4 | Диагностический runbook (4 проверки из постмортема) — в docs/operations. |
5. Не-цели
- Не менять source-of-truth (Plane), схему БД.
- Не отменять self-hosting safety (no auto-rollback / no-restart-others) — наоборот, усилить верификацией.
- Восстановление текущего
main(долив 022/059/066/068) — ОТДЕЛЬНАЯ веткаinteg/restore-main-2026-06-08, вне scope.
6. Инварианты (обязательны к соблюдению)
| ID | Инвариант |
|---|---|
| INV-1 | never-raise на шаге верификации — при ошибке шлётся alert, не падение процесса/конвейера. |
| INV-2 | self-hosting safety: верификация НЕ рестартит и НЕ роняет прод-контейнер orchestrator (8500), не трогает другие проекты. |
| INV-3 | Ручной approve прод-деплоя (триггер «Confirm Deploy», ORCH-059) сохранён — новая логика не вводит авто-деплой. |
| INV-4 | Никогда не делать force-push / прямой push в main; merge только через PR-merge API Gitea (как у deployer-агента сегодня). |
| INV-5 | Идемпотентность: повторный прогон (re-drive/reaper/двойной webhook) не делает второй merge и не ломает контракты (опора на pr_already_merged, ORCH-065). |
7. Заинтересованные стороны
- Owner — одобряет прод-деплой («Confirm Deploy»), получает alert при «deployed but not merged».
- Все проекты на инстансе (enduro-trails) — косвенно: целостность
mainорка влияет на инструмент, обслуживающий их из общей БД/очереди.
8. Критерий успеха (бизнес-уровень)
После доработки невозможно состояние «задача done + прод задеплоен, а PR open / commit не в main»: либо merge подтверждён и задача done, либо задача НЕ done и поднят alert «deploy succeeded but not merged». Воспроизведение исходного сценария на staging показывает, что main реально получает commit.