# 03 — Критерии приёмки (Acceptance Criteria) **Work Item:** ORCH-043 — merge-gate + auto-rebase + re-test **Автор:** Analyst Каждый критерий имеет однозначное условие PASS/FAIL. Все критерии должны быть PASS. --- ## AC-1 — Ветка актуальна: гейт пропускает без догона - **Дано:** ветка содержит последний `origin/main` (не отстаёт). - **Когда:** выполняется `check_branch_mergeable(repo, work_item_id, branch)`. - **PASS:** возвращает `(True, ...)` с причиной «up-to-date», auto-rebase НЕ запускается, ветка не пушится повторно. - **FAIL:** возвращает `False`, либо выполняет ненужный rebase/push. ## AC-2 — Ветка отстаёт + чистый догон + зелёный re-test → проход - **Дано:** ветка отстаёт от `origin/main`; rebase проходит без текстового конфликта; тест-набор на догнанной ветке зелёный. - **Когда:** выполняется merge-gate. - **PASS:** ветка догнана до `origin/main`, запушена `--force-with-lease`, re-test зелёный, гейт возвращает `(True, ...)`. - **FAIL:** гейт возвращает `False` при чистом догоне и зелёном re-test, либо `main` тронут, либо push выполнен НЕ через `--force-with-lease`. ## AC-3 — Текстовый конфликт rebase → откат на development, без слияния - **Дано:** auto-rebase упирается в текстовый конфликт. - **Когда:** выполняется merge-gate. - **PASS:** rebase отменён (worktree чист), гейт возвращает `(False, "rebase conflict...")`, задача переведена на `development`, в Plane — комментарий с причиной, слияния в `main` нет. - **FAIL:** ветка осталась в конфликтном состоянии, или задача продвинулась к слиянию, или `main` изменён. ## AC-4 — Красный re-test после догона → откат на development, без слияния - **Дано:** rebase чистый, но тесты на догнанной ветке падают. - **Когда:** выполняется merge-gate. - **PASS:** гейт возвращает `(False, "re-test failed after rebase...")`, задача на `development`, комментарий в Plane, слияния нет. - **FAIL:** гейт вернул `True`, либо слияние произошло при красном re-test. ## AC-5 — Сериализация слияний (merge-lock) - **Дано:** две задачи одного `repo` одновременно подходят к merge-gate. - **Когда:** обе пытаются пройти гейт. - **PASS:** «догон+re-test+слияние» выполняет одновременно только одна задача; вторая ждёт освобождения lock (в пределах `merge_lock_timeout_s`), после чего повторно сверяет «не отстаёт» и при необходимости догоняется. Воспроизводимый сценарий «две зелёные ветки ломают main» НЕ приводит к красному `main`. - **FAIL:** обе задачи параллельно проходят гейт и вливаются, воспроизводя гонку. ## AC-6 — Re-test тайм-аут управляем - **Дано:** re-test превышает `settings.merge_retest_timeout_s`. - **PASS:** прогон прерывается, гейт возвращает `(False, "re-test timeout...")`, задача не виснет, идёт штатный откат. - **FAIL:** задача висит дольше тайм-аута или падает с необработанным исключением. ## AC-7 — Никогда не push/merge в main напрямую из гейта - **PASS:** код merge-gate не выполняет `git push ... main` и не форс-пушит `main`; force-операции — только `--force-with-lease` по ветке задачи. - **FAIL:** найден любой push/force-push в `main` из логики гейта. ## AC-8 — Изоляция в worktree - **PASS:** все git-операции гейта идут в worktree ветки (`get_worktree_path` / `ensure_worktree`), а не в общем `/repos/` clone. - **FAIL:** rebase/тесты выполняются в общем clone, создавая S-4-гонку. ## AC-9 — Контракт never-raise - **Дано:** недоступен git/сеть, бит worktree, отсутствует ветка и т.п. - **PASS:** `check_branch_mergeable` и функции `merge_gate.py` возвращают `(False, "")` (или безопасный фоллбэк), НИКОГДА не пробрасывают исключение в `advance_stage`. - **FAIL:** любое необработанное исключение всплывает из гейта. ## AC-10 — Реестр QG и снапшоты консистентны - **PASS:** `"check_branch_mergeable"` зарегистрирован в `QG_CHECKS` и callable; `tests/test_qg_registry_snapshot.py` (`_EXPECTED_QGS`, при изменении стадий — `_EXPECTED_TRANSITIONS`) обновлены и зелёные; порядок ключей `STAGE_TRANSITIONS` сохранён (не сломан `get_previous_stage`). - **FAIL:** дрейф реестра/стадий без обновления снапшотов; красные snapshot-тесты. ## AC-11 — Интеграция отката в stage_engine - **PASS:** в `_handle_qg_failure_rollbacks` есть ветка merge-gate FAIL → `development` с уведомлениями (Plane + Telegram) и учётом `MAX_DEVELOPER_RETRIES`; `_run_qg` корректно диспетчеризует новый чек. - **FAIL:** FAIL гейта не приводит к откату, или нет уведомления, или зацикливание заворотов. ## AC-12 — Условный no-op / выключение (если реализовано) - **Дано:** `settings.merge_gate_enabled = False` (или репо вне `merge_gate_repos`). - **PASS:** гейт возвращает `(True, "merge-gate disabled")`, конвейер работает как прежде. - **FAIL:** гейт блокирует/ломает конвейер при выключенном флаге. ## AC-13 — Документация обновлена (golden source) - **PASS:** обновлены `docs/architecture/README.md` (merge-gate/auto-rebase/re-test, при изменении — таблицы стадий/реестра), `CHANGELOG.md`, `.env.example` (новые `ORCH_*` настройки); создан ADR `06-adr/ADR-001-merge-gate.md`. - **FAIL:** функционал изменён, документация/ADR/CHANGELOG не обновлены (Reviewer → REQUEST_CHANGES). ## AC-14 — Безопасность self-hosting - **PASS:** в рамках задачи прод-контейнер `orchestrator` (8500) не рестартился и не падал; изменения не трогают `.env*`, `docker-compose.yml`, прод-инфраструктуру; страховка стадией `deploy-staging` сохранена. - **FAIL:** любой рестарт/падение прод-оркестратора или правка прод-инфры в рамках задачи. ## AC-15 — Зелёный регресс - **PASS:** `pytest tests/ -q` зелёный целиком (новые тесты ORCH-043 + существующий набор). - **FAIL:** любой упавший/сломанный существующий тест.