feat(cancel): STOP-status task cancellation + relaunch-hole close (ORCH-090) #101

Merged
admin merged 9 commits from feature/ORCH-090-stop-plane into main 2026-06-09 21:36:13 +03:00
Owner

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

Реализует ТЗ по docs/work-items/ORCH-090/06-adr/ADR-001-stop-cancel-task.md (+ сквозной adr-0026).

Что сделано

  • STOP-статус (логический ключ stop, fail-closed, нет в _DEFAULT_STATES) → handle_stopstage_engine.cancel_task.
  • Полный сброс: graceful SIGTERM (launcher.stop_process, вынесен из _watchdog), cancel_jobs_for_task (терминальный cancelled), remove_worktree + gitea.delete_remote_branch (никогда main, без force-push), durable stage='cancelled' + тумбстон ключей #cancelled-<id>. Docs сохраняются.
  • Отложенная отмена в критичном окне merge/deploy (cancel.in_critical_window fail-CLOSED, cancel_requested_at), применяется детерминированным run_deploy_finalizer. main/прод не трогаются.
  • Кросс-каттинг (adr-0026): терминал-набор {done}{done, cancelled} в serial_gate/task_deps/stages-сток + reaper/worker requeue-гарды. STAGE_TRANSITIONS exit-гейты / QG_CHECKS / check_* — без изменений.
  • Закрытие дыры релонча: relaunch в handle_status_start ограничен стадией analysis; запуск пайплайна — только «To Analyse».
  • Флаги: stop_status_enabled (kill-switch) / stop_status_repos. Блок stop в GET /queue. Аддитивные колонки cancelled_at/cancel_requested_at.

Заметное уточнение ADR (для ревью)

ADR-001 D4 предлагал сохранить plane_issue_id нетронутым, но get_task_by_plane_id/create_task_atomic матчат по plane_id OR plane_issue_id — нетумбстоненный plane_issue_id заблокировал бы clean-slate re-create (BR-3/TR-4). Поэтому plane_issue_id тоже тумбстонится; исходный UUID парсится из суффикса для аудита. Зафиксировано в коде/README/CLAUDE.

Инфра-предусловие

Создать статус STOP с группой cancelled на доске Plane проекта ORCH (его отсутствие = fail-safe no-op).

Тесты

tests/test_stop_status.py (TC-01..TC-14 + D7, 26 кейсов; сигналы/git/gitea замоканы). Обновлены анти-регресс-тесты STAGE_TRANSITIONS 5 прошлых задач (терминал-сток cancelled). Полный регресс pytest tests/ зелёный (1345 passed). Документация (architecture README / CLAUDE / README / .env.example / CHANGELOG) — в этом же PR.

Refs: ORCH-090

🤖 Generated with Claude Code

## ORCH-090 — Механизм отмены задачи: Plane-статус STOP (остановка + полный сброс) Реализует ТЗ по `docs/work-items/ORCH-090/06-adr/ADR-001-stop-cancel-task.md` (+ сквозной `adr-0026`). ### Что сделано - **STOP-статус** (логический ключ `stop`, fail-closed, нет в `_DEFAULT_STATES`) → `handle_stop` → `stage_engine.cancel_task`. - **Полный сброс:** graceful SIGTERM (`launcher.stop_process`, вынесен из `_watchdog`), `cancel_jobs_for_task` (терминальный `cancelled`), `remove_worktree` + `gitea.delete_remote_branch` (никогда `main`, без force-push), durable `stage='cancelled'` + тумбстон ключей `#cancelled-<id>`. Docs сохраняются. - **Отложенная отмена в критичном окне merge/deploy** (`cancel.in_critical_window` fail-CLOSED, `cancel_requested_at`), применяется детерминированным `run_deploy_finalizer`. `main`/прод не трогаются. - **Кросс-каттинг (adr-0026):** терминал-набор `{done}` → `{done, cancelled}` в `serial_gate`/`task_deps`/`stages`-сток + reaper/worker requeue-гарды. `STAGE_TRANSITIONS` exit-гейты / `QG_CHECKS` / `check_*` — без изменений. - **Закрытие дыры релонча:** relaunch в `handle_status_start` ограничен стадией `analysis`; запуск пайплайна — только «To Analyse». - **Флаги:** `stop_status_enabled` (kill-switch) / `stop_status_repos`. Блок `stop` в `GET /queue`. Аддитивные колонки `cancelled_at`/`cancel_requested_at`. ### Заметное уточнение ADR (для ревью) ADR-001 D4 предлагал сохранить `plane_issue_id` нетронутым, но `get_task_by_plane_id`/`create_task_atomic` матчат по `plane_id OR plane_issue_id` — нетумбстоненный `plane_issue_id` заблокировал бы clean-slate re-create (BR-3/TR-4). Поэтому `plane_issue_id` тоже тумбстонится; исходный UUID парсится из суффикса для аудита. Зафиксировано в коде/README/CLAUDE. ### Инфра-предусловие Создать статус **STOP** с группой `cancelled` на доске Plane проекта ORCH (его отсутствие = fail-safe no-op). ### Тесты `tests/test_stop_status.py` (TC-01..TC-14 + D7, 26 кейсов; сигналы/git/gitea замоканы). Обновлены анти-регресс-тесты STAGE_TRANSITIONS 5 прошлых задач (терминал-сток `cancelled`). Полный регресс `pytest tests/` зелёный (**1345 passed**). Документация (architecture README / CLAUDE / README / .env.example / CHANGELOG) — в этом же PR. Refs: ORCH-090 🤖 Generated with [Claude Code](https://claude.com/claude-code)
admin added 8 commits 2026-06-09 21:31:58 +03:00
Introduce the dedicated Plane STOP status as a single declarative task-cancel
mechanism: stop the active agent (graceful SIGTERM cascade), cancel all jobs
(terminal `cancelled`, never requeued), remove the worktree + delete the remote
feature branch (never main, never force-push), drive the task to the new
system-terminal state `cancelled` and tombstone the natural keys so a later
"To Analyse" re-creates it from scratch (docs artefacts preserved). STOP during a
critical merge/deploy window is deferred until the irreversible step finishes
honestly. Also closes the relaunch hole: handle_status_start relaunch is gated to
the `analysis` stage; the only pipeline-start entry point remains "To Analyse".

Cross-cutting (adr-0026): the "task terminal" predicate is widened {done} ->
{done, cancelled} in serial_gate / task_deps / stages sink + reaper/worker
requeue guards. STAGE_TRANSITIONS exit-gates / QG_CHECKS / check_* are unchanged
(`cancelled` is a sink, not a new edge). Additive, never-raise, restart-safe,
under kill-switch ORCH_STOP_STATUS_ENABLED (off -> zero regression).

New: src/cancel.py (leaf), src/gitea.py (delete_remote_branch), tasks columns
cancelled_at/cancel_requested_at, jobs status `cancelled`, GET /queue `stop` block.
Tests: tests/test_stop_status.py (TC-01..TC-14 + D7); full suite green (1345).
Docs updated in-PR (architecture README, CLAUDE.md, README.md, .env.example,
CHANGELOG). ADR-001 D4 refinement: plane_issue_id is tombstoned too (the lookup
ORs on it) — original UUID recoverable from the parseable suffix.

Refs: ORCH-090

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review P1: a STOP while a self-hosting task is PARKED on `deploy` awaiting the
manual `Confirm Deploy` was classified as a critical merge/deploy window solely
because the task still held the per-repo merge-lease (held from merge-gate through
deploy->done). That window is fully reversible — nothing is merged or deployed yet
(the irreversible merge_pr runs later in _handle_merge_verify, always under an
INITIATED marker). So the cancel was DEFERRED to run_deploy_finalizer, which only
runs after Phase B (Confirm Deploy) — the very step the operator pressed STOP to
avoid. Result: the deferred cancel was never applied, the task wedged non-terminal
holding the lease, blocking the repo's serial-gate (ORCH-088) and merges.

Fix: gate the merge-lease branch of cancel.in_critical_window on an actively
RUNNING actor (_task_has_running_actor). Lease held + running deploy/merge job ->
still deferred (genuine in-flight step). Lease held + no running actor (idle
deploy parking) -> NOT critical -> immediate full reset, which itself releases the
lease (step 3c) and drives the task terminal. INITIATED-marker deferral unchanged.

Also fixes review P2 (AC-6): set_task_cancel_requested now returns the first-stamp
fact (rowcount), and the deferred branch only notifies on the first transition —
a repeated STOP while still deferred no longer spams duplicate notifications.

Tests: test_d7_lease_held_idle_parking_is_not_critical,
test_d7_lease_held_with_running_actor_still_critical,
test_d7_stop_on_deploy_awaiting_confirm_full_resets,
test_d7_repeated_stop_in_critical_window_no_duplicate_notify. Full suite green (1349).

Refs: ORCH-090

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tester(ET): auto-commit from tester run_id=502
All checks were successful
CI / test (push) Successful in 36s
CI / test (pull_request) Successful in 31s
5ca9b8fd62
admin force-pushed feature/ORCH-090-stop-plane from 6fc70ce435 to 5ca9b8fd62 2026-06-09 21:31:58 +03:00 Compare
admin merged commit 3b64cddd32 into main 2026-06-09 21:36:13 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/orchestrator#101