13 KiB
02 — Техническое задание (ТЗ)
Work Item: ORCH-043 Тема: merge-gate + auto-rebase + re-test (безопасная параллель в одном репо) Автор: Analyst
ТЗ описывает ТРЕБУЕМОЕ поведение и конкретные точки изменения кода. Окончательный выбор места встройки в конвейер (новая стадия vs гейт существующего перехода vs шаг перед слиянием) и детали reconciliation — за архитектором (ADR в
06-adr/). Если ТЗ окажется нереализуемым — вернуть на стадиюanalysis, не комментировать задним числом.
1. Задействованные модули src/
| Модуль | Роль в изменении |
|---|---|
src/merge_gate.py (новый) |
Ядро фичи: ancestor-check, auto-rebase, re-test, merge-lock. Чистые функции + git-операции в worktree. |
src/qg/checks.py |
Новый QG-check check_branch_mergeable (merge-gate) + регистрация в QG_CHECKS. Переиспользует паттерн check_tests_local (pytest в worktree) и _repo_path. |
src/stages.py |
Встройка merge-gate в STAGE_TRANSITIONS (точное место — за архитектором; см. §6). |
src/stage_engine.py |
Ветка отката merge-gate → development в _handle_qg_failure_rollbacks + диспетчеризация нового check в _run_qg. |
src/git_worktree.py |
Возможные хелперы: проверка «behind origin/main», rebase, push --force-with-lease. Не ломать сигнатуры ensure_worktree / get_worktree_path. |
src/config.py |
Новые settings: тайм-аут re-test, вкл/выкл гейта, политика отстающей ветки, тайм-аут lock. |
src/agents/launcher.py |
Если merge-gate встраивается как шаг перед слиянием на стадии deploy — точка, где deployer запускается, может потребовать координации с lock (за архитектором). |
tests/ |
Новые тесты (см. 04-test-plan.yaml) + обновление snapshot-тестов реестра/стадий. |
2. Функциональные требования к src/merge_gate.py
Предлагаемый публичный контракт (имена финализирует архитектор; поведение обязательно):
2.1 branch_is_behind_main(repo, branch) -> bool
git fetch origin mainв main-clone/worktree (best-effort, never-raise → трактуем как «не удалось определить» и НЕ пропускаем слияние вслепую).- Ветка считается отстающей, если
origin/mainне является предком HEAD ветки (git merge-base --is-ancestor origin/main <branch>→ ненулевой код).
2.2 auto_rebase_onto_main(repo, branch) -> (ok: bool, reason: str)
- Выполняется в изолированном worktree ветки (
ensure_worktree), НЕ в общем clone. - Догнать ветку до
origin/main(rebase либо merge — выбор архитектора; критично: результат содержит весьorigin/mainи историю/изменения ветки). - Текстовый конфликт → отменить операцию (
git rebase --abort/git merge --abort), worktree оставить чистым, вернуть(False, "rebase conflict: <файлы>"). - Чистый догон →
git push --force-with-lease origin <branch>(ТОЛЬКО ветка задачи, НИКОГДАmain). Вернуть(True, ...). - Контракт never-raise: любая git/OS-ошибка →
(False, "<reason>"), не исключение.
2.3 retest_branch(repo, branch) -> (ok: bool, reason: str)
- Прогнать тест-набор проекта в worktree догнанной ветки. Канон — как в
check_tests_local:python -m pytest(точная команда/каталог — за архитектором, согласованно с CI-конфигом.gitea/workflows/). - Тайм-аут
settings.merge_retest_timeout_s; превышение →(False, "re-test timeout"). - Возврат:
(True, "re-test green")при коде 0, иначе(False, "re-test failed: <tail>").
2.4 Merge-lock (сериализация, BR-5)
- Реализовать межзадачную сериализацию «догон+re-test+слияние» в пределах одного
repo. - Допустимые реализации (выбор архитектора): файловый lock в
repos_dir, advisory-lock, либо строка-замок в SQLite. Требования: restart-safe, с тайм-аутомsettings.merge_lock_timeout_s, корректное освобождение при ошибке/падении. - Под локом: повторно сверить «не отстаёт» ПОСЛЕ захвата (double-check), т.к.
mainмог уйти, пока ждали lock.
3. Новый QG-check (src/qg/checks.py)
check_branch_mergeable(repo, work_item_id, branch) -> tuple[bool, str]
Поведение (детерминированно, без участия LLM):
- Захватить merge-lock для
repo(с тайм-аутом). Не удалось →(False, "merge-lock busy"). - Если ветка не отстаёт от
origin/main→(True, "branch up-to-date with main"). - Иначе
auto_rebase_onto_main:- конфликт →
(False, "rebase conflict: ..."); - успех →
retest_branch:- зелёный →
(True, "rebased onto main, re-test green"); - красный/тайм-аут →
(False, "re-test failed after rebase: ...").
- зелёный →
- конфликт →
- Освободить lock в
finally.
- Зарегистрировать в
QG_CHECKSпод ключом"check_branch_mergeable". - Контракт never-raise (как у соседних чеков): исключение →
(False, "<reason>").
Опционально (за архитектором): флаг
settings.merge_gate_enabled; приFalseчек возвращает(True, "merge-gate disabled")(безопасный no-op для постепенного раскатывания, по образцу условного staging-гейта ORCH-35).
4. Изменения схемы БД
- Не требуется для базовой реализации (lock через файл/advisory).
- ЕСЛИ архитектор выберет lock через SQLite — добавить таблицу/строку-замок миграцией,
совместимой с текущей инициализацией
src/db.py(никаких ломающих измененийtasks,agent_runs,jobs,events). Это решение фиксируется в ADR.
5. Изменения API
- Новых HTTP-эндпоинтов не требуется.
- Допустимо (не обязательно) расширить
GET /statusилиGET /queueиндикатором «merge-gate: rebasing/re-testing/locked» для наблюдаемости — на усмотрение архитектора, без изменения существующих контрактов ответов.
6. Точки встройки в конвейер (требование + кандидаты)
Требование: merge-gate отрабатывает как можно ближе к фактическому слиянию в main
и ДО него. Слияние ветки в main НЕ должно происходить в обход гейта.
Кандидаты (окончательно — ADR архитектора):
- (A) Гейт на переходе
deploy-staging → deployили новый под-гейт перед слиянием: deployer вливает PR на стадииdeploy, поэтому проверка «догнать+re-test» логично встаёт непосредственно перед запуском deployer. - (B) Новая стадия
merge-gateмеждуdeploy-stagingиdeployс агентом=None иqg="check_branch_mergeable". - (C) Перенести само слияние в
mainиз ответственности deployer-агента в детерминированный шаг оркестратора, защищённый merge-gate (более крупное изменение).
При любом варианте, меняющем STAGE_TRANSITIONS или QG_CHECKS:
- обновить
docs/architecture/README.md(таблица стадий + реестр QG, §«Конвейер»); - обновить snapshot-тесты
tests/test_qg_registry_snapshot.py(_EXPECTED_QGS,_EXPECTED_TRANSITIONS) — осознанно, в этом же PR; - сохранить порядок ключей
STAGE_TRANSITIONS(от него зависитget_previous_stage).
7. Откаты (интеграция со stage_engine)
В _handle_qg_failure_rollbacks добавить ветку для merge-gate FAIL по образцу
check_staging_status / check_deploy_status:
update_task_stage(task_id, "development"),set_issue_blocked(work_item_id);- комментарий в Plane (
plane_add_comment, author="deployer" или системный) с причиной (конфликт rebase / красный re-test) — дословныйreasonгейта; - Telegram-алерт (
send_telegram); - учитывать
MAX_DEVELOPER_RETRIES, не плодить бесконечные заворот-циклы. - В
_run_qgдобавить диспетчеризациюcheck_branch_mergeableс сигнатурой(repo, work_item_id, branch)(как у артефактных чеков).
8. Изменения конфигурации (src/config.py, env-префикс ORCH_)
| Setting | Назначение | Дефолт (предложение) |
|---|---|---|
merge_gate_enabled: bool |
Глобальный вкл/выкл гейта | True |
merge_retest_timeout_s: int |
Тайм-аут повторного прогона тестов | 600 |
merge_lock_timeout_s: int |
Тайм-аут ожидания merge-lock | 300 |
merge_gate_repos: str |
(опц.) ограничить гейт списком репо; пусто = все | "" |
Значения и имена финализирует архитектор; задокументировать в .env.example и
docs/architecture/README.md.
9. Требования к наблюдаемости / документации (golden source)
- Обновить
docs/architecture/README.md: описание merge-gate, auto-rebase, re-test, merge-lock; при изменении стадий/реестра — соответствующие таблицы. - Обновить
CHANGELOG.md. - Завести ADR
docs/work-items/ORCH-043/06-adr/ADR-001-merge-gate.md(механизм догона, выбор rebase vs merge, реализация lock, место встройки). - Все ветки кода — с лог-сообщениями (
logger.info/warning/error) по образцу соседних гейтов, чтобы поведение читалось в/app/data/runsи логах сервиса.
10. Нефункциональные требования
- Безопасность self-hosting: никогда не push в
main; force только--force-with-leaseпо ветке задачи; прод-контейнерorchestratorне рестартить/не ронять. - Изоляция: все git-операции — в worktree ветки (
ensure_worktree), не в общем clone, чтобы не словить S-4-гонку параллельных задач. - Идемпотентность/restart-safe: lock и гейт корректно ведут себя при рестарте сервиса.
- Never-raise контракт у всех новых чеков/парсеров (как в текущем
src/qg/checks.py). - Совместимость: не менять сигнатуры/поведение существующих QG-чеков и вебхуков.
11. Артефакты pipeline, которые должны быть созданы/обновлены
src/merge_gate.py(новый), изменения вsrc/qg/checks.py,src/stages.py,src/stage_engine.py,src/config.py, при необходимостиsrc/git_worktree.py.- Новые тесты в
tests/+ обновлённые snapshot-тесты. docs/architecture/README.md,CHANGELOG.md,.env.example,docs/work-items/ORCH-043/06-adr/ADR-001-merge-gate.md.