--- type: review work_item_id: ORCH-065 verdict: APPROVED version: 3 --- # Review ORCH-065 ## Summary Задача закрывает три связанных класса отказов «процесс/поток умер, а ресурс остался захваченным навсегда»: zombie jobs (A), залипший merge-lease (B), неидемпотентная финализация merge (C). Реализация качественная: новый daemon-поток `src/job_reaper.py` по образцу `reconciler` (never-raise, kill-switch, снимок в `/queue`), трёхуровневая liveness, атомарный `reap_running_job(... WHERE status='running')`, проактивный реклейм lease (`pid_alive` + `reclaim_stale_lease`), идемпотентный guard `pr_already_merged`, колонка `jobs.pid` через идемпотентный `_ensure_column`. **Все блокеры предыдущих ревью устранены:** - v1 P0 (guard `pr_already_merged` не подключён к merge-пути) — устранён `aa46e5d`: промпт `.openclaw/agents/deployer.md` консультирует `pr_already_merged` ПЕРЕД любым (повторным) merge (AC-11 wiring на месте, подтверждено строками 94–105/152). - v2 P1 (Tier-2 реапит живой финализирующий monitor; side-effects ДО атомарного claim, нарушение ADR-001 Р-1) — устранён `3e2eb27` двумя мерами: 1. **Tier-2 finalization grace** — новая колонка `finished_age_s` в `get_running_jobs` (`src/db.py:609`) + настройка `reaper_finalize_grace_s` (дефолт 300с); Tier-2 реапит только при `finished_age >= grace`, иначе строка не трогается (`src/job_reaper.py:197-209`). Живой финализирующий monitor больше не реапится (FR-1.3/AC-3). 2. **claim-before-act** — `_reap_exit0` (`src/job_reaper.py:242-286`) сначала оценивает канонический QG read-only (`_gate_is_green` → `_run_qg`, без побочных эффектов), затем атомарно claim `done` ПЕРВЫМ, и только победитель claim выполняет `_gate_driven_advance`. Проигравший гонку (поздний monitor / стартовый requeue) не делает НИКАКИХ побочных эффектов → нет дубль-advance/дубль-enqueue (FR-1.2/AC-4). - v2 P3 (битая ссылка на adr-0011 в CHANGELOG) — исправлена в `3e2eb27` (`adr-0011-job-reaper-lease-reclaim.md`). Инварианты сохранены (AC-13): ORCH-065-коммиты (`1a2e881`/`aa46e5d`/`3e2eb27`) НЕ касаются `src/stages.py` и `src/qg/checks.py` — `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/БАГ-8/ exit-коды хука не тронуты; реклейм lease — только удаление файла, без git-операций (AC-12). Документация (README, internals, ADR-001, глобальный adr-0011, CHANGELOG, .env.example) обновлена в этом же PR (AC-17). Новые тесты покрывают grace-окно, lost-claim-no-side-effects, already-advanced-идемпотентность. `pytest tests/ -q` — **747 passed**. ## Findings ### P0 — Blocker - нет ### P1 — Must fix - нет ### P2 — Should fix - нет ### P3 — Nice to have - нет ## Документация Обновлена корректно и в этом же PR (AC-17 PASS): `docs/architecture/README.md` (раздел про job-reaper + lease-reclaim, таблицы БД и `/queue`), `docs/architecture/internals.md`, `docs/architecture/adr/adr-0011-job-reaper-lease-reclaim.md` (+ запись в `adr/README.md`), `docs/work-items/ORCH-065/06-adr/ADR-001-job-reaper-and-lease-reclaim.md`, `CHANGELOG.md` (ссылка на adr-0011 исправлена), `.env.example` (флаги `ORCH_REAPER_*` / `ORCH_REAPER_FINALIZE_GRACE_S` / `ORCH_LEASE_RECLAIM_ENABLED`). ADR-001 Р-1 и реализация exit0-пути теперь согласованы (claim-before-act).