# Критерии приёмки — ORCH-065 Work Item ID: ORCH-065 Формат: каждый критерий имеет явное условие PASS/FAIL. Все критерии должны быть PASS для прохождения review/testing. ## A. Job-reaper (Проблема A) ### AC-1 — реап мёртвого running-job без рестарта - PASS: при наличии строки `jobs` в статусе `running`, чей процесс/исполнитель достоверно мёртв (pid не существует ИЛИ `agent_runs.exit_code` записан, а job всё ещё `running`) и условие устойчивости (FR-1.3) выполнено, фоновый reaper переводит строку в корректный статус (`done`/`queued`/`failed`) **без перезапуска процесса**. - FAIL: строка остаётся `running` после `reaper_dead_ticks` тиков / превышения `reaper_max_running_s`. ### AC-2 — разблокировка очереди при concurrency=1 - PASS: после реапа зомби-строки `count_running_jobs()` снижается, и следующий queued-job успешно claim'ится воркером. - FAIL: очередь остаётся заблокированной зомби-строкой. ### AC-3 — анти-ложноположительность (живой долгий агент не реапится) - PASS: `running`-job с ЖИВЫМ процессом в пределах его `agent_timeout` НЕ помечается зомби (ни по одному тику, ни в пределах `reaper_max_running_s`, если потолок больше таймаута). - FAIL: живой агент помечен `failed`/`queued` reaper'ом. ### AC-4 — корректный исход по результату - PASS: при `agent_runs.exit_code == 0` reaper доводит до успешного завершения без дублирования уже выполненного stage-advance (идемпотентно); при неуспехе и `attempts < max_attempts` → `queued`; при исчерпании → `failed` + Telegram. - FAIL: успешный исход помечен `failed`; либо дублируется stage-переход; либо исчерпанный бюджет молча зацикливается на `queued`. ### AC-5 — restart-safe совместимость - PASS: одновременная работа стартового `requeue_running_jobs()` и периодического reaper не приводит к двойной обработке одной строки (атомарный UPDATE с guard `status='running'`). - FAIL: одна строка обработана дважды / гонка приводит к рассинхрону статуса. ## B. Stale/dead merge-lease reclaim (Проблема B) ### AC-6 — реклейм lease мёртвого держателя - PASS: lease `.merge-lease-.json`, чей `pid` не существует, проактивно освобождается на старте И периодическим потоком (не дожидаясь TTL и не дожидаясь чужого `acquire`). - FAIL: lease мёртвого держателя остаётся до истечения `merge_lock_timeout_s` или до следующего чужого `acquire`. ### AC-7 — реклейм по TTL сохранён - PASS: lease старше `merge_lock_timeout_s` освобождается (существующий контракт не сломан), с `logger.warning`. - FAIL: просроченный lease не освобождается. ### AC-8 — не трогать живой lease - PASS: lease с ЖИВЫМ держателем (pid жив) и возрастом `< merge_lock_timeout_s` НЕ освобождается (защита легитимного merge). - FAIL: освобождён lease живого держателя → возможен параллельный конфликтный merge. ### AC-9 — условность и never-raise - PASS: реклейм реален только для `merge_gate_repos`/self-hosting; для прочих репо — no-op; любая ошибка реклейма логируется и не валит поток (never-raise). - FAIL: реклейм выполняется для не-self-hosting репо; либо ошибка пробрасывается наружу/роняет поток. ## C. Идемпотентная финализация merge (Проблема C) ### AC-10 — докатывание незавершённого merge - PASS: сценарий «rebase+re-test зелёные, merge не состоялся, процесс умер» восстанавливается автоматически (job → `queued` reaper'ом / reconciler доигрывает), и merge доводится без повторного ненужного прогона дорогих шагов. - FAIL: задача остаётся в полу-выполненном состоянии, требует ручного merge. ### AC-11 — идемпотентность при уже слитом PR - PASS: повторный вызов финализации при уже слитом PR — no-op (определяется по состоянию PR/`main`), без ошибки и без второго merge. - FAIL: второй merge / ошибка при уже слитом PR. ## D. Инварианты и безопасность self-hosting ### AC-12 — прод-контейнер не трогается - PASS: ни reaper, ни lease-reclaim не рестартят/не роняют прод-контейнер и не инициируют git-push в `main`. - FAIL: любая из новых веток кода рестартит self / пушит main. ### AC-13 — контракты неизменны - PASS: `STAGE_TRANSITIONS`, реестр `QG_CHECKS`, сигнатуры/поведение `check_*`, БАГ-8 откат, exit-коды deploy-хука — без изменений; новых QG checks/стадий нет. - FAIL: затронут любой из перечисленных контрактов. ### AC-14 — kill-switches - PASS: `reaper_enabled=false` → reaper не работает (строго прежнее поведение); `lease_reclaim_enabled=false` → проактивный реклейм отключён (остаётся лишь прежний ленивый TTL-реклейм в `acquire`). - FAIL: флаг `false` не отключает соответствующий механизм. ## E. Наблюдаемость ### AC-15 — блок reaper в /queue - PASS: `GET /queue` содержит блок `reaper` (enabled, interval, last_run_ts, reaped_total, last_reaped, lease_reclaimed_total). - FAIL: блок отсутствует/не обновляется. ### AC-16 — логи и алерты - PASS: каждый reap и lease-reclaim → `logger.warning` с идентификаторами; reap→`failed` и lease-reclaim → Telegram. - FAIL: реап/реклейм происходят молча. ## F. Документация (gate reviewer) ### AC-17 — golden-source обновлён в этом же PR - PASS: обновлены `docs/architecture/README.md` (раздел про reaper + lease-reclaim), `CHANGELOG.md`, `.env.example` (новые `ORCH_*` флаги); заведён `06-adr/ADR-001-*.md`. - FAIL: код изменён, документация — нет (reviewer → REQUEST_CHANGES). ## G. Тесты ### AC-18 — регресс-тесты зелёные - PASS: новые unit/integration тесты (см. 04-test-plan.yaml) проходят; существующий `pytest tests/ -q` зелёный (нет регресса merge_gate / queue / reconciler). - FAIL: любой тест из плана красный или сломан существующий тест.