18 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 |
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 → graceagent_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считаются исчерпанными (либо отдельный терминальный статус jobcancelled, либо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_depsORCH-026 иserial_gateORCH-088 — логика в обработчике/claim, не новый QG).
7. Совместимость / регресс
- Kill-switch: новый флаг
stop_status_enabled(envORCH_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 — новый
cancelledvsfailed+маркер. - OQ-3: Состояние отменённой задачи — терминальная стадия
cancelledvs аддитивная колонка/таблица. - 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), чтобы не сломать намеренный сценарий возврата к работе.