Files

14 KiB
Raw Permalink Blame History

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. Цель эпика

Дать оркестратору масштаб автономности: накидать вечером 1020 задач и получить к утру последовательно проведённый через весь конвейер (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-hosting done достигается 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 останавливает пакет — нужна наблюдаемость и ручное снятие.