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

11 KiB
Raw Blame History

02 — ТЗ: ORCH-073 — системный фикс эрозии main + восстановление кода 067/069

ТЗ описывает ТРЕБУЕМОЕ ПОВЕДЕНИЕ и точки изменения. Выбор конкретного дизайна (где именно резать docs-PR от code-PR, формат набора регресс-маркеров) — за архитектором (06-adr). Запрещено комментировать ТЗ задним числом: если требование не годится — вернуть в Анализ.

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

Модуль Роль в фиксе FR
src/merge_gate.py verify_merged_to_main, pr_already_merged, merge_pr, новый регресс-гард FR-1, FR-2, FR-3, FR-5
src/stage_engine.py _handle_merge_verify (под-гейт deploy → done) — точка вызова FR-1/FR-5 FR-1, FR-5
src/config.py (опц.) настройки регресс-гарда: kill-switch + набор маркеров/таймаут FR-5
.gitattributes (корень репо, новый) CHANGELOG.md merge=union (+ опц. docs/*.md merge=union) FR-4
docs/architecture/README.md раздел merge-verify — обновить под новую семантику AC-8
CHANGELOG.md запись Unreleased AC-8
docs/work-items/ORCH-073/06-adr/ ADR на новую семантику merge-verify + регресс-гард AC-8

2. Требуемые изменения по коду

FR-1 (G3, ядро) — verify_merged_to_main чинит семантику

Текущее (баг): src/merge_gate.py::verify_merged_to_main(repo, branch, sha) возвращает True, если pr_already_merged(...) ИЛИ git merge-base --is-ancestor <sha> origin/main. OR-ветка pr_already_merged засчитывает docs-PR → ложно-зелёный.

Требование: подтверждение merge — ТОЛЬКО прямой факт «deployed commit является предком origin/main»:

  • после git fetch origin main выполнить git merge-base --is-ancestor <deployed_sha> origin/main;
  • rc==0True (код в main), иначе → False.
  • pr_already_merged НЕ может быть единственным/достаточным условием True. Допустимо оставить PR-флаг только как вспомогательный сигнал (idempotency / диагностика), но он НЕ должен подтверждать merge при отсутствии SHA в main.
  • Пустой sha → неопределённо → False (fail-closed: alert + HOLD), как сейчас.
  • never-raise: любая git/HTTP-ошибка → False (INV-1).

FR-2 (G2) — pr_already_merged различает code-PR и docs-PR

Текущее (баг): src/merge_gate.py::pr_already_merged возвращает True за ЛЮБОЙ merged==True PR из GET /pulls?state=all&head=<branch> — включая авто docs-PR.

Требование (на выбор архитектора, предпочтителен вариант «б»):

  • (а) засчитывать merged только для PR, реально несущего код ветки: base.ref==main И head.ref==<feature-branch> (исключить docs/* ветки и docs-only PR); или
  • (б, предпочтительно) понизить роль pr_already_merged до idempotency-guard: единственный критерий «merged/done» — SHA-предок-main (FR-1); PR-флаги вспомогательны.
  • Поведение для non-self репо (enduro) не меняется (INV-5).
  • never-raise → False (консервативно).

FR-3 (G2) — merge_pr реально сливает code-ветку

Требование: src/merge_gate.py::merge_pr мержит ИМЕННО feature-PR с кодом (base==main, head==<feature-branch>), а не полагается на docs-PR. После merge — обязательная верификация по FR-1 (SHA в main) как единственный источник истины. Merge только через Gitea PR-merge API, никогда push/force-push в main (INV-2).

FR-5 (G3 регресс-гард, защита навсегда) — sanity-проверка целостности main

Требование: перед фиксацией done_handle_merge_verify, ПОСЛЕ зелёного check_deploy_status, до update_task_stage):

  1. Подтвердить FR-1 (deployed SHA — предок origin/main).
  2. (опц., по дизайну) Проверить, что в origin/main присутствует набор маркеров ключевых функций недавно-merged задач (regression marker set) — merge не уменьшил его.
  3. При откате соседнего кода / отсутствии маркера → alert «main regressed: code of missing» (Telegram + Plane), задача НЕ done (HOLD), как ветка not-merged в ORCH-071.
  • Реакция — ALERT-only + HOLD, без авто-отката на development (это инфра-дефект, не код-фолт).
  • never-raise (INV-1); kill-switch (как merge_verify_enabled); условность только для self-hosting / merge_verify_repos (INV-5).
  • Набор маркеров — конфигурируемый/декларативный (например, в src/config.py или рядом), чтобы следующие задачи могли его расширять. Точный формат — за архитектором.

FR-4 (G2/G4 корень) — .gitattributes с merge=union

Требование: в корне репо завести .gitattributes:

CHANGELOG.md merge=union
# опционально для append-only документов:
# docs/**/*.md merge=union   # ВНИМАНИЕ: union НЕ годится для файлов, где правки
                              # переписывают строки — применять только к append-only
  • merge=union встроен в git (драйвер по умолчанию), доп. конфиг хоста не требуется — но проверить, что атрибут реально применяется в worktree агентов (git check-attr merge CHANGELOG.md).
  • Эффект: при auto_rebase_onto_main правки ## [Unreleased] авто-сливаются (обе записи сохраняются) без конфликта → ветка не откатывается в development и не затирает соседний код.

3. Изменения API

  • Внешних HTTP API оркестратора (src/main.py endpoints) НЕ менять.
  • Внутренние сигнатуры:
    • verify_merged_to_main(repo, branch, sha) -> bool — семантика меняется, сигнатура сохраняется.
    • pr_already_merged(repo, branch) -> bool — семантика/назначение уточняется.
    • merge_pr(repo, branch) -> tuple[bool, str] — поведение уточняется (фильтр code-PR).
    • (опц.) новая функция регресс-гарда в merge_gate.pytuple[bool, str]/bool, never-raise.
  • GET /queue merge_verify_status() — допустимо дополнить счётчиком регресс-алертов (read-only, не источник истины).
  • Внешние вызовы Gitea — те же эндпоинты (/pulls, /pulls/{index}/merge).

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

  • НЕТ. Схема БД (src/db.py) не трогается (Не-цель). Регресс-гард опирается на git/origin/main, не на новые таблицы.

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

  • Новых зарегистрированных QG-checks не вводить. Логика остаётся под-гейтом в advance_stage (_handle_merge_verify), как ORCH-071 — не новый элемент реестра QG_CHECKS.
  • Реестр QG_CHECKS, check_deploy_status, _parse_deploy_status, merge-gate (check_branch_mergeable), image-freshness — без изменений.

6. Конфигурация (src/config.py / .env.example)

  • Существующие merge_verify_enabled (kill-switch, дефолт true), merge_verify_repos (пусто → только self-hosting), merge_pr_timeout_s, merge_verify_timeout_s — переиспользовать.
  • (опц., по дизайну) новые: kill-switch регресс-гарда и декларация набора маркеров. Дефолты — безопасные (для non-self — no-op). Любой новый ключ задокументировать в .env.example.

7. Артефакты pipeline, которые должны быть созданы/обновлены

  • docs/work-items/ORCH-073/06-adr/ADR-001-*.md — решение по новой семантике merge-verify (FR-1/FR-2/FR-3) + регресс-гард (FR-5) + .gitattributes (FR-4).
  • docs/architecture/README.md — обновить раздел «Merge-в-main + пост-деплой верификация» (ORCH-071) под FR-1 (SHA как единственный критерий) и добавить регресс-гард FR-5.
  • CHANGELOG.md — запись в ## [Unreleased].
  • docs/work-items/ORCH-073/10-tech-risks.md, 12-review.md, 13-test-report.md, 14-deploy-log.md, 15-staging-log.md — по ходу конвейера.
  • 04-test-plan.yaml (этот пакет) — реализовать тесты в tests/.

8. Аудит G4 (зафиксировать в ADR / 06-adr)

Зафиксировать подтверждённую причину docs-only merge: у feature-ветки 067/069 в main попадали только авто docs-PR (staging-log / deploy-log / CLAUDE.md / CHANGELOG), а code-PR не сливался, при этом pr_already_merged засчитывал docs-PR → merge-verify ложно CONFIRMEDdone. Корень устранён FR-1+FR-2+FR-3. Восстановление кода (G1) уже выполнено restore-PR #76 — подтвердить маркеры в origin/main (AC-1).