6.7 KiB
Runbook — диагностика «фантомного merge» (ORCH-071)
Когда применять. Задача дошла до
done(или прод задеплоен «зелёным»), но есть подозрение, что её ветка не влита вmain— следующая задача срежет ветку от устаревшегоmainи потеряет код предшественника (постмортемdocs/history/LESSONS_2026-06-08_phantom-merge.md). Этот runbook даёт 4 проверки для однозначной локализации фантома.
С ORCH-071 такой исход блокируется автоматически: под-гейт deploy → done
(stage_engine._handle_merge_verify) сначала детерминированно вливает PR
(merge_gate.merge_pr, Gitea PR-merge API), затем верифицирует merge
(merge_gate.verify_merged_to_main) и НЕ пускает задачу в done, пока merge не
подтверждён (alert + HOLD). Этот runbook — для ручной перепроверки/инцидентов
(в т.ч. при выключенном kill-switch ORCH_MERGE_VERIFY_ENABLED=false).
Подставьте значения:
OWNER=admin # settings.gitea_owner
REPO=orchestrator # репозиторий
BRANCH=feature/ORCH-071-slug # ветка задачи
GITEA=http://localhost:3000 # settings.gitea_url
TOKEN=<gitea_token> # settings.gitea_token
FILE=src/stage_engine.py # любой файл, гарантированно изменённый задачей
Проверка 1 — Gitea API: список PR + флаги merged
Показывает, считает ли сам Gitea PR влитым.
curl -s -H "Authorization: token $TOKEN" \
"$GITEA/api/v1/repos/$OWNER/$REPO/pulls?state=all" \
| python3 -c 'import sys,json; \
[print(p["number"], p["state"], "merged="+str(p.get("merged")), p["head"]["ref"]) \
for p in json.load(sys.stdin)]'
- Фантом НЕ подтверждён (всё хорошо): строка ветки
$BRANCHимеетmerged=True. - Фантом подтверждён (по этому критерию): PR ветки
state=open/merged=False(или PR отсутствует), при том что задача вdone/ прод задеплоен.
Проверка 2 — md5 прод-файлов vs git show origin/main:<file>
Сверяет содержимое файла на проде с тем, что лежит в origin/main.
# в прод-контейнере (или через docker exec orchestrator):
md5sum "/app/$FILE"
# содержимое того же файла из origin/main (на хосте, в клоне репо):
git -C /home/slin/repos/$REPO fetch origin main -q
git -C /home/slin/repos/$REPO show "origin/main:$FILE" | md5sum
- Совпало: прод соответствует
main(фантома нет ИЛИ задача не меняла этот файл — возьмите файл из проверки 3/diff'а ветки). - Разошлось: прод собран из ветки, а
mainего не получил → косвенный признак фантома.
Проверка 3 — git merge-base ветки vs main
Главный детерминированный критерий: является ли HEAD ветки предком origin/main.
git -C /home/slin/repos/$REPO fetch origin -q
SHA=$(git -C /home/slin/repos/$REPO rev-parse "origin/$BRANCH")
git -C /home/slin/repos/$REPO merge-base --is-ancestor "$SHA" origin/main \
&& echo "MERGED: ветка влита в main" \
|| echo "NOT MERGED: ветка НЕ предок origin/main (ФАНТОМ)"
Это ровно та проверка, что выполняет merge_gate.verify_merged_to_main (rc=0 → влито).
MERGED: фантома нет.NOT MERGED: фантом подтверждён —mainне содержит коммитов задачи.
Проверка 4 — таймлайн деплой-логов
Восстанавливает порядок событий: был ли merge до/после деплоя, и был ли он вообще.
# Вердикт деплоя + новое поле merge-верификации (ORCH-071):
git -C /home/slin/repos/$REPO show "origin/$BRANCH:docs/work-items/<WI>/14-deploy-log.md" \
| sed -n '1,12p' # frontmatter: deploy_status:, merged_to_main:
# Наблюдаемость под-гейта в живом сервисе:
curl -s "$GITEA_HEALTH/queue" | python3 -c \
'import sys,json; print(json.load(sys.stdin)["merge_verify"])'
# -> {"enabled":..., "merge_verified_total":..., "not_merged_alerts_total":..., "last_alert_wi":...}
# Журнал хоста по деплою (sentinel-каталог задачи):
ls -la /home/slin/repos/.deploy-state-$REPO/<WI>/
cat /home/slin/repos/.deploy-state-$REPO/<WI>/hook.log
deploy_status: SUCCESS+merged_to_main: false→ деплой прошёл, merge — нет (это и есть класс ORCH-071; задача должна быть удержана наdeploy, неdone).not_merged_alerts_totalрастёт /last_alert_wi == <WI>→ под-гейт уже поднял alert.
Критерий «фантом подтверждён»
Фантомный merge считается подтверждённым, если выполняется ХОТЯ БЫ ОДНО из:
- Проверка 1: PR ветки
state=open/merged=False(или PR нет), а задача вdone. - Проверка 3:
merge-base --is-ancestorвернул NOT MERGED (HEAD ветки не предокorigin/main). - Проверка 4:
14-deploy-log.mdимеетdeploy_status: SUCCESSприmerged_to_main: false.
Проверка 2 — вспомогательная (зависит от того, менял ли файл задачей), используется для подтверждения проверок 1/3.
Что делать при подтверждённом фантоме
- Влить PR вручную через Gitea (PR-merge API / UI) — НИКОГДА не
git push/--forceвmain(INV-4). - Повторить approve задачи (re-drive) — под-гейт переоценит: merge подтвердится → задача уйдёт в
done. - Если фантом случился при выключенном kill-switch — включить
ORCH_MERGE_VERIFY_ENABLED=true.