Files
orchestrator/docs/work-items/ORCH-082/02-trz.md

9.1 KiB
Raw Permalink Blame History

02 — ТЗ: ORCH-082 (ORCH-81)

Гарантированный идемпотентный код-PR перед merge-verify + наблюдаемость

Машина стадий, реестр QG_CHECKS, схема БД, exit-коды хука, контракты check_deploy_status/_parse_deploy_status, защита ORCH-073 (SHA-в-main) — НЕ меняются. Изменение — точечная врезка «ensure PR» в под-гейт merge-verify + новый идемпотентный PR-актор в merge_gate + структурное логирование.


1. Задействованные модули src/

Модуль Роль в задаче Характер изменения
src/merge_gate.py leaf-логика merge-актора (merge_pr, verify_merged_to_main, pr_already_merged) + новый идемпотентный актор ensure_open_pr(repo, branch) -> (status, detail) (never-raise).
src/stage_engine.py под-гейт _handle_merge_verify на ребре deploy → done врезка: вызвать ensure_open_pr ПЕРЕД merge_pr; на failed → честный HOLD+alert; логировать исход.
src/agents/launcher.py _ensure_pr (текущий единственный создатель PR) усилить наблюдаемость (различать created/existed/failed) — опционально переиспользовать новый актор merge_gate.ensure_open_pr, чтобы создание PR было единым кодом. Поведение «создавать только у developer» НЕ ужесточать без необходимости.
src/config.py флаги + kill-switch merge_verify_autocreate_pr_enabled (дефолт True), область — та же merge_verify_applies (self-hosting / merge_verify_repos).
docs/architecture/README.md, CHANGELOG.md golden source обновить (раздел ORCH-071/073 merge-verify — дописать про авто-создание PR).

Точная сигнатура ensure_open_pr, имя/дефолт kill-switch и место врезки — за архитектором (ADR). Ниже — функциональные требования к поведению, не финальный дизайн.

2. Функциональные требования

FR-1 — Идемпотентный PR-актор merge_gate.ensure_open_pr(repo, branch)

Возвращает структурированный исход (например ("existed"|"created"|"failed", detail)):

  1. GET …/pulls?state=open → если есть PR с head.ref==branch И base.ref=="main"("existed", <number>). Фильтр идентичен merge_pr/ORCH-073 FR-3 — авто-docs-PR (base != main) НЕ считается код-PR.
  2. Иначе POST …/pulls (head=branch, base=main, заголовок/тело — авто) → 201("created", <number>).
  3. Идемпотентность: если параллельно PR уже создан и Gitea вернёт ошибку «PR exists» — повторный GET подтверждает существующий PR и возвращает ("existed", …), дубль не плодится (AC-2).
  4. Любая иная ошибка HTTP/parse/сети → ("failed", <reason>). Never-raise.

FR-2 — Врезка в _handle_merge_verify (ребро deploy → done)

Внутри существующего _handle_merge_verify, ПОСЛЕ merge_verify_applies(repo)-гейта и резолва validated_revision, но ПЕРЕД merge_pr:

  • если merge_verify_autocreate_pr_enabled → вызвать ensure_open_pr(repo, branch);
  • status == "created"|"existed" → продолжить штатно к merge_prverify_merged_to_main;
  • status == "failed"честный HOLD + alert (как сегодняшний not-merged путь: note_not_merged_alert + set_issue_blocked + Plane-коммент + Telegram; задача остаётся на deploy, НЕ done, БЕЗ отката на development) с сообщением, отражающим «PR создать не удалось» (а не «PR не влит»).
  • kill-switch off → текущее поведение 1:1 (никакого создания PR).

FR-3 — Защита ORCH-073 цела (регресс-инвариант)

Создание PR не подменяет проверку слияния. После ensure_open_pr + merge_pr верификация остаётся только verify_merged_to_main (SHA-в-main, ORCH-073 FR-1) + регресс-гард (check_main_regression). Если код реально не оказался в main — HOLD сохраняется. Создание PR лишь устраняет ложный HOLD «no open PR», который конвейер обязан был предотвратить.

FR-4 — Наблюдаемость (G3)

В лог писать однозначный исход на каждом из мест работы с PR:

  • merge-verify ensure_open_pr -> created PR #N /
  • … -> existed PR #N /
  • … -> failed: <reason>. Сообщение HOLD при failed обязано отличаться текстом от HOLD «not merged» (оператор должен видеть, что причина — невозможность создать PR, а не невозможность слить уже созданный). Желательно — пометка исхода в 14-deploy-log.md (best-effort, frontmatter deploy_status: нетронут).

FR-5 — Идемпотентность повторного прохода

Повторный заход в merge-verify (reaper / reconciler / повторный approve) при уже существующем PR → ensure_open_pr возвращает ("existed", …), merge_pralready-merged/штатно — без дублей PR и без побочных эффектов (INV-5/AC-9 ORCH-073 сохранены).

3. Изменения API (HTTP / внутренние)

  • Внешний HTTP API сервиса — без изменений (новых endpoint нет).
  • Исходящие вызовы Gitea: новый POST /api/v1/repos/{owner}/{repo}/pulls из контекста merge-verify (тот же вызов, что уже делает _ensure_pr); чтение — существующий GET …/pulls?state=open.
  • Внутренний контракт merge_gate: новая публичная функция ensure_open_pr (leaf, never-raise), вызывается из stage_engine._handle_merge_verify (и опционально из launcher._ensure_pr).

4. Изменения схемы БД

Нет. Состояние идемпотентности выводится из самого Gitea (наличие открытого PR), миграции не требуются. (Согласуется с restart-safe-моделью merge-verify.)

5. Требования к новым QG checks

Новых зарегистрированных QG-checks нет. Это под-гейт-врезка в advance_stage (_handle_merge_verify), как и сам ORCH-071 merge-verify — не отдельный QG_CHECKS-элемент. Реестр QG_CHECKS не трогается.

6. Конфигурация / kill-switch

  • merge_verify_autocreate_pr_enabled: bool = True (env ORCH_MERGE_VERIFY_AUTOCREATE_PR_ENABLED). False → ровно прежнее поведение (нет авто-создания PR; «no open PR» → HOLD как раньше).
  • Область действия — merge_gate.merge_verify_applies(repo): реально только для self-hosting / merge_verify_repos; прочие репо — no-op.

7. Артефакты pipeline (создать/обновить)

  • docs/work-items/ORCH-082/06-adr/ADR-001-*.md — архитектор (root cause G1 + дизайн ensure-PR).
  • 12-review.md, 13-test-report.md, 14/15/16-* — последующие стадии.
  • Обновить docs/architecture/README.md (блок ORCH-071/073) и CHANGELOG.md — в ТОМ ЖЕ PR (правило агентов №2/№6).

8. Инварианты (не нарушать)

  • STAGE_TRANSITIONS, QG_CHECKS, схема БД, check_deploy_status/_parse_deploy_status, exit-коды хука, terminal-sync, merge-gate (ORCH-043), image-freshness (ORCH-058) — без изменений.
  • Контракт never-raise на всём пути merge-verify (INV-1 ORCH-073).
  • Слияние только через PR (POST /pulls/{index}/merge); main никогда не push/force-push.
  • Защита ORCH-073 (SHA-в-main + регресс-гард) приоритетна: при конфликте «создать PR» проигрывает «не дать ложно-зелёный done».