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

166 lines
16 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.
---
work_item: ORCH-090
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-09
model_used: 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 в `jobs``queued | 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` (заполняет архитектор).