Files
orchestrator/docs/work-items/ORCH-073/01-brd.md

99 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01 — BRD: ORCH-073 — CRIT: эрозия main (код ORCH-067/069 затёрт ребейзами, не доехал)
- **Work Item:** ORCH-073
- **Тип:** BUG CRITICAL — целостность `main`, накопительный регресс/эрозия
- **Репозиторий:** orchestrator (self-hosting)
- **Ветка:** `feature/ORCH-073-crit-main-orch-067-069`
- **Связь:** усиливает/чинит ORCH-071 (merge-verify); НЕ покрыт ORCH-071.
## 1. Бизнес-проблема
Код успешно «задеплоенных» и переведённых в `done` задач **ORCH-067** (tracker bump,
Plane-статусы, кликабельные ссылки `plane_issue_link`) и **ORCH-069** (`qg0_title_max`)
**физически отсутствовал в `origin/main`**, хотя обе прошли весь конвейер, Confirm Deploy,
merge-verify `CONFIRMED` и стали `done`. В `main` попадали только их **docs-коммиты**
(staging-log / verdict через отдельные авто docs-PR), но НЕ код feature-веток.
Внешнее проявление (нашёл Слава, 08.06): «ссылок на задачу в Plane нет», карточка Telegram
показывает сырой номер задачи вместо кликабельной ссылки — потому что код ссылок есть в ветке
ORCH-067, но не в `main`.
**Накопительный характер:** каждая новая задача срезает ветку от УСТАРЕВШЕГО `main` и при merge
тихо (без конфликт-маркеров) затирает код предшественника. Уже потеряны ORCH-067 и ORCH-069;
без системного фикса теряется код каждой следующей задачи с правкой `CHANGELOG.md`.
## 2. Подтверждённый root cause (git-аудит 08.06, не гипотеза)
1. **`verify_merged_to_main` подтверждает merge по ложному признаку.**
`src/merge_gate.py::verify_merged_to_main` возвращает `True`, если выполнено **ЛИБО**
`pr_already_merged(repo, branch)`, **ЛИБО** `git merge-base --is-ancestor <sha> origin/main`.
Первая ветка (`pr_already_merged`) и есть дыра.
2. **`pr_already_merged` засчитывает ЛЮБОЙ merged PR ветки.**
`src/merge_gate.py::pr_already_merged` делает `GET /pulls?state=all&head=<branch>` и
возвращает `True`, если **хоть один** PR `merged==True`. У одной ветки несколько PR
(code-PR + авто docs-PR со staging/deploy-логами). Сливается docs-PR → функция говорит
«already-merged» → `verify_merged_to_main`=`True` → merge-verify `CONFIRMED``done`,
хотя code-PR НЕ слит. **Ложно-зелёный.**
3. **CHANGELOG.md-ребейзы — вторичный усилитель.**
Merge-gate `auto_rebase_onto_main` при конфликте `CHANGELOG.md` откатывает `deploy-staging →
development`; повторный ребейз ветки от старого `main` несёт устаревшие версии файлов
(`notifications.py`/`config.py`/`webhooks/plane.py`), которые при merge тихо затирают
соседний код (фантом-эффект, как в ORCH-071, без конфликт-маркеров).
> Уточнение для архитектора: в ТЗ упомянута «инвертированная проверка `merge-base --is-ancestor
> origin/main HEAD` (merge_gate.py ~76)» — это `branch_is_behind_main` (детектор «ветка
> свежая»), он корректен для своей цели. Фактический дефект merge-verify — это OR-ветка
> `pr_already_merged` в `verify_merged_to_main` (строка ~649), которая засчитывает docs-PR.
## 3. Состояние на момент анализа (G1)
Аудит `origin/main` показал, что **восстановительный PR #76** (`restore(main): re-merge
ORCH-067 + ORCH-069 (ORCH-073)`) уже вернул код в `main`:
- `plane_issue_link` присутствует (`src/notifications.py`), `qg0_title_max` присутствует
(`src/config.py`, `src/webhooks/plane.py`), `verify_merged_to_main` присутствует.
Таким образом **G1 (восстановление кода) фактически выполнено** ручным restore-PR. Задача
ORCH-073 должна **подтвердить и зафиксировать** это в критериях приёмки (AC-1) и сосредоточиться
на **системном фиксе навсегда** (G2G5 / FR-1…FR-5), иначе регресс повторится.
## 4. Цели (Goals)
- **G1.** КОД ORCH-067 и ORCH-069 присутствует в `origin/main` одновременно с ORCH-071
(подтвердить restore-PR #76, зафиксировать маркеры > 0). Pytest зелёный. Прод задеплоен.
- **G2 (FR-2/FR-3).** `merge`/`pr_already_merged` различают **code-PR** и **docs-PR** — merge
засчитывается только за PR с кодом ветки (`base==main`, `head==<feature-branch>`).
- **G3 (FR-1, ядро).** `verify_merged_to_main` подтверждает merge **ТОЛЬКО** по факту «deployed
SHA — предок `origin/main`». PR-флаги вспомогательны, не достаточны.
- **G4 (FR-4).** Защита от CHANGELOG-затирания: `.gitattributes` с `CHANGELOG.md merge=union`
(+ опц. `docs/*.md merge=union` для append-only).
- **G5 (FR-5, регресс-гард навсегда).** После деплоя — sanity-проверка целостности `main`:
deployed SHA в `main` И набор маркеров ранее-merged задач не уменьшился. Откат соседнего кода
→ alert «main regressed», задача НЕ `done`.
## 5. Не-цели (Out of scope)
- Не менять Plane / схему БД.
- Не отменять self-hosting safety (не ронять прод, merge только через PR-API, без force-push в `main`).
- Не менять ручной гейт `Confirm Deploy`.
- Не менять поведение merge/verify для non-self репозиториев (enduro-trails) — обратная совместимость.
## 6. Инварианты
- **INV-1.** never-raise на верификации (alert, не падение).
- **INV-2.** self-hosting safety: прод не падает; merge только PR-API, без force-push в `main`.
- **INV-3.** ручной `Confirm Deploy` сохранён.
- **INV-4.** Идемпотентность: повторный прогон / reaper не делает второй merge; idempotency
опирается на «SHA-в-main», а не на «любой merged PR».
- **INV-5.** Обратная совместимость non-self (enduro): поведение merge/verify без изменений.
## 7. Заинтересованные стороны
- **Owner / Слава** — потребитель (видит кликабельные ссылки в карточке; доверие к merge-verify).
- **Все проекты на инстансе** (enduro-trails) — общий `main`/очередь/БД; регресс орка = групповой риск.
## 8. Срочность
КРИТИКАЛ. Без FR-1/FR-4/FR-5 каждая новая задача с правкой `CHANGELOG.md` продолжает терять код
предшественников (уже потеряны 067, 069). Ложно-зелёный merge-verify подрывает само ядро
автономности конвейера.