14 KiB
01 — BRD: ORCH-088 — Пакетный автономный режим (Этап 1: serial e2e)
Work Item: ORCH-088 Repo: orchestrator (self-hosting) Стадия: analysis Заказчик: Слава Тип: ЭПИК — Этап 1 (минимальный, без параллелизма)
⚠️ Скоп зафиксирован Владельцем 09.06. Реализуется ТОЛЬКО serial e2e (FR-1…FR-5). Фазовый режим A/B/C, merge-очередь FIFO, pre-merge rebase и зависимость от ORCH-83 — ОТМЕНЕНЫ, не реализовывать.
1. Бизнес-контекст и проблема
1.1. Цель эпика
Дать оркестратору масштаб автономности: накидать вечером 10–20 задач и получить к утру последовательно проведённый через весь конвейер (analysis → … → deploy → done) пакет — без ручного запуска каждой задачи и без взаимного повреждения веток.
1.2. Корневая проблема — «stale-анализ» (логический, а не код-затирание)
Конвейер создаёт ветку задачи от main. Если задача N+1 входит в анализ, пока задача N
ещё не влита в main, то ветка N+1 срезается от устаревшего main (без кода N). Результат:
- семантически устаревшая база разработки;
- риск потери/переоткрытия уже сделанного в N (накопительные потери прецедента — постмортем фантомного merge, см. CLAUDE.md / ORCH-071);
- ручной разбор конфликтов утром вместо готового пакета.
Физическое код-затирание при параллельном merge уже закрыто (ORCH-026 auto_rebase + merge-lease).
ORCH-088 закрывает логический разрыв: гарантирует, что каждая следующая задача стартует от
main, уже содержащего все предыдущие завершённые задачи репо.
1.3. Почему сериализация именно «от АНАЛИЗА», а не «от merge»
Ветка срезается в самом начале — на входе в анализ (start_pipeline создаёт ветку в Gitea, далее
worktree). Если допустить параллельный анализ N и N+1, ветка N+1 уже срезана от старого main —
поздняя сериализация на merge проблему не лечит. Поэтому gate ставится на входе новой задачи в
анализ: новая задача не начинает анализ (и не режет ветку), пока в репо есть незавершённая задача.
1.4. Установленные факты (проверено, не изобретать)
- Plane API v1: bulk-операций НЕТ; issue-relation НЕТ → зависимости/очередь оркестратор хранит у себя (gate в планировщике/claim по локальной БД), не в Plane.
- Уже есть (переиспользовать):
max_concurrency=1; ORCH-026 auto_rebase_onto_main + force-with-lease + merge-lease; персистентная очередь ORCH-1 (таблицаjobs, atomic claim, restart-safe); ORCH-021 post-deploy monitor (для self — всегдаALERT_ONLY, db-стадияdoneдостигается ДО окна мониторинга — ORCH-071/066).
1.5. Решения Владельца (09.06) — приняты как требования
| # | Решение |
|---|---|
| D-1 | Serial e2e подтверждён. BRD появляются по одному — осознанный размен: надёжность > батч-просмотр BRD. |
| D-2 | Сигнал «задача завершена» = успешный прод-деплой (stage = done после прод-деплоя). НЕ merge, НЕ staging. |
| D-3 | Мониторинг (~15 мин) НЕ ждём: gate N+1 открывается по stage = done, не по завершению окна мониторинга. |
| D-4 | Auto-rollback прода во время мониторинга → заморозить gate + алерт; следующая НЕ стартует до ручного снятия. |
| D-5 | Зависимость ORCH-088 ← ORCH-83 убрана — запускается независимо. |
2. Объём (scope)
2.1. В объёме (Этап 1)
- FR-1 — Serial gate (per-repo): новая задача не входит в
analysis(не режет ветку, не запускает analyst), пока в том же репо есть незавершённая задача (stage < done). - FR-2 — Очередь e2e: накиданные задачи становятся в очередь и обрабатываются строго по одной end-to-end (от анализа до прод-деплоя).
- FR-3 — Per-repo изоляция: сериализация действует внутри одного репо; разные репо
(
orchestrator,enduro-trails) идут параллельно (независимыеmain). - FR-4 — Restart-safe: активная задача и состояние gate определяются по БД (не in-memory) — переживают рестарт оркестратора.
- FR-5 — Rollback-freeze: auto-rollback / деградация прода → gate репо заморожен + Telegram- алерт; следующая задача не стартует до ручного снятия заморозки.
2.2. Вне объёма (явно, не делать)
- Merge-очередь FIFO; pre-merge rebase как отдельная фича; фазовый режим A/B/C; любая координация параллелизма задач внутри одного репо.
- Изменение
STAGE_TRANSITIONS, реестраQG_CHECKS, новых стадий конвейера. - Зависимость от ORCH-83.
3. Заинтересованные стороны
- Владелец/оператор (Слава): накидывает пакет вечером, разбирает заморозку при сбое, читает алерты, снимает freeze вручную.
- Self-hosting прод (
orchestrator): обслуживает enduro-trails из того же инстанса — нельзя ронять/блокировать конвейер enduro (FR-3).
4. Бизнес-требования (BR)
| ID | Требование | Связь |
|---|---|---|
| BR-1 | Пока в репо есть задача со stage < done, любая другая задача того же репо не начинает анализ — ждёт в очереди. |
FR-1, AC-1 |
| BR-2 | Как только активная задача достигла stage = done (после прод-деплоя), следующая задача того же репо автоматически стартует анализ. |
FR-1/FR-2, AC-2, D-2 |
| BR-3 | Ветка новой задачи срезается от main, уже содержащего все ранее завершённые задачи репо — нет stale-base. Branch не создаётся раньше, чем предшественник завершён. |
FR-1, AC-6, §1.2 |
| BR-4 | Сериализация — строго per-repo; задачи разных репо идут параллельно, gate одного репо не влияет на другой. | FR-3, AC-4 |
| BR-5 | Активная задача и факт заморозки определяются из БД; после рестарта оркестратора gate ведёт себя идентично (не «забывает» активную задачу и не «теряет» freeze). | FR-4, AC-3 |
| BR-6 | Auto-rollback/деградация прода (post-deploy) → per-repo freeze + Telegram-алерт; следующая задача не стартует до ручного снятия freeze. | FR-5, AC-5, D-4 |
| BR-7 | Мониторинг прода (~15 мин) gate не ждёт — открытие gate привязано к stage = done. (Freeze BR-6 — отдельный, независимый от stage сигнал, т.к. к моменту деградации задача уже done.) |
D-3, AC-5 |
| BR-8 | Поведение управляется kill-switch'ом и областью репо (как ORCH-35/43/58): выключение флага → строго прежнее поведение (нулевая регрессия для enduro). | NFR |
| BR-9 | Состояние gate наблюдаемо в GET /queue (активная задача репо, очередь ожидающих, статус freeze). |
NFR |
5. Нефункциональные требования (NFR)
| ID | Требование |
|---|---|
| NFR-1 | never-raise: любая ошибка логики gate не роняет claim/конвейер. Поведение при ошибке БД — fail-open для claim (транзиентный сбой не должен заклинить очередь ВСЕХ проектов), fail-closed для freeze (сомнение в безопасности прода → не стартовать). |
| NFR-2 | Offline-устойчивость: проверка gate в горячем цикле claim не должна ходить в сеть (Plane/Gitea) — иначе встанет очередь всех проектов. Источник истины — локальная БД. |
| NFR-3 | Restart-safe: никакого in-memory состояния; freeze и активная задача — в БД. |
| NFR-4 | Нулевая регрессия: при выключенном флаге запрос claim и путь старта идентичны текущим; enduro не затрагивается. |
| NFR-5 | Инварианты неизменны: STAGE_TRANSITIONS, реестр QG_CHECKS, check_*, exit-коды deploy-хука, merge-gate, схема post-deploy — не меняются (допустима только аддитивная, идемпотентная миграция БД). |
| NFR-6 | Self-hosting безопасность: механизм не рестартит/не роняет прод-контейнер; freeze — пассивная остановка стартов, не действие над прод. |
6. Допущения и ограничения
max_concurrency = 1остаётся (Этап 1 без параллелизма); gate не зависит от значения, но не ослабляет его.- «Завершена» =
tasks.stage = 'done'. Для self-hostingdoneдостигается merge-verify + прод-деплой (ORCH-071/036); пост-деплойное окно мониторинга идёт послеdoneи gate его не ждёт (BR-7). - Задача в статусе Blocked / Needs Input имеет
stage < doneи, следовательно, держит gate закрытым — это сознательное поведение (Этап 1): пока задача не доведена до прод или не закрыта оператором, пакет не движется. (Поведение зафиксировать в AC; альтернатива — вне скопа.) - Снятие freeze (BR-6) — ручное (оператор), автоматического разбора деградации нет.
7. Критерии успеха (резюме; детали — 03-acceptance-criteria.md)
- AC-1 активная задача (
stage<done) → новая не стартует анализ. - AC-2 активная достигла
done→ следующая стартует автоматически. - AC-3 gate переживает рестарт (состояние в БД).
- AC-4 разные репо идут параллельно.
- AC-5 auto-rollback → freeze + алерт, следующая не стартует до ручного снятия.
- AC-6 каждая ветка срезана от
mainсо всеми предыдущими завершёнными задачами репо (нет stale-base).
8. Риски (детали — 10-tech-risks.md, заполняет архитектор)
- R-1: stale-base сохраняется, если ветка режется на входе (
_create_gitea_branchвstart_pipeline) до завершения предшественника — gate обязан отсрочить создание ветки, а не только claim. - R-2: gate, ошибочно fail-closed на транзиентной ошибке БД, заклинит очередь всех проектов.
- R-3: «вечный freeze» / залипшая активная задача в Blocked останавливает пакет — нужна наблюдаемость и ручное снятие.