# Критерии приёмки: ORCH-060 Work Item ID: ORCH-060 Формат: каждый критерий — Дано / Когда / Тогда, с однозначным PASS/FAIL. --- ## AC-1 — Escalated-задача (retry == лимит) не разблокируется (главный кейс ET-013) - **Дано:** задача на `stage='development'`, без активного job, `age >= grace`, `check_ci_green` зелёный; в `agent_runs` ровно `MAX_DEVELOPER_RETRIES` (=3) записей `agent='developer'`. - **Когда:** выполняется `Reconciler.reconcile_gate_once()`. - **Тогда:** стадия остаётся `development`; `advance_stage`/`advance_if_gate_passed` не приводит к смене стадии; `unblocked_total == 0`; новый developer/reviewer job не создаётся. - **PASS:** стадия не изменилась И `unblocked_total == 0` И нет новых job. - **FAIL:** стадия стала `review` / появился новый job / `unblocked_total > 0`. ## AC-2 — Граница: retry > лимита тоже пропускается - **Дано:** то же, но developer-записей `> MAX_DEVELOPER_RETRIES` (например 4–5). - **Когда:** `reconcile_gate_once()`. - **Тогда:** задача пропущена (как AC-1). - **PASS / FAIL:** как AC-1. ## AC-3 — Регресс happy-path: retry < лимита по-прежнему доигрывается - **Дано:** `development`, без активного job, `age >= grace`, `check_ci_green` зелёный; developer-записей `< MAX_DEVELOPER_RETRIES` (например 0, 1 или 2). - **Когда:** `reconcile_gate_once()`. - **Тогда:** задача доигрывается `development → review`; `unblocked_total == 1`; enqueue следующего агента происходит как раньше. - **PASS:** стадия стала `review` И `unblocked_total == 1`. - **FAIL:** задача пропущена / стадия не изменилась. ## AC-4 — Граница ровно на лимите (==3) → skip, на (лимит−1) → advance - **Дано:** две задачи-близнеца, идентичные кроме числа developer-записей: одна с `MAX_DEVELOPER_RETRIES`, другая с `MAX_DEVELOPER_RETRIES − 1`. - **Когда:** `reconcile_gate_once()`. - **Тогда:** первая пропущена (skip), вторая доиграна (advance). - **PASS:** ровно одна из двух доиграна (та, что `−1`). - **FAIL:** обе доиграны / обе пропущены / доиграна задача на лимите. ## AC-5 — Plane-статус Blocked → пропуск - **Дано:** задача-кандидат F-1 (stage не-терминальный, без активного job, `age >= grace`, гейт зелёный), у которой текущий Plane-статус issue = **Blocked**; retry < лимита (чтобы изолировать именно этот гард). - **Когда:** `reconcile_gate_once()`. - **Тогда:** задача пропущена; стадия не меняется; `unblocked_total == 0`. - **PASS:** стадия не изменилась И `unblocked_total == 0`. - **FAIL:** задача доиграна. ## AC-6 — Plane-статус Needs Input → пропуск - **Дано:** как AC-5, но Plane-статус = **Needs Input**. - **Когда:** `reconcile_gate_once()`. - **Тогда:** задача пропущена (как AC-5). - **PASS / FAIL:** как AC-5. ## AC-7 — Тишина при пропуске (no spam) - **Дано:** escalated-задача (как AC-1). - **Когда:** `reconcile_gate_once()` (один или несколько тиков). - **Тогда:** НЕ вызывается `_note_unblock`; нет лог-строки `... разблокирована`; нет `send_telegram`; нет `notify_qg_failure` (пропуск — раньше оценки гейта). - **PASS:** ни одна из перечисленных нотификаций не вызвана. - **FAIL:** вызвана любая нотификация. ## AC-8 — Никакого сетевого вызова гейта на escalated-задаче - **Дано:** escalated-задача (как AC-1) с замоканным `check_ci_green`. - **Когда:** `reconcile_gate_once()`. - **Тогда:** `check_ci_green` (через `advance_if_gate_passed`/`_run_qg`) НЕ вызывается для этой задачи — пропуск происходит раньше. - **PASS:** мок гейта не вызван. - **FAIL:** мок гейта вызван. ## AC-9 — F-2 не доигрывает Blocked/Needs Input (регресс) - **Дано:** issue в Plane-статусе Blocked или Needs Input (не входит в {in_progress, approved, rejected}). - **Когда:** `reconcile_plane_once()`. - **Тогда:** ни `handle_status_start`, ни `handle_verdict` не вызываются для этого issue; `unblocked_total == 0`. - **PASS:** обработчики не вызваны. - **FAIL:** вызван любой обработчик. ## AC-10 — Never-raise: ошибка проверки статуса не ломает тик - **Дано:** проверка blocked/needs-input (Plane API в Варианте A) бросает исключение для одной задачи; в выборке есть ещё одна валидная задача. - **Когда:** `reconcile_gate_once()`. - **Тогда:** тик не падает; сбойная задача консервативно НЕ трогается (skip); остальные обрабатываются. - **PASS:** исключение изолировано, остальные задачи обработаны. - **FAIL:** исключение всплыло из `reconcile_gate_once`. ## AC-11 — Лимит не хардкодится - **Дано:** код F-1-гарда. - **Тогда:** используется `stage_engine.MAX_DEVELOPER_RETRIES`, а не литерал `3`. - **PASS:** граница берётся из константы. - **FAIL:** в reconciler.py появился магический `3`. ## AC-12 — Документация обновлена (golden source) - **Дано:** PR задачи. - **Тогда:** обновлены `docs/architecture/README.md` (описание F-1 с новым skip), `CHANGELOG.md`, создан `06-adr/ADR-001-*.md`. - **PASS:** все три артефакта обновлены/созданы в этом же PR. - **FAIL:** любой отсутствует (reviewer → REQUEST_CHANGES). ## AC-13 — Регресс существующих тестов reconciler - **Дано:** существующий `tests/test_reconciler.py` (ORCH-053). - **Когда:** `pytest tests/test_reconciler.py -q`. - **Тогда:** все прежние тесты зелёные (поведение happy-path/analysis/kill-switch не сломано). - **PASS:** 0 регрессий. - **FAIL:** любой ранее зелёный тест упал.