Files
orchestrator/docs/work-items/ORCH-090/02-trz.md

18 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

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

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

ТЗ описывает что и где должно измениться (модули/контракты/артефакты), выведенное из BRD и фактического кода. Как (хранилище статуса отмены, точка безопасного прерывания merge/deploy, удаление vs архив ветки, точные точки врезки) — решает архитектор в 06-adr/. ТЗ фиксирует требования и границы, не предлагает архитектурное решение.


1. Сводка изменения

Ввести обработку нового Plane-статуса STOP как сигнала отмены задачи. При его получении оркестратор: (1) останавливает активного агента (graceful SIGTERM через существующий каскад), (2) отменяет все job'ы задачи и исчерпывает ретраи, (3) снимает таймеры/мониторы, (4) удаляет/ архивирует рабочую ветку+worktree и сбрасывает незавершённый прогресс в БД до состояния «отменена» (durable), сохраняя docs-артефакты. Параллельно закрывается дыра релонча: ручной перевод в промежуточный рабочий статус больше не запускает агента — единственный вход к запуску пайплайна остаётся «To Analyse» (start_pipeline). Всё — аддитивно, под kill-switch, never-raise, restart-safe. STAGE_TRANSITIONS, QG_CHECKS, check_* и семантика существующих статусов — не меняются.


2. Задействованные модули / пути

Путь Действие
src/webhooks/plane.py изменить: добавить распознавание/маршрутизацию STOP (handle_issue_updated) → новый обработчик handle_stop (имя — на усмотрение архитектора); загейтить/убрать релонч агента в handle_status_start (промежуточные статусы не запускают агента; пайплайн — только из To Analyse/start_pipeline)
src/agents/launcher.py изменить: предоставить/переиспользовать остановку активного процесса задачи (SIGTERM каскад _watchdog; jobs.pid), пометку «не релончить» (исчерпание max_attempts/запрет авто-requeue для отменённой задачи)
src/queue_worker.py / src/db.py изменить: отмена job'ов задачи (queued/running → терминальный «cancelled»-исход); claim не выбирает отменённые; helper'ы выборки job'ов задачи; (возможно) новый терминальный статус job cancelled ИЛИ переиспользование failed+флаг — выбор архитектора; durable-пометка задачи «отменена» в tasks
src/git_worktree.py изменить/переиспользовать: удаление/архив рабочей ветки и worktree отменённой задачи (remove_worktree; удаление/архив Gitea-ветки) — never-raise
src/plane_sync.py изменить: маппинг Plane-статуса STOP (_PLANE_NAME_TO_KEY / _DEFAULT_STATES); переиспользовать группу cancelled для терминал-скипа; сеттер статуса (best-effort)
src/stages.py при необходимости — терминальная трактовка отменённой задачи (НЕ менять exit-гейты рёбер; добавление cancelled-стадии — решение архитектора, см. §5)
src/reconciler.py переиспользовать терминал-скип done/cancelled (_is_terminal_state) — отменённая задача не реконсилируется/не релончится
src/job_reaper.py согласовать: reaper не «оживляет» отменённые job'ы (терминальный исход не requeue'ится)
src/stage_engine.py согласовать: снятие таймеров/мониторов (post-deploy monitor, brd-review clock) и безопасное прерывание merge/deploy при STOP
src/notifications.py переиспользовать send_telegram/update_task_tracker для алерта/карточки отмены (never-raise, кликабельный номер)
src/config.py изменить: новый kill-switch stop_status_enabled (+ при необходимости область репо/доп-флаги) по образцу serial_gate_enabled
src/main.py изменить: read-only блок наблюдаемости отмены в GET /queue (аддитивно)
docs/architecture/README.md, CLAUDE.md, CHANGELOG.md обновить в том же PR (golden source)
tests/ добавить тесты (см. 04-test-plan.yaml)

Чистую логику распознавания/решения по STOP желательно вынести в leaf-модуль (по образцу src/serial_gate.py / src/labels.py, never-raise) — окончательно решает архитектор.


3. Функциональные требования

FR-1 — Распознавание и маршрутизация STOP (BR-1, BR-5)

  • handle_issue_updated (webhooks/plane.py) распознаёт перевод задачи в логический статус STOP (через _PLANE_NAME_TO_KEY/группа cancelled) и маршрутизирует в обработчик отмены.
  • Обработчик идемпотентен: если задача уже отменена / done / отсутствует → no-op (BR-5).
  • Контракт — never-raise: ошибка обработки STOP логируется, вебхук-поток не падает (NFR-5).

FR-2 — Остановка активного агента (BR-1a)

  • Для running-job'а задачи послать активному процессу SIGTERM (graceful) через существующий каскад launcher._watchdog (SIGTERM → grace agent_kill_grace_seconds → SIGKILL); PID берётся из jobs.pid.
  • Если активного процесса нет (idle/queued) — шаг no-op.

FR-3 — Отмена job'ов и исчерпание ретраев (BR-1b, BR-1c)

  • Все job'ы задачи (status IN (queued, running)) переводятся в терминальный отменённый исход так, что claim_next_job их больше не выбирает и _finalize_*/reaper не делает авто-requeue.
  • Запрет авто-requeue: после STOP attempts считаются исчерпанными (либо отдельный терминальный статус job cancelled, либо failed+маркер — выбор архитектора). Reaper (job_reaper.py) и _finalize_permanent не должны возвращать отменённый job в queued.

FR-4 — Снятие таймеров и мониторов (BR-1d)

  • При STOP снимаются/обнуляются связанные с задачей таймеры и фоновые наблюдатели: post-deploy monitor (ORCH-021), brd-review clock (ORCH-087), отложенные defer'ы merge-lease/serial-gate.
  • Терминал-скип done/cancelled (reconciler._is_terminal_state, ORCH-068/086) применяется к отменённой задаче, чтобы реконсилятор/мониторы её не трогали (NFR-4).

FR-5 — Полный сброс прогресса (BR-2)

  • Рабочая ветка и worktree задачи удаляются/архивируются (git_worktree.remove_worktree + удаление/ архив Gitea-ветки; never-raise). main не трогается, force-push в main запрещён.
  • Незавершённый прогресс задачи в БД приводится к durable-состоянию «отменена» так, что повторный запуск возможен ТОЛЬКО через start_pipeline с нуля (новая ветка от свежего origin/main, новый analyst). Конкретика «очистить строку vs пометить cancelled» — архитектору; инвариант: возобновления «с середины» не происходит.
  • Docs-артефакты задачи (01..17) сохраняются/бэкапятся — не удаляются вместе с прогрессом.

FR-6 — Закрытие дыры релонча (BR-3, BR-4)

  • handle_status_start (или эквивалентная точка) не должен релончить агента текущей стадии при ручном переводе в промежуточный рабочий статус (Architecture/Development/Review/Testing/ Deploying/Awaiting Deploy/Monitoring/…).
  • Запуск пайплайна остаётся возможен только через статус «To Analyse» → start_pipeline (создание ветки + docs + enqueue analyst). Любой намеренный сценарий «вернуть задачу в работу» (например, после Needs Input) должен быть пересмотрен так, чтобы НЕ опираться на авто-релонч агента сменой рабочего статуса (точный заменяющий механизм — архитектору).

FR-7 — Безопасное прерывание критичных операций (BR-6, NFR-3)

  • STOP во время merge/deploy не оставляет main в half-merged состоянии и не рестартит/не роняет прод-контейнер. Если необратимый шаг (detached self-deploy / слияние PR) уже запущен — STOP не «разрывает» его с порчей: допускается дать необратимому шагу завершиться/зафиксировать честный исход, после чего применить отмену. Точка безопасного прерывания и обработка merge-lease — ADR.

FR-8 — Наблюдаемость (BR-8)

  • Каждое срабатывание STOP: logger.info/warning (что остановлено/сброшено), Telegram-алерт (send_telegram, кликабельный номер plane_issue_link), Plane-коммент (best-effort), обновление live-карточки (update_task_tracker, never-raise), read-only блок отмены в GET /queue.

4. Изменения API

  • Новых обязательных публичных endpoint'ов нет. Триггер STOP — смена статуса Plane (webhook), не REST. (По аналогии с ORCH-088 возможен опциональный админ-эндпоинт принудительной отмены — на усмотрение архитектора; если вводится, описать в ADR и таблице API README.)
  • GET /queueаддитивно: новый read-only блок (например stop/cancel) — флаг enabled, счётчик отменённых задач/job'ов, последние отмены. Существующие ключи не меняются; never-raise.
  • Внешний контракт вебхука POST /webhook/plane — не меняется (новая ветка обработки статуса внутри handle_issue_updated).

5. Изменения схемы БД

Только аддитивные, идемпотентные миграции (общая прод-БД; enduro не трогать). CREATE TABLE IF NOT EXISTS / _ensure_column.

  • Статус job «отменён» (FR-3): требуется терминальный исход, который не requeue'ится. Варианты (выбор — архитектор): новый статус jobs.status='cancelled' ИЛИ переиспользование failed + аддитивный маркер. Требование к выбранному варианту: claim/finalize/reaper не возвращают его в queued; restart-safe.
  • Состояние задачи «отменена» (FR-5, NFR-4): durable-признак, что задача отменена и не возобновляется с середины. Варианты: добавление терминальной стадии cancelled в tasks.stage (учитывается терминал-скипом done/cancelled, уже поддержан reconciler'ом) ИЛИ аддитивная колонка/таблица. STAGE_TRANSITIONS (exit-гейты рёбер) при этом не меняются — отмена это терминальное состояние, не новое ребро конвейера.
  • QG_CHECKS, check_*, job_deps, agent_runs-контракт, repo_freezeбез изменений.

6. Требования к новым/изменённым QG checks

  • Новых QG-проверок не вводить. STOP — это решение диспетчера статусов/планировщика (отмена), а не Quality Gate стадии. Реестр QG_CHECKS и check_* не меняются (по образцу task_deps ORCH-026 и serial_gate ORCH-088 — логика в обработчике/claim, не новый QG).

7. Совместимость / регресс

  • Kill-switch: новый флаг stop_status_enabled (env ORCH_STOP_STATUS_ENABLED) по образцу serial_gate_enabled; False → STOP-обработка и закрытие дыры релонча ведут себя нейтрально (поведение строго как сейчас, нулевая регрессия). При необходимости — область репо (stop_status_repos, CSV) с дефолтом «все репо» (отмена осмысленна и для enduro).
  • Аддитивность БД (NFR-2): только идемпотентные миграции; enduro при выключенном/неприменимом флаге не затрагивается.
  • Инварианты (не нарушать): STAGE_TRANSITIONS, реестр QG_CHECKS, check_*, exit-коды deploy-хука, merge-gate (ORCH-043), merge-verify (ORCH-071/073), image-freshness (ORCH-058), post-deploy контракт (ORCH-021), serial-gate (ORCH-088), auto-label (ORCH-089), семантика Rejected/Approved/Confirm Deploy — без изменений.
  • Self-hosting safety (NFR-3): STOP не рестартит/не роняет прод-контейнер; не push/force-push в main; merge/deploy прерываются fail-safe (без half-merge).
  • never-raise (NFR-5): обработчик STOP и закрытие релонча не валят вебхук-поток; ошибка на единице работы изолирована.
  • Артефакты pipeline (создать/обновить в том же PR): docs/work-items/ORCH-090/06-adr/ADR-001-… (решение архитектора), docs/architecture/README.md (раздел «STOP / отмена задачи (ORCH-090)», обновление описания GET /queue, раздела статусной модели и при новой таблице/колонке — раздела «База данных»), CLAUDE.md (абзац о STOP в статусной модели), CHANGELOG.md (feat:); при новой таблице/колонке — docs/work-items/ORCH-090/08-data-requirements.md; при админ-эндпоинте — таблица API в README.

8. Открытые вопросы для архитектора (не блокируют анализ)

  • OQ-1: Имя Plane-статуса — отдельный «STOP» (новый key) vs переиспользование существующего «Cancelled» (key cancelled уже в _PLANE_NAME_TO_KEY). Влияет на маппинг и группу терминал-скипа.
  • OQ-2: Статус отменённого job — новый cancelled vs failed+маркер.
  • OQ-3: Состояние отменённой задачи — терминальная стадия cancelled vs аддитивная колонка/таблица.
  • OQ-4: Сброс прогресса — удалить строку task (полный re-create через To Analyse) vs пометить cancelled и при To Analyse создавать новую задачу.
  • OQ-5: Удаление vs архив рабочей ветки (и Gitea-ветки) — что безопаснее для аудита.
  • OQ-6: Точка безопасного прерывания merge/deploy (FR-7) и обработка удерживаемого merge-lease.
  • OQ-7: Чем заменить легитимный «resume после Needs Input», который сейчас опирается на релонч в handle_status_start (FR-6), чтобы не сломать намеренный сценарий возврата к работе.