Files
claude-bot 77e7205ce8
All checks were successful
CI / test (push) Successful in 14s
analyst(ET): auto-commit from analyst run_id=182
2026-06-06 16:39:20 +00:00

13 KiB
Raw Permalink Blame History

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):

  1. Захватить merge-lock для repo (с тайм-аутом). Не удалось → (False, "merge-lock busy").
  2. Если ветка не отстаёт от origin/main(True, "branch up-to-date with main").
  3. Иначе auto_rebase_onto_main:
    • конфликт → (False, "rebase conflict: ...");
    • успех → retest_branch:
      • зелёный → (True, "rebased onto main, re-test green");
      • красный/тайм-аут → (False, "re-test failed after rebase: ...").
  4. Освободить 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.