125 lines
7.2 KiB
Markdown
125 lines
7.2 KiB
Markdown
# Критерии приёмки: 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:** любой ранее зелёный тест упал.
|