9.5 KiB
9.5 KiB
Acceptance Criteria — ORCH-053
Work Item ID: ORCH-053
Формат: каждый критерий имеет явное условие PASS/FAIL. Критерий считается выполненным,
только если соответствующие тесты из 04-test-plan.yaml зелёные.
AC-1 — Реконсиляция застрявшей стадии (gate-side, F-1)
- Дано: task на стадии
development, без активных job'ов,updated_atстарше grace, гейтcheck_ci_greenдля её branch — зелёный (CI прошёл, но webhook потерян, как ORCH-044). - Когда: срабатывает фоновый проход
reconcile_gate_once(). - PASS: задача продвинута
development → review, заenqueuenreviewer(черезadvance_stage(..., finished_agent=None)),tasks.updated_atобновлён. - FAIL: задача осталась на
development, либо продвижение пошло параллельной логикой (не черезadvance_stage).
AC-2 — Источник истины — гейт, не событие
- PASS: продвижение в F-1 выполняется исключительно вызовом
stage_engine.advance_stage(...); вreconciler.pyНЕТ собственногоupdate_task_stage+enqueue_jobдля advance стадии (только переиспользование). - FAIL: в reconciler продублирована логика advance/rollback.
AC-3 — Идемпотентность: sweeper не трогает задачи с активным job
- Дано: task с
queuedилиrunningjob (has_active_job_for_task == True). - PASS: sweeper пропускает задачу — ни advance, ни enqueue, ни нотификации.
- FAIL: sweeper дёргает гейт / создаёт второй job для такой задачи.
AC-4 — Идемпотентность: задержавшийся/дублированный webhook + sweeper не двоят
- Дано: issue в Plane = In Progress, задержавшийся Plane-webhook ещё не обработан.
- Когда: F-2 реконсилирует И затем (или одновременно) приходит реальный webhook.
- PASS: создаётся ровно одна задача (один task row, один branch/worktree, один стартовый analyst-job). Повторный путь видит существующую задачу/активный job и не двоит.
- FAIL: созданы две задачи / два стартовых job / два worktree на один
plane_id.
AC-5 — Per-stage grace соблюдается
- Дано: task на стадии, чей
updated_atсвежее grace этой стадии (агент легитимно работает, напр. analysis 8 мин при grace 1800с). - PASS: sweeper НЕ трогает задачу (не дёргает гейт).
- PASS (граница): как только
age(updated_at) >= grace_for_stage(stage)и нет активного job — задача становится кандидатом. - FAIL: sweeper дёргает гейт у задачи в пределах grace.
AC-6 — Plane In Progress без задачи → запуск (F-2)
- Дано: issue в Plane = In Progress (статус сменён руками, webhook потерян), в
tasksзадачи нет, прошёл grace. - PASS: sweeper вызывает
handle_status_start/start_pipeline→ задача создана, заenqueuen analyst — как если бы пришёл webhook. - FAIL: задача не создана; либо создана дублирующей логикой, минуя
handle_status_start.
AC-7 — Plane Approved без advance → advance (F-2)
- Дано: issue = Approved, task существует и стадия НЕ сдвинута, нет активного job, прошёл grace.
- PASS: sweeper вызывает
handle_verdict(approved=True)→ штатный advance. - FAIL: нет advance, либо advance вне
handle_verdict/advance_stage.
AC-8 — Plane Rejected без rollback → rollback (F-2)
- Дано: issue = Rejected, task существует и не откатана, нет активного job, прошёл grace.
- PASS: sweeper вызывает
handle_verdict(approved=False)→ штатный rollback на предыдущую стадию. - FAIL: нет rollback, либо rollback вне штатного пути.
AC-9 — Нет спама нотификаций на красном гейте
- Дано: застрявшая задача, у которой гейт стабильно красный (напр. CI failure), нет активного job, прошёл grace.
- Когда: sweeper проходит несколько тиков подряд.
- PASS:
notify_qg_failure/Telegram НЕ вызывается на каждом тике (≤1 раз / без повторов); задача не продвигается. - FAIL: на каждом тике летит нотификация о провале гейта.
AC-10 — Тишина при синхронности
- Дано: все задачи синхронны (нет застрявших; статусы Plane совпадают с локальными).
- PASS: проход не выполняет действий, не пишет INFO-логов о разблокировке, не шлёт нотификаций.
- FAIL: sweeper генерирует шум/действия при полностью синхронном состоянии.
AC-11 — Restart-safe фоновый поток
- PASS: reconciler стартует в
main.lifespan(daemon-поток), корректно останавливается (stop()), переживает рестарт сервиса без потери (нет состояния в памяти, критичного для корректности; всё перечитывается из БД/Plane). - FAIL: reconciler не стартует автоматически, висит при shutdown, или дублирует действия после рестарта.
AC-12 — Наблюдаемость разблокировки (F-4)
- Дано: sweeper разблокировал застрявшую задачу.
- PASS: в лог пишется явная строка вида
reconciler: <work_item_id> <stage> разблокирована (потерян webhook); приreconcile_notify_unblock=True— Telegram-уведомление. - FAIL: разблокировка происходит молча (невозможно измерить частоту дыры).
AC-13 — Kill-switch
- Дано:
reconcile_enabled=False(envORCH_RECONCILE_ENABLED=false). - PASS: фоновый поток reconciler не выполняет проходов (или не стартует); система
работает как до ORCH-053.
reconcile_plane_enabled=Falseгасит только F-2, F-1 работает. - FAIL: sweeper активен при выключенном флаге.
AC-14 — Усиленный sha→branch резолв (F-3)
- Дано: Gitea CI-status webhook без
branchesи соsha, не разрезолвившимся черезgit branch -r --contains. - PASS: добавленный БД-fallback однозначно находит task (по repo + активной development-стадии) и продвигает; неоднозначность логируется на уровне INFO; существующая success/failure-семантика гейта не изменена.
- FAIL: регресс существующего резолва, либо ложный матч при неоднозначности.
AC-15 — Never-raise в тике
- Дано: обработка одной задачи/issue кидает исключение (битые данные, ошибка API).
- PASS: исключение изолировано, проход продолжает остальные задачи; поток не падает.
- FAIL: одно исключение роняет весь проход / поток reconciler.
AC-16 — F-1 не продвигает analysis по локальному состоянию
- Дано: task на
analysis, артефакты на диске присутствуют, но Plane НЕ в статусе Approved (BRD не одобрен человеком), нет активного job, прошёл grace. - PASS: F-1 (gate-side) НЕ продвигает analysis→architecture (advance стадии analysis отдан F-2, которая сверяется с реальным статусом Plane Approved).
- FAIL: sweeper автопродвинул неодобренный BRD.
AC-17 — Документация обновлена (golden source)
- PASS: в PR обновлены
docs/architecture/README.md, заведёнdocs/work-items/ORCH-053/06-adr/ADR-001-*.md, обновлёнCHANGELOG.md, упомянут kill-switch вdocs/operations/INFRA.md. - FAIL: код изменён, документация — нет (Reviewer обязан вернуть REQUEST_CHANGES).