147 lines
9.2 KiB
Markdown
147 lines
9.2 KiB
Markdown
---
|
||
work_item: ORCH-090
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-09
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# 03 — Критерии приёмки (Acceptance Criteria): ORCH-090 — Механизм отмены задачи: статус STOP в Plane
|
||
|
||
Work Item: **ORCH-090** · Repo: **orchestrator** · Стадия: analysis
|
||
|
||
Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL**
|
||
(что считается провалом). Любой машинный/ручной reviewer проверяет их буквально по файлам
|
||
репозитория.
|
||
|
||
---
|
||
|
||
## AC-1 — STOP останавливает активного агента
|
||
|
||
**Условие:** задача с running-job'ом переведена в Plane-статус STOP.
|
||
- **PASS:** активному процессу агента послан SIGTERM через существующий каскад
|
||
(`launcher._watchdog`: SIGTERM → grace → SIGKILL); по grace процесс завершён; `agent_runs`/`jobs`
|
||
отражают завершение. Тест демонстрирует вызов остановки по `jobs.pid`.
|
||
- **FAIL:** процесс агента продолжает работать после STOP, либо kill реализован новым «грязным»
|
||
механизмом мимо graceful-каскада, либо STOP падает с исключением.
|
||
|
||
---
|
||
|
||
## AC-2 — Все job'ы задачи отменены без авто-requeue
|
||
|
||
**Условие:** у задачи есть job'ы в `queued` и/или `running`; пришёл STOP.
|
||
- **PASS:** все job'ы задачи переведены в терминальный отменённый исход; `claim_next_job` их не
|
||
выбирает; `_finalize_permanent`/`job_reaper` не возвращают их в `queued` (ретраи исчерпаны).
|
||
Тест: после STOP claim не возвращает job задачи, reaper не requeue'ит.
|
||
- **FAIL:** хотя бы один job задачи остаётся claimable/возвращается в `queued` после STOP, либо
|
||
происходит авто-requeue.
|
||
|
||
---
|
||
|
||
## AC-3 — Таймеры/мониторы сняты, отменённая задача не реконсилируется
|
||
|
||
**Условие:** задача отменена через STOP.
|
||
- **PASS:** связанные таймеры/мониторы (post-deploy monitor, brd-review clock, defer'ы) не активны
|
||
для задачи; `reconciler` (`_is_terminal_state`, терминал-скип `done`/`cancelled`) и `job_reaper`
|
||
не трогают/не «оживляют» отменённую задачу. Тест: reconciler F-1 пропускает отменённую задачу.
|
||
- **FAIL:** монитор/таймер срабатывает по отменённой задаче, либо reconciler/reaper её
|
||
релончит/реанимирует.
|
||
|
||
---
|
||
|
||
## AC-4 — Полный сброс: ветка/worktree удалены/архивированы, прогресс сброшен, docs сохранены
|
||
|
||
**Условие:** задача отменена через STOP.
|
||
- **PASS:** рабочий worktree удалён (`remove_worktree`, never-raise), рабочая ветка удалена/
|
||
заархивирована; `main` не тронут (force-push в `main` отсутствует); прогресс задачи в БД приведён
|
||
к durable-состоянию «отменена» (повторный запуск возможен только с нуля); docs-артефакты
|
||
(`docs/work-items/ORCH-090/01..17`) **сохранены/забэкаплены**, не удалены.
|
||
- **FAIL:** worktree/ветка остаются как «живой» прогресс, либо тронут `main`, либо docs-артефакты
|
||
удалены, либо задача способна продолжиться «с середины».
|
||
|
||
---
|
||
|
||
## AC-5 — Единственный вход к запуску — To Analyse; дыра релонча закрыта
|
||
|
||
**Условие:** существующая задача (с веткой/прогрессом) вручную переведена в промежуточный рабочий
|
||
статус (Architecture/Development/Review/Testing/Deploying/Awaiting Deploy/Monitoring).
|
||
- **PASS:** агент соответствующей стадии **не** запускается (нет `enqueue_job` стадийного агента по
|
||
факту ручной смены рабочего статуса). Запуск пайплайна происходит ТОЛЬКО при статусе «To Analyse»
|
||
(`start_pipeline`). Тест: перевод в Development не порождает job; перевод в To Analyse порождает
|
||
старт с нуля.
|
||
- **FAIL:** ручной перевод в любой промежуточный рабочий статус релончит агента текущей стадии
|
||
(текущее дырявое поведение `handle_status_start`).
|
||
|
||
---
|
||
|
||
## AC-6 — Идемпотентность STOP
|
||
|
||
**Условие:** STOP приходит на задачу, которая уже отменена / `done` / не существует.
|
||
- **PASS:** обработчик — no-op: нет повторного kill, нет повторного удаления ветки, нет ошибок, нет
|
||
Telegram-спама дублями. Тест: повторный STOP не меняет состояние и не бросает.
|
||
- **FAIL:** повторный STOP бросает исключение, повторно убивает/чистит, либо генерирует
|
||
дубль-уведомления.
|
||
|
||
---
|
||
|
||
## AC-7 — Безопасное прерывание merge/deploy (self-hosting safety)
|
||
|
||
**Условие:** STOP приходит во время merge/deploy задачи.
|
||
- **PASS:** `main` не остаётся в half-merged состоянии; прод-контейнер не рестартится/не роняется
|
||
обработчиком STOP; force-push в `main` отсутствует. Если необратимый шаг уже запущен — он не
|
||
«разрывается» с порчей (исход зафиксирован честно, затем применена отмена). Тест/обоснование
|
||
демонстрирует fail-safe точку прерывания.
|
||
- **FAIL:** после STOP `main` в неконсистентном состоянии, прод перезапущен/упал по вине STOP, либо
|
||
выполнен force-push в `main`.
|
||
|
||
---
|
||
|
||
## AC-8 — Kill-switch и нулевая регрессия
|
||
|
||
**Условие:** флаг `stop_status_enabled=False`.
|
||
- **PASS:** STOP-обработка не активна, дыра релонча в поведении не меняется относительно текущего
|
||
кода; `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` не изменены; полный `pytest tests/` зелёный;
|
||
enduro-trails не затронут. При `True` — STOP работает по AC-1…AC-7.
|
||
- **FAIL:** при выключенном флаге поведение отличается от текущего; изменены exit-гейты/реестр QG;
|
||
регресс существующих тестов.
|
||
|
||
---
|
||
|
||
## AC-9 — Аддитивность БД и restart-safe
|
||
|
||
**Условие:** изменения схемы БД и поведение после рестарта.
|
||
- **PASS:** все миграции аддитивны и идемпотентны (`CREATE TABLE IF NOT EXISTS`/`_ensure_column`);
|
||
после рестарта контейнера отменённая задача остаётся отменённой и не релончится. Тест: повторная
|
||
инициализация БД не падает; отменённая задача durable.
|
||
- **FAIL:** деструктивная/неидемпотентная миграция, изменение существующих таблиц-контрактов, либо
|
||
«оживание» отменённой задачи после рестарта.
|
||
|
||
---
|
||
|
||
## AC-10 — Наблюдаемость STOP
|
||
|
||
**Условие:** STOP применён к задаче.
|
||
- **PASS:** факт отмены залогирован; отправлен Telegram-алерт с кликабельным номером задачи;
|
||
Plane-коммент (best-effort); live-карточка обновлена (never-raise); `GET /queue` несёт read-only
|
||
блок отмены. Тест: блок присутствует в ответе `GET /queue`.
|
||
- **FAIL:** STOP не оставляет следов в логе/уведомлениях, либо `GET /queue` падает/не отражает
|
||
отмену.
|
||
|
||
---
|
||
|
||
## Сводная матрица AC ↔ FR/BR
|
||
|
||
| AC | Покрывает |
|
||
|----|-----------|
|
||
| AC-1 | BR-1 / FR-2 |
|
||
| AC-2 | BR-1 / FR-3 |
|
||
| AC-3 | BR-1 / FR-4 / NFR-4 |
|
||
| AC-4 | BR-2 / FR-5 |
|
||
| AC-5 | BR-3, BR-4 / FR-6 |
|
||
| AC-6 | BR-5 / FR-1 |
|
||
| AC-7 | BR-6 / FR-7 / NFR-3 |
|
||
| AC-8 | NFR-1 / FR-6 |
|
||
| AC-9 | NFR-2, NFR-4 / FR-3, FR-5 |
|
||
| AC-10 | BR-8 / FR-8 |
|