---
verdict: APPROVED
work_item: ORCH-094
stage: review
author_agent: reviewer
status: approved
created_at: 2026-06-09
model_used: claude-opus-4-8
type: review
work_item_id: ORCH-094
version: 1
---

# Review ORCH-094 — terminal-window-aware гард deploy-статусов

## Summary

PR устраняет флапп deploy-статусов у терминальной (`done`) задачи в Plane через единый
terminal-window-aware гард на входе трёх deploy-фазовых сеттеров `plane_sync`. Реализация
**точно следует** ADR-001 (D1–D8): новый leaf `src/deploy_status_guard.py` (чистый, never-raise,
config-gated), перенос арм-блока перед terminal-sync, харднинг пост-деплой-монитора, наблюдаемость
через `reason`-kwarg. Все 4 оси проверки — без P0/P1.

Проверено по коду ветки: `deploy_status_guard.py`, `plane_sync.py` (врезка `_deploy_status_guarded` +
3 сеттера), `stage_engine.py` (перенос арм-блока D3 + zombie-tick guard D4 + `reason`-call-sites),
`post_deploy.py` (`window_active`), `db.py` (`get_task_by_work_item_id`), `config.py` (2 флага).

## Findings

### P0 — Blocker
- Нет.

### P1 — Must fix
- Нет.

### P2 — Should fix
- Нет.

### P3 — Nice-to-have (информационно, вердикт не меняет)
- [ ] `post_deploy.window_active` при внутреннем исключении (`has_marker`-чтение sentinel'а) →
  `False` → внутри `decide` шаг 6 даёт `CONVERGE_DONE`. Это **асимметрия** относительно общего
  fail-safe-к-ALLOW контракта `decide` (шаг 7): транзиентная ошибка чтения sentinel'а в момент
  легитимного первого `Monitoring` свела бы его к `Done` (индикация-глитч, не флапп). Поведение
  **намеренное и задокументировано** (docstring `window_active`: «doubt → window closed → converge
  to Done — safe-for-indication default»), безопасно к терминальному состоянию; SQLite/диск-чтение
  локальное и надёжное. Оставлено как осознанный дизайн-выбор, фиксации не требует.

## Соответствие ТЗ (`02-trz.md` / `03-acceptance-criteria.md`)

- **FR-1 / AC-1** (источник флаппа локализован, done держит Done) — ✅ актор задокументирован
  (BR-7: code-писатели `stage_engine.py:404/1218/1316`, F-2 не перебирает, live-overlay read-only;
  гипотеза «под бот-токеном» в ADR), гард — буфер сходимости. Тесты TC-01/02/10.
- **FR-2 / AC-2** (терминал-aware идемпотентность) — ✅ `decide → ALLOW|CONVERGE_DONE|SUPPRESS`,
  предикат «нетерминал ИЛИ (`done` И окно)», `done`-иначе → `set_issue_done` идемпотентно, повтор
  на уже-`Done` → no-op. Тесты TC-01/02/12.
- **FR-3 / AC-3** (детерминированный конец монитора, нет зомби-тиков) — ✅ страж `has_marker(DONE)`
  сохранён; добавлен `cancelled`-мид-окно → `mark_done` без PATCH и без перепостановки; тик ≡ job.
  Тесты TC-06/07/08.
- **FR-4 / AC-5** (наблюдаемость) — ✅ BC-kwarg `reason` у 3 сеттеров; ровно одна структурная запись
  на вердикт (`work_item`/`caller`/`target`/`db_stage`/`window_active`/`verdict`; converge/suppress →
  WARNING). Тест TC-09 (полная атрибуция).
- **FR-5 / AC-4** (обратимость, регресс рабочего цикла) — ✅ kill-switch
  `deploy_status_guard_enabled` (`False` → 1:1) + self-hosting-only по дефолту (`repos=""`);
  нетерминальный `Awaiting/Deploying/Monitoring` проходит как раньше. Тесты TC-04/11/12 — особо
  TC-11 (end-to-end `run_deploy_finalizer`: легитимный `Monitoring` НЕ свёрнут к Done).

## Соответствие ADR (`06-adr/ADR-001` + сквозной `adr-0028`)

- D1 (гард на входе сеттеров `plane_sync`, не в caller'ах) — ✅.
- D2 (предикат терминал **И** окно; 7 шагов) — ✅ реализован 1:1 в `decide`.
- D3 (перенос арм-блока выше terminal-sync) — ✅ подтверждён в diff `advance_stage`; merge-lease
  release остаётся после terminal-sync; инварианты ORCH-021/066 сохранены.
- D4 (харднинг монитора) — ✅. D5 (наблюдаемость) — ✅. D6 (флаги) — ✅. D7 (что НЕ трогаем) — ✅
  (проверено: `src/stages.py`/`src/qg/`/`src/reconciler.py` — нулевой diff; machine-verdict ключи
  байт-в-байт). D8 (`get_task_by_work_item_id` read-only) — ✅.
- **Трассировка маркеров (CLAUDE.md прав. 9 / TRACEABILITY):** правка маркированного блока
  `next_stage=="done"` (ORCH-021/066/043/088) — ADR прочитаны, инварианты не сломаны (deploy→done
  self ⇒ Monitoring; монитор-close ⇒ Done; терминал-набор `{done,cancelled}`; merge-lease release
  не сдвинут относительно terminal-sync). Слома инвариантов нет.

## Качество кода

- Leaf-модуль `deploy_status_guard.py` — чистый, never-raise (двойная защита: `decide` + wrapper
  `_deploy_status_guarded`), нет рекурсии (`set_issue_done` не гардится), docstrings на всех публичных
  функциях, образец `serial_gate`/`labels`/`cancel` выдержан.
- Тесты содержательные (не тривиальные): 5 новых файлов, TC-01..12; TC-11 — реальный прогон
  `run_deploy_finalizer` с проверкой стадии и единственного `Monitoring`-PATCH; обновлены
  анти-регресс-ассерты под `reason`-kwarg. `pytest tests/ -q` — **1413 passed**.

## Документация

`src/` изменён → документация обновлена **в том же PR** (golden source соблюдён):
- ✅ `CHANGELOG.md` — детальная запись ORCH-094 (FR/AC/D-разбивка).
- ✅ `docs/architecture/README.md` — новый раздел «Terminal-window-aware гард deploy-статусов».
- ✅ `CLAUDE.md` — врезка в блок статусной модели Plane.
- ✅ `.env.example` — `ORCH_DEPLOY_STATUS_GUARD_ENABLED` / `_REPOS` с описанием.
- ✅ `docs/work-items/ORCH-094/06-adr/ADR-001-…md` (work-item) + сквозной
  `docs/architecture/adr/adr-0028-…md` (кросс-каттинг) — оба присутствуют.
- ✅ Обзорные доки (ORCH-079): PR — баг-фикс индикации, не закрывает пункт `README.md`
  «Известные ограничения»; обновления корневого `README.md` не требуется.

Документация полная и согласована с реализацией. Расхождений код ↔ доки не найдено.
