6.9 KiB
adr-0014: SHA-в-main — единственный критерий merge-verify + регресс-гард целостности main
- Статус: accepted
- Дата: 2026-06-08
- Задача: ORCH-073 (BUG CRITICAL — эрозия
main) - Amends: adr-0013 (ORCH-071) — меняет КРИТЕРИЙ подтверждения merge.
- Детальный ADR:
docs/work-items/ORCH-073/06-adr/ADR-001-merge-verify-sha-truth-and-regression-guard.md - Постмортем:
docs/history/LESSONS_2026-06-08_phantom-merge.md
Контекст
adr-0013 (ORCH-071) ввёл под-гейт merge-verify на ребре deploy → done, но допускал
подтверждение merge по ИЛИ-критерию: verify_merged_to_main возвращал True, если
pr_already_merged(repo, branch) ЛИБО SHA — предок origin/main. pr_already_merged
засчитывал любой merged PR ветки, включая авто docs-PR (staging/deploy-логи). У одной
feature-ветки в main сливались только docs-PR, а code-PR — нет → pr_already_merged=True →
verify CONFIRMED → done, хотя кода в main не было. Накопительно потеряны ORCH-067 (ссылки
plane_issue_link) и ORCH-069 (qg0_title_max). Вторичный усилитель — CHANGELOG-ребейзы,
откатывающие ветку и тащащие устаревший код-сосед. Восстановление кода (G1) выполнено вручную
restore-PR #76; этот ADR устраняет корень навсегда.
Решение
- SHA-в-main — единственный критерий (FR-1).
verify_merged_to_main(repo, branch, sha)подтверждает merge ТОЛЬКО прямым фактомgit merge-base --is-ancestor <sha> origin/main(послеgit fetch origin main). OR-веткаpr_already_mergedудалена из верификатора. Пустойsha/ любая git-ошибка →False(fail-closed: alert + HOLD). never-raise (INV-1). pr_already_merged→ idempotency-guard, различающий code-PR/docs-PR (FR-2). Засчитывает merged PR только приhead.ref==<feature-branch>Иbase.ref=="main"(явный фильтр в цикле, не ненадёжный query-параметрhead). Используется лишь как защитаmerge_prот второго merge, НЕ как подтверждениеdone.merge_prсливает именно code-ветку (FR-3). Выбор открытого PR поhead.ref==branchИbase.ref=="main"; merge только GiteaPOST /pulls/{index}/merge, никогда push/force-push вmain. Источник истины «слилось» — FR-1.- Регресс-гард целостности
main(FR-5). Новаяmerge_gate.check_main_regression, вызываемая в_handle_merge_verifyПОСЛЕ подтверждённого SHA-в-main и ДОdone: проверяет, чтоorigin/mainсодержит декларативный набор маркеров ключевых функций ранее-merged задач (git grep -c <marker> origin/main -- <path>> 0). Маркер отсутствует → alert «main regressed» + HOLD (НЕdone, БЕЗ авто-отката наdevelopment— инфра-дефект, ALERT-only как ORCH-021/071). Набор — append-only константаMAIN_REGRESSION_MARKERSвmerge_gate.py(расширяется каждой значимой задачей). Fail-open на git-ошибке самого грепа (регресс утверждается только при детерминированномcount==0); первичный фейл-клозед — SHA-в-main. Kill-switchregression_guard_enabled(дефолтtrue); non-self → no-op. .gitattributes CHANGELOG.md merge=union(FR-4). В корне репо; авто-слияние правок## [Unreleased]без конфликта →auto_rebase_onto_mainне откатывает ветку и не тащит устаревший код-сосед.docs/**/*.mdпод union НЕ ставится (union только для append-only; доки переписываются построчно).
Инварианты
never-raise на verify/merge/регресс-гарде (ошибка → alert/HOLD, не падение); прод 8500 не
рестартится/не падает в рамках merge; merge только Gitea PR-API без force-push в main; ручной
Confirm Deploy (ORCH-059) сохранён; идемпотентность по «SHA-в-main», а не по «любому merged PR»;
non-self репо (enduro) — merge/verify/регресс-гард без изменений. STAGE_TRANSITIONS, реестр
QG_CHECKS, check_deploy_status, схема БД, внешние HTTP-эндпоинты — без изменений.
Альтернативы
- Сохранить PR-флаг как со-критерий verify (с фильтром head/base) — отклонено: PR можно слить и тут же откатить ребейзом-соседом; надёжен только факт «SHA в main».
docs/**/*.md merge=union— отклонено: тихая дубликация строк в переписываемых доках.- Регресс-гард с авто-откатом / хранением маркеров в БД/Plane — отклонено (Не-цель «не менять схему БД/Plane»; реакция ALERT-only).
- Fail-closed на marker-grep — отклонено: ложный HOLD при git-сбое; marker-grep вторичен.
Последствия
Невозможно «done + прод задеплоен, а code-PR не в main». Ложно-зелёный по docs-PR устранён в
корне. CHANGELOG-конфликты больше не откатывают ветку. Регресс соседнего кода ловится отдельным
гардом. Минус: при недоступной Gitea/git verify консервативно False → возможен ложный HOLD+alert
(снимается повтором; fail-closed для done приоритетен). Набор маркеров требует дисциплины —
значимая задача дописывает свой маркер.
Связи
- Amends adr-0013 (ORCH-071), наследует adr-0006 (merge-gate), adr-0011 (job-reaper/lease).
- Детально:
docs/work-items/ORCH-073/06-adr/ADR-001-merge-verify-sha-truth-and-regression-guard.md.