16 KiB
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содержит UUIDcancelled; имени «STOP» в маппинге сейчас нет. - Остановка процесса агента уже реализована как graceful-каскад в
src/agents/launcher.py::_watchdog(SIGTERM → graceagent_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_TRANSITIONSexit-гейтов и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(заполняет архитектор).