156 lines
15 KiB
Markdown
156 lines
15 KiB
Markdown
---
|
||
work_item: ORCH-094
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-09
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# 01 — BRD (бизнес-требования): ORCH-094 — терминальная (done) задача флаппит deploy-статусы в Plane (Awaiting↔Monitoring), не держит Done
|
||
|
||
Work Item: **ORCH-094** · Repo: **orchestrator** · Стадия: analysis
|
||
|
||
## 1. Бизнес-контекст и проблема
|
||
|
||
**Тип:** BUG — рассинхрон БД↔Plane / «зомби»-цикл post-deploy-статуса (self-hosting).
|
||
|
||
**Симптом (верифицирован живьём 09.06 на ORCH-061):**
|
||
Задача ORCH-061 в БД оркестратора = `done` с 07.06 (task 47; фикс задеплоен в прод; конвейер её
|
||
не трогает — 0 активных job'ов). При этом карточка задачи в **Plane не держит Done**: непрерывно
|
||
флаппит `Monitoring after Deploy ⟷ Awaiting Deploy` парами (туда-обратно за ~2 сек), каждые
|
||
несколько минут. Накоплено 273 активности. Доходило до абсурда: 09.06 14:56 встала в `Done` →
|
||
15:48 её выдернуло обратно `Done → Awaiting Deploy`. Воспроизводится детерминированно: ручной
|
||
sync 061→Done (PATCH 200, 16:47) → через ~60 сек снова `Done → Awaiting Deploy → Monitoring`
|
||
(16:48). Само **не затихает**.
|
||
|
||
**Установленные факты (по логам/БД прода + чтение кода ветки):**
|
||
- **Сам оркестратор не инициирует переходы из своих штатных стадийных обработчиков для done-задачи.**
|
||
В момент флаппа лог орка показывает только **входящие** webhook-и Plane
|
||
(`issue … updated to state … (Awaiting Deploy) → no pipeline action`, затем `(Monitoring) →
|
||
no pipeline action`). Обработчик `webhooks/plane.py::handle_issue_updated` для статусов
|
||
Awaiting/Monitoring логирует «no pipeline action» и **сам статус не переотправляет** (echo-loop
|
||
обработчика исключён).
|
||
- **Actor всех 273 переходов** = `daf4d3f4-55df-4016-9095-0cf9ddd8fd28` — бот-актор оркестратора
|
||
(тот же токен, под которым орк делает гигиену доски / sync). То есть PATCH-и шлёт **что-то под
|
||
токеном орка**, не привязанное к активной task/job в БД.
|
||
- В БД орка **нет активного post-deploy-monitor** для task 47 (pdm активен только у текущей
|
||
063/task 74). `orchestrator-staging` (8501) — не источник (task 061 в его БД отсутствует).
|
||
- В коде ветки **единственные три писателя** deploy-статусов — `src/stage_engine.py`:
|
||
`set_issue_monitoring` (строка 404, на переходе `deploy → done` для self-hosting),
|
||
`set_issue_awaiting_deploy` (строка 1218, Phase A), `set_issue_deploying` (строка 1316, Phase B).
|
||
Все три — **внутри стадийных обработчиков** (`advance_stage` / `_handle_self_deploy_phase_*`),
|
||
ни один не сидит в фоновом цикле, независимом от таблицы `jobs`.
|
||
- `notifications.py::_live_plane_branch_override` **только читает** живой Plane-статус (для рендера
|
||
карточки) — писателем не является.
|
||
- Реконсилятор: F-1 пропускает задачи со `stage in ('done','cancelled')` (terminal-skip ORCH-086);
|
||
F-2 опрашивает issue **только** в статусах `[to_analyse, approved, rejected]` — статусы
|
||
`Monitoring`/`Awaiting` он не перебирает. **Механизма «привести done-задачу, застрявшую на
|
||
deploy-статусе, обратно к Done» (идемпотентного схождения) — нет.**
|
||
|
||
**Боль:** карточка вводит наблюдателя в заблуждение («задача деплоится», хотя она в проде и done),
|
||
шумит активностью (273 события на одной задаче), **вечно жжёт API-вызовы Plane** флаппом и
|
||
маскирует реальное состояние доски. Конвейер технически не нарушен (задача в проде), поэтому
|
||
приоритет **MEDIUM**, но дефект бессрочный и самовоспроизводящийся.
|
||
|
||
**Родственные задачи:** ORCH-091 (врущие/застывшие статусы карточки), ORCH-068/086 (терминал-скип
|
||
как защита инвариантов). ORCH-094 распространяет идею терминал-скипа на deploy-статусы и закрывает
|
||
источник флаппа.
|
||
|
||
## 2. Объём (scope)
|
||
|
||
### В объёме
|
||
- **G1 — устранить источник** PATCH-ей deploy-статуса на задачу, у которой в БД `stage=done` и нет
|
||
активного job'а. Терминальная (done) задача в Plane должна стабильно держать `Done` и не получать
|
||
`Awaiting`/`Monitoring`.
|
||
- **G2 — идемпотентность sync/setter'ов:** если БД=`done`, любой sync/монитор/реконсилятор/прямой
|
||
вызов приводит Plane к `Done` (не к промежуточному deploy-статусу) — терминал-скип/схождение,
|
||
распространённые на статусы `Monitoring`/`Awaiting` (как ORCH-068/086 для других статусов).
|
||
- **G3 — детерминированный конец post-deploy-monitor:** монитор завершается чётко (HEALTHY / N тиков
|
||
→ Done) и не оставляет «зомби»-таймеров, переживающих завершение задачи/рестарт; тики монитора
|
||
привязаны к активному job'у в БД (нет job → нет тиков, нет статус-PATCH).
|
||
- **G4 — наблюдаемость:** лог однозначно показывает, **кто и почему** ставит deploy-статус
|
||
(caller/функция + причина), для будущей диагностики таких флаппов.
|
||
- Инструментальная локализация фактического актора флаппа на проде (воспроизведение на 061) и его
|
||
документирование (что это было) — в рамках выполнения задачи (developer/architect).
|
||
|
||
### Вне объёма
|
||
- Изменение конвейера стадий (`STAGE_TRANSITIONS`), состава `QG_CHECKS`, семантики machine-verdict
|
||
ключей (`deploy_status:`/`staging_status:`/…) — **не трогать**.
|
||
- Изменение рабочего deploy-цикла для **реально деплоящейся** задачи (Phase A→B→C, post-deploy
|
||
HEALTHY-окно) — поведение должно сохраниться 1:1 (регресс, AC-4).
|
||
- Поведение для не-self-hosting репозиториев (enduro-trails) — нулевая регрессия.
|
||
- Архитектурное решение «где именно поставить гард» (на уровне setter'а в `plane_sync` vs на уровне
|
||
вызывающего в `stage_engine` vs реконсилятор) — определяет **архитектор** в `06-adr/`.
|
||
|
||
## 3. Заинтересованные стороны
|
||
|
||
- **Заказчик/репортёр:** Слава (владелец) — обнаружил на ORCH-061 09.06.
|
||
- **Затрагивает:** всех наблюдателей доски Plane проекта ORCH (ложная индикация); лимиты Plane API
|
||
(вечный флапп жжёт вызовы под общим бот-токеном).
|
||
- **Принимает результат:** Owner / CI на финальной стадии конвейера.
|
||
- **Особый риск:** self-hosting — правка идёт в инструмент, обслуживающий прод всех проектов из
|
||
общего инстанса; рабочий deploy-цикл нельзя сломать.
|
||
|
||
## 4. Бизнес-требования (BR)
|
||
|
||
- **BR-1** — Терминальная задача (БД `stage=done`, 0 активных job'ов), выставленная в Plane=`Done`,
|
||
**остаётся `Done`** и не получает авто-переходов в `Awaiting Deploy`/`Monitoring after Deploy`.
|
||
- **BR-2** — Любой источник синхронизации (реконсилятор, монитор, прямой вызов setter'а deploy-статуса)
|
||
для задачи с БД=`done` приводит Plane к **`Done` идемпотентно**, а не к промежуточному deploy-статусу;
|
||
повторные срабатывания не качают маятник.
|
||
- **BR-3** — Post-deploy-monitor имеет **детерминированный конец** (HEALTHY / исчерпание N тиков → Done,
|
||
или DEGRADED → Blocked+freeze) и после завершения **не производит ни одного** последующего
|
||
статус-PATCH для этой задачи; не оставляет таймера/состояния, переживающего завершение или рестарт.
|
||
- **BR-4** — Тики post-deploy-monitor **привязаны к активному job'у** в таблице `jobs`: нет активного
|
||
job'а для задачи → нет тиков → нет статус-PATCH. «Зомби»-монитор (тики без соответствующего активного
|
||
job'а) исключён.
|
||
- **BR-5** — Для **реально деплоящейся** задачи (063-подобной) deploy-окно
|
||
`Awaiting → Deploying → Monitoring → Done` работает в точности как раньше (нет регресса).
|
||
- **BR-6** — Каждый вызов, выставляющий deploy-статус, оставляет в логе однозначную запись **кто
|
||
(функция/путь) и почему** ставит статус (наблюдаемость для будущей диагностики флаппов).
|
||
- **BR-7** — Фактический источник флаппа на проде локализован и **задокументирован** (что это было)
|
||
в `06-adr/` и/или `CHANGELOG.md`.
|
||
|
||
## 5. Нефункциональные требования (NFR)
|
||
|
||
- **NFR-1 — never-raise:** вся новая логика (гарды/терминал-скип/идемпотентность) не бросает
|
||
исключений в горячих путях; сетевая ошибка Plane при сверке статуса → безопасная деградация
|
||
(не флаппить и не падать), а не блокировка конвейера всех проектов.
|
||
- **NFR-2 — self-hosting безопасность:** не перезапускать/не ронять прод-контейнер; не трогать
|
||
`main`/force-push/прод-деплой; правка не меняет рабочий критический путь self-deploy.
|
||
- **NFR-3 — обратимость:** поведение под kill-switch (или иным обратимым флагом) — при выключении
|
||
возврат к прежнему поведению; нулевая регрессия для не-self репозиториев.
|
||
- **NFR-4 — restart-safe:** состояние монитора/гардов корректно после рестарта контейнера (нет
|
||
«воскрешения» тиков для уже завершённой задачи).
|
||
- **NFR-5 — `pytest tests/ -q` зелёный**; `STAGE_TRANSITIONS` / `QG_CHECKS` / machine-verdict ключи /
|
||
схема БД (если без миграции) — без изменений или строго аддитивно.
|
||
|
||
## 6. Допущения и ограничения
|
||
|
||
- Допущение: статусы `Monitoring after Deploy` / `Awaiting Deploy` существуют в Plane-проекте ORCH
|
||
как реальные статусы (иначе alias-fallback маппит их на базовые UUID — это часть диагностики
|
||
терминал-детекта).
|
||
- Допущение: бот-токен орка (`daf4d3f4-…`) — единственный актор переходов; внешняя Plane-automation
|
||
под другим токеном считается отдельной гипотезой и проверяется при локализации (H-внешнее).
|
||
- Ограничение: установленные факты выше **не изобретать** — они верифицированы на проде; точный
|
||
актор флаппа требует инструментального воспроизведения (фикс — после локализации).
|
||
- Ограничение: правка строго в зоне self-hosting deploy/post-deploy/sync; конвейер и гейты неизменны.
|
||
|
||
## 7. Критерии успеха
|
||
|
||
Терминальная задача стабильно держит `Done` ≥10 мин без авто-переходов (AC-1); любой sync для done
|
||
идемпотентно сходится к `Done` (AC-2); post-deploy-monitor завершается детерминированно и не
|
||
оставляет тиков/таймеров (AC-3); рабочий deploy-цикл 063-подобной задачи не регрессирует (AC-4);
|
||
never-raise + зелёный pytest + источник флаппа задокументирован (AC-5). Детальные PASS/FAIL — в
|
||
`03-acceptance-criteria.md`.
|
||
|
||
## 8. Риски
|
||
|
||
- Гард терминал-скипа поставлен слишком широко → подавит легитимный `Monitoring` у реально
|
||
деплоящейся задачи (регресс AC-4). Митигировать тонкой привязкой к БД `stage=done` + активность job.
|
||
- Фактический актор флаппа окажется внешней Plane-automation (вне кода орка) → код-фикс не закроет
|
||
G1 полностью; нужно зафиксировать в ADR и, при необходимости, защититься идемпотентным схождением
|
||
к Done (BR-2) как буфером.
|
||
- Детали — `10-tech-risks.md` (заполняет архитектор).
|