10 KiB
01 — Business Requirements Document (BRD)
Work Item: ORCH-043 Тема: Безопасная параллель в одном репо: merge-gate + auto-rebase + re-test Проект: orchestrator (self-hosting) Автор: Analyst Дата: 2026-06-06
1. Контекст и проблема
Оркестратор ведёт несколько work item параллельно, каждый в своём изолированном
git worktree / ветке (feature/ORCH-NNN-slug, ORCH-2/S-4). Все ветки одного проекта
исходят из общего origin/main и в конце конвейера вливаются обратно в main.
Текущий конвейер валидирует ветку относительно того состояния main, из которого
она была создана, а не относительно main на момент слияния:
check_ci_green(стадияdevelopment) — CI зелёный на ветке (Gitea commit status ветки).check_tests_passed(стадияtesting) — вердикт тестировщика по коду ветки.- На стадии
deployветка вливается вmain(слияние выполняет deployer-агент, см.src/webhooks/gitea.py— комментарий про «deployer merges the PR at the START of its run»).
Между «ветка проверена» и «ветка влита» main мог уйти вперёд из-за слияния другой
параллельной задачи. Возникает семантический (логический) конфликт слияния: git
сливает ветки без текстового конфликта, но объединённый код main сломан — тесты,
которые были зелёными на ветке, на обновлённом main падают.
Почему это критично именно здесь (self-hosting)
Проект ORCH правит инструмент, который СЕЙЧАС работает в проде и обслуживает другие
проекты (enduro-trails) из одного инстанса с общей БД и общей очередью (см. CLAUDE.md,
docs/operations/INFRA.md). Сломанный main оркестратора = встал конвейер ВСЕХ проектов.
Две параллельные ORCH-задачи, каждая «зелёная» по отдельности, при последовательном
слиянии способны положить прод.
Сценарий-иллюстрация
- Задачи A и B ответвлены от
main@C0. - A проходит конвейер, вливается →
main@C1. - B тестировалась против
C0; её CI зелёный относительноC0. Git-слияние B вC1проходит без текстового конфликта, ноC1содержит изменения A, ломающие B. mainстановится красным. Конвейер всех проектов деградирует.
2. Цель
Гарантировать, что ветка вливается в main только если она проверена против
актуального origin/main. Перед слиянием ветка автоматически догоняет main
(auto-rebase) и повторно тестируется (re-test); зелёный результат на актуальном
main — обязательное условие слияния (merge-gate). Слияния в main одного репозитория
сериализуются, чтобы окно гонки не воспроизводилось между двумя гейтами.
3. Заинтересованные стороны
- Owner / разработчики — не хотят красный
mainи ручные разборы конфликтов. - Все проекты на инстансе — зависят от живого прод-оркестратора.
- Агенты конвейера — получают детерминированный гейт вместо ручной координации.
4. Объём (Scope)
В объёме
- Merge-gate — детерминированный гейт перед слиянием в
main: пропускает слияние только если ветка не отстаёт отorigin/mainИ повторная проверка зелёная. - Auto-rebase — если ветка отстаёт от
origin/main, автоматически догнатьmain(rebase/merge ветки на актуальныйorigin/main) в worktree и запушить результат. - Re-test — после auto-rebase повторно прогнать тест-набор на догнанной ветке; зелёный результат — условие прохода гейта.
- Сериализация слияний — в пределах одного репозитория одновременно «догон+слияние» выполняет только одна задача (merge-lock), иначе гонка воспроизводится.
- Откаты при неуспехе — текстовый конфликт rebase ИЛИ красный re-test → возврат
задачи на
development(по образцу существующих откатов) с понятным комментарием. - Конфигурируемость — пороги/тайм-ауты re-test и поведение гейта вынесены в
settings.
Вне объёма
- Изменение логики стадий
analysis/architecture/review. - Замена самого механизма слияния PR в Gitea (UI/настройки репозитория).
- Реальные прод-деплои (остаются за
scripts/orchestrator-deploy-hook.sh). - Кросс-репозиторная сериализация (гейт защищает
mainкаждого репо отдельно).
5. Бизнес-требования (BR)
| ID | Требование |
|---|---|
| BR-1 | Перед слиянием ветки в main оркестратор обязан проверить, что ветка содержит последний origin/main (не отстаёт). |
| BR-2 | Если ветка отстаёт — оркестратор автоматически догоняет её до origin/main без участия человека (auto-rebase). |
| BR-3 | После догона тест-набор повторно прогоняется; слияние разрешено только при зелёном результате (re-test). |
| BR-4 | Текстовый конфликт при auto-rebase или красный re-test НЕ приводит к слиянию: задача откатывается на development для ручного фикса. |
| BR-5 | В пределах одного репозитория «догон+проверка+слияние» сериализуются: две задачи не могут одновременно пройти merge-gate и влиться. |
| BR-6 | Гейт детерминированный (Python/гит-команды + код тестов), а не доверие LLM-агенту. |
| BR-7 | Гейт обязателен минимум для self-hosting репозитория orchestrator; применим к любому репо с параллельными задачами. |
| BR-8 | Все события гейта (догон, re-test, проход/откат) логируются и отражаются комментарием в Plane, без рассинхрона стадий. |
6. Критерии успеха
- Воспроизводимый ранее сценарий «две зелёные ветки ломают
main» более не приводит к красномуmain: вторая ветка либо догоняется и проходит re-test, либо откатывается. - Прод-контейнер
orchestratorне перезапускается и не падает в рамках задачи. - Реестр гейтов и стадий остаётся консистентным (snapshot-тесты обновлены осознанно).
7. Риски и ограничения
- Гонка между двумя гейтами — снимается merge-lock (BR-5); без него фикс неполон.
- Долгий re-test — нужен тайм-аут и понятный откат, а не вис задачи.
- Force-push догнанной ветки — допустим только
--force-with-leaseи только по own-ветке задачи; никогда поmain. - Self-hosting — любые изменения не должны ронять/рестартить прод-оркестратор;
обязательная страховка стадией
deploy-staging(порт 8501) сохраняется. - Окончательное место встройки в конвейер (новая стадия / гейт существующего перехода / шаг перед слиянием) — решение архитектора (ADR), BRD фиксирует требуемое поведение.
8. Связанные артефакты
02-trz.md— техническое задание (модули, гейт, конфиг, точки встройки).03-acceptance-criteria.md— критерии приёмки PASS/FAIL.04-test-plan.yaml— план тестов.- Контекст кода:
src/qg/checks.py,src/stage_engine.py,src/git_worktree.py,src/agents/launcher.py,src/webhooks/gitea.py,src/stages.py,src/config.py.