# 03-Критерии приёмки — ORCH-026

**Work Item:** ORCH-026 · **Repo:** orchestrator · **Стадия:** analysis

Каждый критерий — проверяемое условие PASS/FAIL. Маппинг на тесты — `04-test-plan.yaml`.

---

## Уровень A — Сериализация merge/деплоя внутри одного репо

### AC-A1 — Сериализация merge внутри репо
- **PASS:** пока задача A применимого репо удерживает окно merge (merge-lease не освобождён /
  `main` ещё не обновлён), задача B того же репо НЕ доходит до фактического merge — она
  **defer**-ится (повторная постановка через `available_at`), а не мержится от устаревшего `main`.
- **FAIL:** B мержится/деплоится, пока A не в `main`; или B откатывается на `development` вместо
  defer.

### AC-A2 — Proactive pre-merge rebase
- **PASS:** перед merge ветка задачи **всегда** догоняется на свежий `origin/main` (вызывается
  rebase), даже когда текстового конфликта нет и ветка формально не «behind» по старой проверке;
  после rebase ветка содержит код предшественника (A).
- **FAIL:** rebase запускается только при конфликте/`branch_is_behind_main`, и B мержится без
  кода A.

### AC-A3 — Кросс-репо параллелизм сохранён
- **PASS:** задача в `orchestrator` и задача в `enduro-trails` доходят до merge/деплоя
  параллельно — сериализация одного репо не блокирует другой (lease/гейт строго per-repo).
- **FAIL:** задача одного репо ждёт освобождения ресурса, удерживаемого задачей ДРУГОГО репо.

### AC-A4 — Restart-safe
- **PASS:** после рестарта прод-контейнера состояние сериализации восстанавливается корректно;
  мёртвый держатель merge-lease проактивно реклеймится (ORCH-065), конвейер не встаёт навсегда.
- **FAIL:** рестарт оставляет навсегда захваченный lease → конвейер всех проектов встаёт.

### AC-A5 — Self-hosting safety
- **PASS:** прод-контейнер orchestrator НЕ рестартится/не падает вне штатного `Confirm Deploy`
  (ORCH-059); нет push/force-push в `main`; `STAGE_TRANSITIONS` и реестр `QG_CHECKS` не изменены.
- **FAIL:** любой незапрошенный рестарт прода, прямой push в `main`, или изменение машины стадий.

### AC-A6 — Anti-deadlock / anti-livelock при defer
- **PASS:** при занятой сериализации B defer-ится с задержкой и bounded бюджетом; исчерпание
  бюджета → эскалация (alert/Blocked), не бесконечный цикл и не откат.
- **FAIL:** B уходит в вечный defer-цикл, либо немедленно откатывается на `development`.

### AC-A7 — Условность (не-self репо без регресса)
- **PASS:** при выключенном kill-switch и для репо вне scope поведение конвейера 1:1 как до
  ORCH-026 (нулевая регрессия для enduro-trails).
- **FAIL:** не-self репо меняет поведение merge/деплоя.

---

## Уровень B — Декларативные зависимости

### AC-B1 — Декларация зависимости
- **PASS:** задача может объявить `blocked-by`/`depends-on` (через выбранный источник —
  Plane relations / БД / гибрid), и связь корректно считывается планировщиком.
- **FAIL:** связь не считывается / теряется.

### AC-B2 — Гейт планировщика (B не стартует до A)
- **PASS:** задача с незавершённым depends-on **не клеймится** воркером (не запускается агент,
  слот `max_concurrency` не занимается), пока все depends-on не достигли `done`; как только A
  становится `done` — B становится claimable.
- **FAIL:** B запускается раньше завершения A; или занимает слот, простаивая.

### AC-B3 — Детект дедлоков (циклы)
- **PASS:** циклическая зависимость (A→B→A и длиннее) детектируется детерминированно; задача(и)
  в цикле → `Blocked` + alert (Telegram/Plane) с указанием цикла; поток остальных задач не
  блокируется.
- **FAIL:** цикл приводит к молчаливому вечному ожиданию или к падению воркера.

### AC-B4 — Видимость заблокированной задачи
- **PASS:** заблокированная задача видна — Plane-статус `Blocked` и/или строка ожидания в
  Telegram-карточке (что/кого ждёт); инвариант «одна карточка на задачу» сохранён.
- **FAIL:** заблокированная задача невидима наблюдателю.

### AC-B5 — Совместимость с reconciler/reaper
- **PASS:** `reconciler` F-1 НЕ «разблокирует» задачу, заблокированную по зависимости (как уже
  делает для Blocked/Needs-Input, ORCH-060/068); reaper не реапит корректно ожидающую задачу.
- **FAIL:** reconciler продвигает заблокированную задачу мимо её depends-on.

---

## Общие (оба уровня)

### AC-G1 — never-raise
- **PASS:** любая ошибка (git/сеть/БД/Plane) в новой логике не пробрасывается в `advance_stage`/
  воркер; деградирует консервативно (defer/skip/fail-closed), конвейер не падает.
- **FAIL:** необработанное исключение роняет воркер/монитор-поток.

### AC-G2 — Kill-switch
- **PASS:** глобальный kill-switch выключает фичу целиком → поведение 1:1 как до ORCH-026.
- **FAIL:** при выключенном флаге поведение изменено.

### AC-G3 — Документация обновлена (golden source)
- **PASS:** в ТОМ ЖЕ PR обновлены `docs/architecture/README.md`, `CLAUDE.md` (если изменилось
  поведение очереди), `CHANGELOG.md`, заведён ADR в `06-adr/`. Reviewer проверяет.
- **FAIL:** код изменён, документация — нет (→ REQUEST_CHANGES).

### AC-G4 — Миграция БД безопасна (если применимо)
- **PASS:** миграция только аддитивная (`CREATE TABLE IF NOT EXISTS`/`_ensure_column`),
  идемпотентна, безопасна на живой общей прод-БД; существующие данные enduro-trails не затронуты.
- **FAIL:** деструктивная миграция / изменение существующих колонок.

### AC-G5 — Тесты зелёные
- **PASS:** новые unit+integration тесты (`04-test-plan.yaml`) проходят; существующий
  `pytest tests/ -q` остаётся зелёным (нет регресса merge-gate/merge-verify/reconciler/reaper).
- **FAIL:** красный pytest или регресс существующих тестов.
