# Критерии приёмки — 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-<repo>.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: любой тест из плана красный или сломан существующий тест.
