# ADR-0007: Исполняемый самодеплой стадии `deploy` (Вариант B, ORCH-36)

## Статус
Accepted (design) — реализация в ветке `feature/ORCH-036`.

## Контекст
Стадия `deploy` была «бумажной»: deployer-агент писал `deploy_status:` в
`14-deploy-log.md`, гейт `check_deploy_status` парсил вердикт и двигал
`deploy → done`. Реального деплоя не было. ORCH-36 делает стадию исполняемой для
self-hosting (`orchestrator`), сохраняя прежний ssh-путь для остальных репо.

Три ограничения формируют дизайн (детально — `docs/work-items/ORCH-036/06-adr/ADR-001`):
1. **Self-restart**: рестарт прод-контейнера 8500 убивает in-container процесс →
   рестарт делает ВНЕШНИЙ host-процесс.
2. **Status-only verdict model**: approve = смена статуса Plane на `Approved`
   (комментарии не управляют конвейером).
3. **Гонка гейта**: вердикт нельзя читать до завершения асинхронного хука.

## Решение
Для self-hosting стадия `deploy` исполняется в три фазы детерминированным кодом
(без LLM в критическом пути self-restart):

- **Фаза A (вход в `deploy`)** — для self + `deploy_require_manual_approve=true`
  вместо запуска прод-deployer выставляется approval-pending статус Plane + запрос
  approve (Plane-коммент + Telegram). Перехват в `advance_stage` на ребре
  `deploy-staging → deploy` (после `check_staging_status` и merge-gate).
- **Фаза B (Plane → Approved)** — `advance_stage(deploy, finished_agent=None)`
  запускает **detached host-процесс** (ssh + setsid → `orchestrator-deploy-hook.sh`
  с прод-параметрами и build-once retag) и ставит **детерминированный finalizer-job**
  с задержкой; маркер `initiated` — идемпотентность. Возврат БЕЗ advance.
- **Фаза C (finalizer)** — после рестарта новый контейнер дочитывает sentinel
  `result` (exit-code хука), маппит `0→SUCCESS / иначе→FAILED`, пишет
  `14-deploy-log.md`, вызывает `advance_stage(deploy, finished_agent="deployer")`
  → существующие контракты: `SUCCESS → done`, `FAILED → откат БАГ-8 на development`.

### Ключевые инварианты (НЕ меняются)
`STAGE_TRANSITIONS`, реестр QG, `check_deploy_status` / `_parse_deploy_status`
(frontmatter only), откат БАГ-8, terminal-sync `deploy → done`, merge-gate (ORCH-43),
exit-code-контракт хука (0/1/2).

### Новое (сквозное)
- **Детерминированный job-kind** `deploy-finalizer` в очереди (reserved-agent, не
  LLM): read-result | defer | map+write+advance. Зеркалит детерминизм merge-gate.
- **Approve-флаг** `deploy_require_manual_approve` (дефолт `true`; полный авто —
  отдельная задача после набора метрик доверия, ORCH-54).
- **Build-once**: опциональный `SOURCE_IMAGE` retag в хуке (обратно совместимо).
- **Restart-safe состояние** деплоя — sentinel-файлы под
  `<repos_dir>/.deploy-state-<repo>/<wi>/` (как merge-lease), БЕЗ миграции БД.

### Условность
Вся логика — только для `is_self_hosting_repo(repo)` (как ORCH-35). Прочие репо
деплоятся прежним синхронным ssh-путём агентом.

## Последствия
- `deploy_status: SUCCESS` доказан реальным health-ok; критический путь self-restart
  детерминирован.
- Вводится новая под-компонента (finalizer job-handler) → изменение помечено
  `arch:major-change`.
- Approve вписан в status-only модель: restart-safe, аудируемо, идемпотентно.
- На старте — обязательный ручной approve; молчаливых деплоев нет (Plane+Telegram).

## Связанные ADR
`adr-0003` (staging-gate), `adr-0006` (merge-gate), `adr-0005` (run-as-host-uid).
Детальный per-work-item: `docs/work-items/ORCH-036/06-adr/ADR-001-executable-self-deploy.md`.
