Files

15 KiB
Raw Permalink Blame History

work_item, stage, author_agent, status, created_at, model_used
work_item stage author_agent status created_at model_used
ORCH-094 analysis analyst ready-for-review 2026-06-09 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 (заполняет архитектор).