Files
orchestrator/docs/architecture/adr/adr-0006-merge-gate.md
claude-bot ad1589084b
All checks were successful
CI / test (push) Successful in 14s
architect(ET): auto-commit from architect run_id=183
2026-06-06 17:16:00 +00:00

4.3 KiB
Raw Blame History

adr-0006: Merge-gate — догон main + re-test + сериализация слияний

  • Статус: proposed
  • Дата: 2026-06-06
  • Задача: ORCH-043
  • Детальный ADR: docs/work-items/ORCH-043/06-adr/ADR-001-merge-gate.md

Контекст

Ветка валидируется относительно того main, из которого создана, а не относительно main на момент слияния. Параллельная задача могла влиться раньше → семантический конфликт слияния (git мержит без текстового конфликта, но main сломан). Для self-hosting это красный main инструмента, обслуживающего все проекты. Слияние в main делает deployer-агент в начале стадии deploy; замена механизма PR-merge — вне объёма.

Решение

Детерминированный merge-gate (check_branch_mergeable, без LLM) на ребре deploy-staging → deploy, ДО запуска deployer'а, который мержит. STAGE_TRANSITIONS не меняется (минимальный blast-radius); в QG_CHECKS добавлен check_branch_mergeable.

  • Догон: ветка отстаёт ⇔ origin/main не предок HEAD → rebase origin/main в worktree
    • push --force-with-lease (ТОЛЬКО ветка задачи; main — никогда). Текстовый конфликт → rebase --abort → откат на development.
  • Re-test: python -m pytest tests/ в worktree догнанной ветки, тайм-аут merge_retest_timeout_s. Красный/тайм-аут → откат на development.
  • Сериализация (BR-5): файловый merge-lease на репо (<repos_dir>/.merge-lease-<repo>.json), живёт от гейта до фактического merge. Acquire неблокирующий (anti-deadlock при max_concurrency=1): busy → defer (re-enqueue deployer с задержкой через available_at), не rollback. Release — на PR-merged вебхуке / deploy→done / откате / по возрасту (crash-реклейм). Restart-safe.
  • Условность (как ORCH-35): реален для orchestrator; прочие репо — no-op. Флаги merge_gate_enabled / merge_gate_repos для поэтапного раската.

Альтернативы

  • Новая стадия merge-gate (кандидат B) — «пустая» стадия без агента не имеет триггера (advance_stage срабатывает только на завершении агента/вебхуке); потребовала бы chaining в движке (не restart-safe) или синтетический job-тип. Отклонено.
  • Перенос merge в детерминированный шаг оркестратора (кандидат C) — запрещён объёмом (замена механизма PR-merge вне scope). Отклонено.
  • Блокирующий lock — дедлок при одном worker-слоте. Отклонено в пользу defer.

Последствия

  • Сценарий «две зелёные ветки ломают main» закрыт: re-test против актуального main + сериализация слияний.
  • Плата: merge-gate — «скрытый» под-гейт ребра (нет в STAGE_TRANSITIONS); сериализация опирается на PR-merged вебхук со страховкой реклеймом по возрасту; defer перепрогоняет staging; длинный re-test держит worker-слот.
  • Сквозное изменение конвейера → arch:major-change; прод-деплой ORCH-043 строго через staging-гейт (8501).

Связи

adr-0001 (is_self_hosting_repo), adr-0003 (условный staging-гейт — образец условности), adr-0002 (очередь / available_at для defer), ORCH-2 (worktree-изоляция), ORCH-046 (дословный reason в task_desc при откате).