Files
orchestrator/docs/architecture/adr/adr-0028-terminal-window-aware-deploy-status-guard.md

7.9 KiB
Raw Permalink Blame History

work_item, stage, author_agent, status, created_at, model_used
work_item stage author_agent status created_at model_used
ORCH-094 architecture architect proposed 2026-06-09 claude-opus-4-8

adr-0028: Terminal-window-aware гард выставления deploy-фазовых статусов Plane

Сквозной (cross-cutting) ADR. Амендмент к adr-0010 (post-deploy monitor, ORCH-021) и Plane-статусной модели (ORCH-066): вводит инвариант «deploy-фазовые Plane-статусы — terminal-window-aware» поверх общих сеттеров plane_sync и переупорядочивает блок next_stage == "done" в advance_stage. Детальное решение задачи — docs/work-items/ORCH-094/06-adr/ADR-001-terminal-window-aware-deploy-status-guard.md.

Регистрируется как сквозной, т.к. правит общие сеттеры set_issue_awaiting_deploy/ set_issue_deploying/set_issue_monitoring (используются системно) и трогает маркированный блок с ORCH-021/ORCH-066 (docs/_standards/TRACEABILITY.md).

Статус

Proposed

Контекст

Терминальная (done) задача в Plane не держит Done: непрерывный флапп Awaiting Deploy ⟷ Monitoring after Deploy (верифицировано живьём на ORCH-061, task 47, done с 07.06 — 273 активности, само не затихает). Установлено по коду/логам/БД прода:

  • Три code-писателя deploy-фазовых статусов (src/stage_engine.py:404/1218/1316) делегируют в тонкие сеттеры src/plane_sync.py, которые БД-стадию не читают ⇒ терминал-слепы: любой повторный вызов перезаписывает Done обратно на промежуточный статус.
  • Ordering: update_task_stage("done") (stage_engine.py:369) пишет tasks.stage='done' раньше легитимного set_issue_monitoring (стр. 404) ⇒ пост-деплой-окно ORCH-021 — by-design индикация поверх уже-done задачи. Наивный гард «stage==done → Done» ⇒ регресс легитимного окна.
  • Актор всех 273 переходов — бот-токен орка (daf4d3f4-…), не привязан к активной task/job; в БД нет активного post-deploy-monitor для task 47 (окно 15 мин закрыто). Реконсилятор F-1 пропускает done/cancelled, F-2 опрашивает только [to_analyse, approved, rejected] ⇒ механизма привести застрявшую на deploy-статусе done-задачу к Done нет.

Решение

Единый terminal-window-aware гард на низком чокпоинте — на входе трёх deploy-фазовых сеттеров plane_sync. Чистую логику держит новый leaf-модуль src/deploy_status_guard.py (never-raise, config-gated; образец serial_gate.py/labels.py/cancel.py); сеттеры исполняют вердикт.

  • Инвариант легитимности: deploy-фазовый статус легитимен ⇔ задача нетерминальна ИЛИ (done И активно пост-деплой-окно). Иначе — идемпотентное схождение к Done. decide(work_item_id, target) -> ALLOW | CONVERGE_DONE | SUPPRESS: kill-switch off / чужой issue / не-self репо / нетерминал → ALLOW; cancelledSUPPRESS; done + target==monitoring + window_activeALLOW; done иначе → CONVERGE_DONE (set_issue_done, идемпотентно); любое исключение → ALLOW + warning (never-raise).
  • Новый helper post_deploy.window_active(repo, wi) = has_marker(ARMED) and not has_marker(DONE) (restart-safe).
  • Перенос арм-блока (post_deploy.arm_monitor) перед terminal-sync в блоке next_stage == "done": на стр. 404 ARMED уже записан ⇒ window_active==True ⇒ легитимный первый Monitoring проходит; re-drive после закрытия окна сходится к Done.
  • Харднинг монитора: идемпотентный страж has_marker(...DONE) (ранний return без PATCH/реэнкью)
    • тик no-op при cancelled мид-окно; тики привязаны к активному job'у (нет job → нет тика).
  • Наблюдаемость: каждый вердикт логируется (work_item/caller/target/db_stage/ window_active/вердикт); подавление/схождение — явно.
  • Флаги (config.py): deploy_status_guard_enabled=True (ORCH_DEPLOY_STATUS_GUARD_ENABLED, kill-switch → 1:1) + deploy_status_guard_repos="" (ORCH_DEPLOY_STATUS_GUARD_REPOS, пусто → self-hosting only) с локальным applies(repo).

Альтернативы

  • Гард в caller'ах stage_engine — отвергнуто: не ловит неизвестный/стейл путь под бот-токеном, размазывает инвариант.
  • Наивный «stage==done → Done» без предиката окна — отвергнуто: регресс легитимного Monitoring.
  • Bypass-флаг на доверенном вызове 404 — отвергнуто в пользу переноса арм-блока (один предикат).
  • Активная сходимость в реконсиляторе F-2 — отвергнуто как основной механизм (лишний polling, правка маркированного F-2); гард на сеттере гасит непрерывный флапп.

Последствия

  • Терминальная задача стабильно держит Done; маятник гаснет за один цикл независимо от актора.
  • Легитимный пост-деплой Monitoring и рабочий self-deploy-цикл — 1:1 (предикат окна + перенос арм).
  • STAGE_TRANSITIONS / QG_CHECKS / check_* / machine-verdict ключи / схема БД — не тронуты.
  • main/force-push/прод-контейнер/detached-деплой — не тронуты; не-self репо инертны.
  • Ограничение: если актор флаппа — внешняя Plane-automation (вне кода орка), гард — буфер на стороне орка; локализация (FR-1) и итог документируются (BR-7).
  • Откат: ORCH_DEPLOY_STATUS_GUARD_ENABLED=false → поведение 1:1; полный — revert ветки.

Связи

  • adr-0010 (ORCH-021 — пост-деплой-окно, sentinel armed/done, арм-блок) — амендмент: окно становится предикатом легитимности Monitoring.
  • ORCH-066 (Plane-статусная модель — слой B индикации; deploy→done self ⇒ Monitoring) — инвариант сохранён.
  • adr-0026 (ORCH-090 — терминал cancelled) — гард не штампует deploy-статус поверх cancelled.
  • ORCH-068/086 (терминал-скип реконсилятора) — этот ADR распространяет идею терминал-aware на выставление deploy-статусов.
  • Детально: docs/work-items/ORCH-094/06-adr/ADR-001-terminal-window-aware-deploy-status-guard.md.