11 KiB
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==0→True(код в 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):
- Подтвердить FR-1 (deployed SHA — предок
origin/main). - (опц., по дизайну) Проверить, что в
origin/mainприсутствует набор маркеров ключевых функций недавно-merged задач (regression marker set) — merge не уменьшил его. - При откате соседнего кода / отсутствии маркера → 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.pyendpoints) НЕ менять. - Внутренние сигнатуры:
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.py—tuple[bool, str]/bool, never-raise.
GET /queuemerge_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 ложно CONFIRMED → done.
Корень устранён FR-1+FR-2+FR-3. Восстановление кода (G1) уже выполнено restore-PR #76 —
подтвердить маркеры в origin/main (AC-1).