Files
orchestrator/docs/work-items/ORCH-090/01-brd.md
claude-bot 610619edc2
All checks were successful
CI / test (push) Successful in 29s
analyst(ET): auto-commit from analyst run_id=496
2026-06-09 20:06:31 +03:00

16 KiB
Raw Blame History

work_item, stage, author_agent, status, created_at, model_used
work_item stage author_agent status created_at model_used
ORCH-090 analysis analyst ready-for-review 2026-06-09 claude-opus-4-8

01 — BRD (бизнес-требования): ORCH-090 — Механизм отмены задачи: статус STOP в Plane (остановка + полный сброс)

Work Item: ORCH-090 · Repo: orchestrator · Стадия: analysis

1. Бизнес-контекст и проблема

Сегодня в оркестраторе нет штатного способа отменить/остановить задачу. Оператор вынужден выполнять разрозненные ручные действия: убить процесс агента, дождаться исчерпания ретраев job, удалить ветку/worktree/строку task из БД и вручную сбросить статус в Plane. Это медленно, ошибкоопасно и не воспроизводимо (инцидент 09.06 с ORCH-087 — оператор делал всё это руками).

Вторая, связанная проблема — дыра ручного релонча: src/webhooks/plane.py::handle_status_start при ручном переводе задачи в рабочий статус (через «To Analyse» / In Progress) повторно ставит в очередь агента текущей стадии на той же ветке (has_active_job_for_task → иначе enqueue_job(stage_agent, …)). Это означает, что попытка оператора «подтолкнуть» задачу сменой статуса может незаметно релончить агента — именно этот механизм усугубил сегодняшний инцидент.

Требуется единый, декларативный механизм: перевод задачи в новый Plane-статус STOP → оркестратор немедленно останавливает всю работу по задаче и полностью сбрасывает её прогресс. Повторный запуск возможен ТОЛЬКО через «To Analyse» (с нуля). Никакой другой статус пайплайн не запускает.

Установленные факты (по текущему коду, не изобретать):

  • Машина стадий — src/stages.py::STAGE_TRANSITIONS; терминальная стадия только done (cancelled-стадии нет).
  • Plane-маппинг — src/plane_sync.py: _PLANE_NAME_TO_KEY уже содержит "Cancelled" → "cancelled", _DEFAULT_STATES содержит UUID cancelled; имени «STOP» в маппинге сейчас нет.
  • Остановка процесса агента уже реализована как graceful-каскад в src/agents/launcher.py::_watchdog (SIGTERM → grace agent_kill_grace_seconds → SIGKILL); PID задачи хранится в jobs.pid.
  • Статусы job в jobsqueued | running | done | failed; статуса cancelled нет.
  • Терминал-скип для реконсилятора/мониторов уже учитывает done и cancelled (src/reconciler.py::_is_terminal_state, ORCH-068/086).
  • Запуск пайплайна с нуля — handle_status_start → start_pipeline (создаёт ветку + docs + analyst).

2. Объём (scope)

В объёме

  • Новый Plane-статус STOP как сигнал отмены задачи (распознавание в диспетчере статусов).
  • Остановка задачи (G1): graceful-стоп активного агента (SIGTERM), отмена всех job'ов задачи (queued/running → терминальный «cancelled»-исход), исчерпание ретраев (запрет авто-requeue), снятие таймеров/мониторов (post-deploy monitor, brd-review clock и т.п.).
  • Полный сброс прогресса (G2): удаление/архив рабочей ветки и worktree, очистка незавершённого прогресса задачи в БД так, чтобы повторный старт шёл строго через start_pipeline (с нуля). Docs-артефакты задачи — сохранить/забэкапить (не теряем аналитику).
  • Закрытие дыры релонча (G3/G4): перевод в любой промежуточный рабочий статус (Development/Architecture/Review/Deploying/…) вручную не запускает агента; единственный вход к запуску пайплайна — «To Analyse» (старт с нуля).
  • Идемпотентность и fail-safe (G5): STOP на уже остановленной/завершённой задаче — no-op; STOP во время критичной операции (merge/deploy) — корректное прерывание без порчи main/прода.
  • Kill-switch фичи; наблюдаемость (лог + Telegram + блок в GET /queue).
  • Обновление документации (CLAUDE.md, architecture/README.md, CHANGELOG.md) и инфра-предусловие (создать статус STOP на доске Plane).

Вне объёма

  • Автоматическая отмена задач по таймауту/эвристике — STOP только по явному человеческому сигналу.
  • Возобновление задачи «с середины» после STOP — сознательно НЕ поддерживается (только перезапуск с нуля через To Analyse).
  • Изменение семантики Rejected (откат на стадию назад) — STOP это отдельный путь, не Rejected.
  • Изменение состава/семантики STAGE_TRANSITIONS exit-гейтов и QG_CHECKS / check_*.
  • Откат уже задеплоенного в прод кода (rollback) — STOP не выполняет rollback; он лишь прерывает незавершённую работу безопасно.
  • Кросс-проектная отмена пакета задач (отменяется одна задача за сигнал).

3. Заинтересованные стороны

  • Заказчик / владелец продукта: Слава (идея STOP-статуса).
  • Оператор оркестратора (Стрим и др.) — главный потребитель: получает кнопку «отменить» вместо ручной хирургии по БД/процессам.
  • Затрагиваемые проекты: orchestrator (self-hosting) и enduro-trails (общая прод-БД/очередь) — изменения должны быть аддитивны и не задевать enduro при выключенном/неприменимом флаге.
  • Принимает результат: reviewer/tester по критериям приёмки (03/04).

4. Бизнес-требования (BR)

  • BR-1 (STOP останавливает работу) — перевод задачи в Plane-статус STOP → оркестратор останавливает всю работу по задаче: (a) активному агенту посылается SIGTERM (graceful, с последующим жёстким kill по существующему grace-каскаду); (b) все job'ы задачи (queued и running) переводятся в терминальный «отменённый» исход и не выбираются claim'ом; (c) ретраи исчерпываются (никакого авто-requeue после STOP); (d) таймеры/мониторы задачи (post-deploy monitor, brd-review clock, merge-lease defer и т.п.) снимаются. Контракт фичи — never-raise.
  • BR-2 (STOP = полный сброс) — после STOP задача НЕ продолжается с середины. Рабочая ветка+worktree удаляются/архивируются; незавершённый прогресс задачи в БД очищается или помечается так, что повторный запуск идёт через start_pipeline с нуля (свежая ветка от актуального origin/main, новый аналитик). Docs-артефакты (01..17) — сохранить/забэкапить.
  • BR-3 (единственный вход — To Analyse) — единственный Plane-статус, запускающий пайплайн — «To Analyse» (старт с нуля). После STOP повторный «To Analyse» создаёт задачу заново.
  • BR-4 (закрыть дыру релонча) — ручной перевод задачи в любой промежуточный рабочий статус (Architecture/Development/Review/Testing/Deploying/Awaiting Deploy/…) не запускает агента соответствующей стадии. Текущее поведение handle_status_start, релончащее агента текущей стадии на той же ветке, должно быть устранено/загейчено так, чтобы пайплайн стартовал только из «To Analyse».
  • BR-5 (идемпотентность) — STOP на задаче, которая уже остановлена (cancelled), уже done или не существует, — no-op (без ошибок, без побочных эффектов, без повторного kill).
  • BR-6 (безопасное прерывание критичных операций) — STOP во время merge/deploy не оставляет main в half-merged состоянии и не роняет/не рестартит прод-контейнер. Если критичный шаг уже необратимо запущен (детач-деплой/слияние в процессе), STOP не должен его «разорвать» с порчей — допустимо дождаться/пропустить необратимый шаг и зафиксировать честный итог (детали безопасной точки прерывания — архитектору).
  • BR-7 (STOP ≠ Rejected) — STOP это полная остановка+сброс задачи, а не откат на предыдущую стадию. Существующий путь Rejected (handle_verdict(approved=False)_rollback_stage) не меняется и не смешивается с STOP.
  • BR-8 (наблюдаемость) — каждое срабатывание STOP прозрачно: лог, Telegram-уведомление (с кликабельным номером задачи), Plane-коммент (best-effort), отражение в live-карточке и read-only блок в GET /queue.

5. Нефункциональные требования (NFR)

  • NFR-1 (нулевая регрессия + kill-switch) — фича под флагом включения (по образцу serial_gate_enabled/merge_gate_enabled); при выключенном флаге поведение оркестратора строго как сейчас. STAGE_TRANSITIONS / QG_CHECKS / check_* / семантика существующих статусов — без изменений.
  • NFR-2 (общая прод-БД, аддитивность) — любые изменения схемы БД — только аддитивные и идемпотентные (CREATE TABLE IF NOT EXISTS / _ensure_column); enduro-trails не затрагивается.
  • NFR-3 (self-hosting safety) — STOP не должен убить сам оркестратор / прод и не портить main. Прерывание merge/deploy — fail-safe (не оставлять half-merge; не рестартить прод).
  • NFR-4 (restart-safe) — состояние «задача отменена» durable (БД); после рестарта контейнера отменённая задача не «оживает» и не релончится reconciler'ом/reaper'ом (переиспользовать терминал-скип done/cancelled).
  • NFR-5 (never-raise) — обработчик STOP и закрытие дыры релонча не должны валить вебхук-поток; ошибка на единице работы логируется и не прерывает обработку других задач/проектов.
  • NFR-6 (offline-устойчивость горячего пути) — закрытие дыры релонча и терминал-скип не должны добавлять обязательных сетевых вызовов в горячий claim-цикл.

6. Допущения и ограничения

  • На доске Plane проекта ORCH будет создан статус STOP (инфра-предусловие); до его создания фича в режиме fail-safe (нет статуса → нет STOP-действия, ничего не ломается).
  • Логический ключ cancelled и его UUID/группа уже присутствуют в plane_sync — STOP может переиспользовать «cancelled»-семантику терминал-скипа (точное соответствие имя→ключ и группа-cancelled — решение архитектора).
  • Существующий graceful kill-каскад агента (_watchdog: SIGTERM→grace→SIGKILL) переиспользуется для остановки активного агента; новый механизм kill не изобретается.
  • Терминал-скип done/cancelled в reconciler/мониторах уже есть и должен покрыть STOP-отменённые задачи (NFR-4) — переиспользовать, не дублировать.
  • Архитектурные решения (хранилище статуса отмены, точка безопасного прерывания merge/deploy, удаление vs архив ветки, точные точки врезки в plane.py) — зона архитектора (06-adr/).

7. Критерии успеха

STOP-статус, выставленный на задаче, приводит к: остановленному агенту, отменённым job'ам без авто-requeue, снятым таймерам/мониторам, удалённой/заархивированной ветке+worktree, durable-статусу «отменена» (переживает рестарт), сохранённым docs-артефактам. Ручной перевод в промежуточный рабочий статус более не релончит агента; пайплайн стартует только из «To Analyse». STOP идемпотентен и безопасен при merge/deploy. Детальные PASS/FAIL — в 03-acceptance-criteria.md.

8. Риски

  • Гонка «STOP во время merge/deploy» → риск half-merge/порчи main (mitigation: безопасная точка прерывания, fail-safe — детали архитектору).
  • Закрытие дыры релонча может задеть легитимный сценарий resume после «Needs Input» → нужно сохранить намеренные сценарии возврата к работе, не ломая их (уточнить с архитектором, какой путь заменяет релонч).
  • Очистка прогресса в БД при общей прод-БД → риск задеть enduro/другие задачи (mitigation: строго per-task, аддитивно).
  • Детали — 10-tech-risks.md (заполняет архитектор).