diff --git a/docs/work-items/ORCH-094/12-review.md b/docs/work-items/ORCH-094/12-review.md new file mode 100644 index 0000000..14805a2 --- /dev/null +++ b/docs/work-items/ORCH-094/12-review.md @@ -0,0 +1,102 @@ +--- +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` не требуется. + +Документация полная и согласована с реализацией. Расхождений код ↔ доки не найдено.