From 4a06537afde18cc92da2c0088607d77874e910a7 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Sun, 7 Jun 2026 21:05:49 +0000 Subject: [PATCH] analyst(ET): auto-commit from analyst run_id=339 --- docs/work-items/ORCH-066/01-brd.md | 110 +++++++++++ docs/work-items/ORCH-066/02-trz.md | 178 +++++++++++++++++ .../ORCH-066/03-acceptance-criteria.md | 71 +++++++ docs/work-items/ORCH-066/04-test-plan.yaml | 184 ++++++++++++++++++ 4 files changed, 543 insertions(+) create mode 100644 docs/work-items/ORCH-066/01-brd.md create mode 100644 docs/work-items/ORCH-066/02-trz.md create mode 100644 docs/work-items/ORCH-066/03-acceptance-criteria.md create mode 100644 docs/work-items/ORCH-066/04-test-plan.yaml diff --git a/docs/work-items/ORCH-066/01-brd.md b/docs/work-items/ORCH-066/01-brd.md new file mode 100644 index 0000000..42e382b --- /dev/null +++ b/docs/work-items/ORCH-066/01-brd.md @@ -0,0 +1,110 @@ +# 01 — Business Requirements Document (BRD) + +**Work Item:** ORCH-066 +**Заголовок:** [высокий] Статусная модель Plane: осмысленные статусы этапов +**Стадия:** analysis +**Автор:** Analyst +**Дата:** 2026-06-07 + +--- + +## 1. Контекст и проблема + +Статусная модель Plane оркестратора имеет **семантические перегрузки**: один и тот +же Plane-статус используется для несовместимых смыслов, из-за чего: + +- оператор не понимает, на каком реально этапе стоит задача (доска нечитаема); +- повышается риск ошибки оператора (например, неверный ручной перевод статуса); +- `In Progress` одновременно означает «человек запускает конвейер», «идёт анализ», + «идёт прод-деплой» и «возврат из Needs Input» — четыре разных смысла на одном статусе. + +Уже частично исправлено: ORCH-059 ввёл отдельный статус для подтверждения деплоя +(`Confirm Deploy`), разгрузив перегруженный `Approved`. ORCH-066 завершает наведение +порядка по **утверждённой Owner** статусной модели. + +### Два слоя (критично различать) + +| Слой | Что это | Источник | Трогаем? | +|------|---------|----------|----------| +| **A** | `STAGE_TRANSITIONS` — внутренняя машина стадий (`created→analysis→…→done`) | `src/stages.py` | **НЕТ (инвариант)** | +| **B** | Plane-статусы — индикация на доске | `src/plane_sync.py` + точки в `src/stage_engine.py` / `src/webhooks/plane.py` | **ДА** | + +ORCH-066 меняет **только слой B** и точки, где код вручную проставляет Plane-статусы. + +--- + +## 2. Целевая статусная модель (решение Owner) + +``` +Backlog → Todo → [To Analyse] → Analysis → [In Review → Approved] → Architecture → +Development → Code-Review → Testing → Awaiting Deploy → [Confirm Deploy] → Deploying → +Monitoring after Deploy → Done +``` + +- `[...]` = **действие человека** (вход-триггер). +- Остальное ставит **орк** (индикация). + +### Ветки (нелинейные исходы) +- **Rejected** — откат на предыдущую стадию (человек). +- **Needs Input** — ТОЛЬКО аналитик (НЕ расширять на других агентов). +- **Blocked** — затык / фейл деплоя / деградация прода. +- **Cancelled** — человек решил не делать задачу (валидный выход из In Review). + +--- + +## 3. Бизнес-требования + +| ID | Требование | Приоритет | +|----|------------|-----------| +| **BR-1** | Каждый этап конвейера показывается на доске Plane осмысленным статусом (To Analyse / Analysis / Code-Review / Awaiting Deploy / Deploying / Monitoring after Deploy). | Must | +| **BR-2** | `To Analyse` — единый человеческий вход: (а) старт нового конвейера, (б) resume/relaunch аналитика при возврате из Needs Input. Заменяет роль `In Progress` как входа-триггера. | Must | +| **BR-3** | Стадия `analysis` индицируется отдельным статусом `Analysis` (орк ставит при старте/relaunch аналитика), а не `In Progress`. | Must | +| **BR-4** | Стадия `review` индицируется Plane-статусом `Code-Review` (переименование `Review`). | Must | +| **BR-5** | Self-deploy Phase A (approval-pending) ставит `Awaiting Deploy` вместо `In Review`. | Must | +| **BR-6** | Self-deploy Phase B (старт прод-деплоя) ставит `Deploying`. | Must | +| **BR-7** | Self-deploy Phase C (health-OK финализация) ставит `Monitoring after Deploy` (НЕ `Done` сразу). | Must | +| **BR-8** | Post-deploy monitor (ORCH-021): чистое закрытие окна (HEALTHY) → `Done`; UNHEALTHY/деградация → `Blocked`. | Must | +| **BR-9** | `In Review` разгрузить: оставить ТОЛЬКО за approve-pending артефактов конвейера (BRD/ревью). Выходы: `Approved` (вперёд), `Rejected` (откат), `Cancelled` (человек отменил). | Must | +| **BR-10** | `Needs Input` — БЕЗ ИЗМЕНЕНИЙ. Остаётся только у аналитика (`01-questions.md` → `set_issue_needs_input`). Механизм не трогать. | Must | +| **BR-11** | Возврат аналитика из Needs Input выполняется через `To Analyse` (а НЕ через `In Progress`). Логика fork «старт vs resume» (по наличию task + active-job) сохраняется. | Must (грабли R1) | +| **BR-12** | **Fail-closed:** отсутствие нового статуса в проекте (enduro / Plane API down / fallback `_DEFAULT_STATES`) НЕ приводит к падению; поведение остаётся backward-compatible (паттерн ORCH-059 AC-7). | Must | +| **BR-13** | Reconciler не «оживляет» активные ожидания (`Awaiting Deploy` / `Deploying` / `Monitoring after Deploy`) как зависшие задачи (Guard 2 skip-list). | Must | +| **BR-14** | Документация (golden source) обновлена в том же PR: `CLAUDE.md`, `docs/architecture/README.md`, `CHANGELOG.md`, ADR per-work-item. | Must | + +--- + +## 4. Границы (Out of Scope / НЕ трогать) + +- `STAGE_TRANSITIONS` (`src/stages.py`) — машина стадий, инвариант. +- `QG_CHECKS`, `check_deploy_status`, exit-коды хука (0/1/2), merge-gate, схема БД. +- `Confirm Deploy` (уже работает, ORCH-059). +- Механизм `Needs Input` (analyst-only) — не расширять, не менять. +- Поведение прод-деплоя **не-self** репозиториев (enduro-trails): для них терминальный + переход остаётся `deploy → Done` как сейчас (Monitoring after Deploy не применяется — + post-deploy monitor армится только для self-hosting). +- Автоматический approve / авто-rollback self-hosting (ORCH-54 / ORCH-021 политика + ALERT_ONLY) — не меняется. + +--- + +## 5. Инфра-предусловие (вне кода, делает оператор) + +Новые Plane-статусы в проекте **ORCH** создаёт оператор через Plane API **ДО** эксплуатации: +`To Analyse`, `Analysis`, `Code-Review`, `Awaiting Deploy`, `Deploying`, +`Monitoring after Deploy` (`Confirm Deploy` уже есть). + +Резолвер (`_PLANE_NAME_TO_KEY` + `get_project_states`) подхватывает их **по имени** с +**fail-closed fallback** на `_DEFAULT_STATES` (см. BR-12). Документируется в +`07-infra-requirements.md` (создаёт архитектор) и в `docs/operations/`. + +--- + +## 6. Definition of Done + +- Plane показывает осмысленные статусы на каждом этапе. +- Возврат аналитика из Needs Input работает через `To Analyse`. +- Phase A → `Awaiting Deploy`, Phase B → `Deploying`, Phase C → `Monitoring after Deploy`, + окно HEALTHY → `Done`, фейл → `Blocked`. +- `STAGE_TRANSITIONS` не изменён. +- `pytest tests/ -q` — зелёный. Fail-closed покрыт тестами. +- Документация обновлена. diff --git a/docs/work-items/ORCH-066/02-trz.md b/docs/work-items/ORCH-066/02-trz.md new file mode 100644 index 0000000..a38860c --- /dev/null +++ b/docs/work-items/ORCH-066/02-trz.md @@ -0,0 +1,178 @@ +# 02 — Техническое задание (ТЗ) + +**Work Item:** ORCH-066 +**Стадия:** analysis → (вход для architecture) +**Автор:** Analyst + +> ТЗ фиксирует ТРЕБУЕМОЕ ПОВЕДЕНИЕ и затронутые точки кода. Конкретную архитектуру +> резолвера (точные имена ключей/функций) финализирует архитектор в ADR. Ниже — +> опорный контракт, согласованный с бизнес-запросом Owner. + +--- + +## 1. Задействованные модули `src/` + +| Модуль | Роль в задаче | +|--------|---------------| +| `src/plane_sync.py` | **Ядро изменений (слой B):** реестр логических статусов (`_DEFAULT_STATES`), `_PLANE_NAME_TO_KEY`, маппинг стадия→статус (`_STAGE_TO_STATE_KEY`, `STAGE_VISIBILITY_STATE`), хелперы `set_issue_*`. | +| `src/webhooks/plane.py` | Маршрутизация входящего статуса (`handle_issue_updated`): `To Analyse` → `handle_status_start` (старт **или** resume). | +| `src/stage_engine.py` | Точки ручной простановки статуса: analyst-flow (`Analysis`/`Needs Input`/`In Review`), Phase A (`Awaiting Deploy`), Phase B (`Deploying`), Phase C → `Monitoring after Deploy`, post-deploy monitor → `Done`/`Blocked`. | +| `src/reconciler.py` | F-2 запрос статусов (`To Analyse` в список), Guard 2 skip-list (активные ожидания). | +| `src/stages.py` | **НЕ менять** (инвариант слоя A). Используется только для чтения переходов. | +| `src/config.py` | (При необходимости) kill-switch для новой статусной модели — на усмотрение архитектора (см. §6). | + +--- + +## 2. Изменения статусной модели (слой B) + +### 2.1. Реестр логических статусов (`src/plane_sync.py`) + +Ввести новые **логические ключи** и их имена в `_PLANE_NAME_TO_KEY`: + +| Логический ключ | Plane name | Назначение | +|-----------------|-----------|------------| +| `to_analyse` | `To Analyse` | Вход-триггер (старт + resume аналитика). | +| `analysis` | `Analysis` | Индикация стадии analysis (орк). | +| `code_review` | `Code-Review` | Индикация стадии review (орк). Заменяет `review`. | +| `awaiting_deploy` | `Awaiting Deploy` | Phase A approval-pending (орк). | +| `deploying` | `Deploying` | Phase B прод-деплой идёт (орк). | +| `monitoring` | `Monitoring after Deploy` | Phase C / post-deploy окно (орк). | + +Сохранить существующие: `backlog`, `todo`, `in_progress` (backward-compat), `needs_input`, +`in_review`, `blocked`, `done`, `cancelled`, `architecture`, `development`, `testing`, +`approved`, `rejected`. `Cancelled` уже присутствует в `_PLANE_NAME_TO_KEY`. + +### 2.2. Fail-closed резолюция (КРИТИЧНО — BR-12) + +`get_project_states()` после резолва по API делает `setdefault(k, v)` из `_DEFAULT_STATES`. +Чтобы отсутствие нового статуса в проекте (enduro / Plane down / частичная конфигурация) +**не ломало** конвейер, новые логические ключи в `_DEFAULT_STATES` должны +**алиаситься на существующие UUID** (degrade-to-current): + +| Новый ключ | Default-алиас (UUID) | Деградированное поведение | +|------------|----------------------|---------------------------| +| `to_analyse` | = `in_progress` | enduro/старый проект: `In Progress` по-прежнему триггерит старт/resume. | +| `analysis` | = `in_progress` | analysis показывается как `In Progress` (как сейчас). | +| `code_review` | = `review` | review показывается как `Review` (как сейчас). | +| `awaiting_deploy` | = `in_review` | Phase A показывается как `In Review` (как сейчас). | +| `deploying` | = `in_progress` | Phase B показывается как `In Progress` (как сейчас). | +| `monitoring` | = `done` | Phase C показывается как `Done` (как сейчас); монитор затем держит Done / флипает Blocked. | + +> Эффект: если оператор НЕ создал новый статус — система работает строго как до ORCH-066 +> (никаких падений, никаких 404 от Plane PATCH). Если создал — резолвится по имени и +> используется новый UUID. Это ровно паттерн ORCH-059 AC-7. + +### 2.3. Маппинг стадия → статус + +`src/plane_sync.py`: +- `_STAGE_TO_STATE_KEY`: `analysis` → `analysis` (было `in_progress`); `review` → `code_review` + (было `review`). `deploy` остаётся (управляется Phase A/B/C напрямую, не через + `update_issue_state`). `created`/`architecture`/`development`/`testing`/`done` — без изменений. +- `STAGE_VISIBILITY_STATE`: `review` → `code_review` (было `review`). Добавить + `analysis` → `analysis`, если индикация analysis ставится через `set_issue_stage_state` + (решает архитектор; альтернатива — отдельный хелпер `set_issue_analysis`). +- Сохранить совместимость `STAGE_TO_STATE` / `PLANE_STATES` алиасов (импортируются тестами). + +### 2.4. Точки простановки статуса + +| Место (файл:симв.) | Сейчас | Должно стать | +|--------------------|--------|--------------| +| `webhooks/plane.py` `handle_issue_updated` | `new_state == in_progress` → `handle_status_start` | `new_state == to_analyse` (с fail-closed: при алиасе совпадает с `in_progress`) → `handle_status_start` | +| `webhooks/plane.py` `start_pipeline` (старт) | статус остаётся `In Progress` | при старте/enqueue analyst орк ставит `Analysis` | +| `webhooks/plane.py` `handle_status_start` (resume из Needs Input) | relaunch на `In Progress`-триггере | relaunch на `To Analyse`-триггере; при relaunch орк ставит `Analysis`. Fork «старт vs resume» (по `get_task_by_plane_id` + `has_active_job_for_task`) — **сохранить как есть.** | +| `stage_engine.py` `_handle_analysis_approved_flow` (artifacts ready) | `set_issue_in_review` | оставить `In Review` (BR-9: In Review только за approve-pending конвейера) ✔ без изменений | +| `stage_engine.py` `_handle_analysis_approved_flow` (questions) | `set_issue_needs_input` | **без изменений** (BR-10) | +| `stage_engine.py` `_handle_self_deploy_phase_a` | `set_issue_in_review` | `Awaiting Deploy` (`set_issue_awaiting_deploy` или аналог) | +| `stage_engine.py` `_handle_self_deploy_phase_b` | (статус не меняет) | `Deploying` | +| `stage_engine.py` advance `deploy → done` (terminal-sync, строка ~338) | `set_issue_done` для всех | **self-hosting:** `Monitoring after Deploy` (перед/вместо арма монитора); **не-self:** `Done` как сейчас | +| `stage_engine.py` `run_post_deploy_monitor` (HEALTHY, окно закрыто) | пишет лог + коммент, статус Plane НЕ трогает (остаётся Done) | `Done` (явно) | +| `stage_engine.py` `run_post_deploy_monitor` (DEGRADED) | пишет лог + alert | `Blocked` | + +> **Замечание по terminal-sync (важно для архитектора):** сейчас `advance_stage` на +> `next_stage == "done"` вызывает `set_issue_done` безусловно (строка ~338), затем армит +> post-deploy monitor для self-hosting (~361). Нужно развести: для репо, где +> `post_deploy.post_deploy_applies(repo)` истинно (self-hosting) — ставить `Monitoring +> after Deploy` вместо `Done`, и переложить простановку `Done`/`Blocked` на финал +> монитора (`run_post_deploy_monitor`). Для прочих репо — `Done` как сейчас. + +### 2.5. Новые хелперы `src/plane_sync.py` + +Добавить тонкие обёртки по образцу `set_issue_in_review` (резолв per-project UUID + +`_set_issue_state_direct`), never-raise при отсутствии issue: +- `set_issue_analysis(work_item_id, project_id=None)` +- `set_issue_code_review(...)` (или через `set_issue_stage_state("review")`) +- `set_issue_awaiting_deploy(...)` +- `set_issue_deploying(...)` +- `set_issue_monitoring(...)` + +(Точный набор/именование — на усмотрение архитектора; контракт: per-project резолв + +fail-closed.) + +--- + +## 3. Изменения reconciler (`src/reconciler.py`) + +- **F-2** `_reconcile_plane_project`: добавить `to_analyse` в список запрашиваемых + статусов (`list_issues_by_state([... , to_analyse])`) и в `_reconcile_plane_issue` + маршрутизировать `new_state == to_analyse` → `handle_status_start` (старт при `task is + None`, resume при существующем task без active-job — логика уже в `handle_status_start`). + Сохранить обработку `approved`/`rejected`. При fail-closed алиасе `to_analyse==in_progress` + поведение не дублируется (один и тот же UUID). +- **Guard 2** `_is_blocked_or_needs_input` (F-1 skip): расширить skip-множество активными + ожиданиями — `awaiting_deploy`, `deploying`, `monitoring` — чтобы реконсилер НЕ + «оживлял» их как зависшие (BR-13). Имя метода/семантику можно обобщить + («human-or-active-wait»), флаг `reconcile_skip_blocked_enabled` продолжает управлять + этим networked-чеком. + +> Примечание: F-1 и так не тронет Phase A (`check_deploy_status` red → silent), +> Deploying (active finalizer job), Monitoring (стадия `done`). Guard 2 — явная +> defense-in-depth по требованию Owner. + +--- + +## 4. Изменения API / эндпоинтов + +**Нет** новых HTTP-эндпоинтов. `GET /queue` / `GET /status` — без изменений контракта +(статусы Plane там не отражаются). Изменения только во внешней индикации Plane (PATCH +issue state — существующий механизм). + +--- + +## 5. Изменения схемы БД + +**Нет.** `tasks` не хранит Plane-статус (источник истины — стадия в БД + Plane API). +Миграции не требуются. + +--- + +## 6. Требования к новым QG checks + +**Нет.** `QG_CHECKS` не расширяется. Статусы — индикация, не управление (канон: +машинные вердикты читаются из YAML-frontmatter артефактов, не из Plane-статуса). + +Опционально (на усмотрение архитектора): единый kill-switch новой статусной модели +(env-флаг) для безопасного раската, по образцу `staging_infra_tolerance_enabled` / +`reconcile_skip_blocked_enabled`. Не обязателен, т.к. fail-closed алиасинг (§2.2) уже даёт +backward-compatible деградацию. + +--- + +## 7. Артефакты pipeline, создаваемые/обновляемые + +- `06-adr/ADR-001-plane-status-model.md` — архитектор (решение по резолверу, + алиасингу, разводке terminal-sync). +- `07-infra-requirements.md` — архитектор (список Plane-статусов для ручного создания + оператором + Plane API инструкция). +- Документация (golden source, тот же PR): `CLAUDE.md` (секция статусной модели), + `docs/architecture/README.md` (секция статусов рядом с ORCH-036/ORCH-021), + `CHANGELOG.md`. + +--- + +## 8. Инварианты (проверяемые) + +- `src/stages.py` `STAGE_TRANSITIONS` — байт-в-байт без изменений. +- `QG_CHECKS`, `check_deploy_status`/`_parse_deploy_status`, exit-коды хука, merge-gate, + схема БД, `Confirm Deploy`, механизм `Needs Input` — без изменений. +- Все новые `set_issue_*` / резолв — never-raise (Plane down ⇒ degrade, не crash). +- Поведение enduro (не-self) и его терминальный `Done` — без регресса. diff --git a/docs/work-items/ORCH-066/03-acceptance-criteria.md b/docs/work-items/ORCH-066/03-acceptance-criteria.md new file mode 100644 index 0000000..73252f3 --- /dev/null +++ b/docs/work-items/ORCH-066/03-acceptance-criteria.md @@ -0,0 +1,71 @@ +# 03 — Критерии приёмки (Acceptance Criteria) + +**Work Item:** ORCH-066 + +Каждый критерий — чёткое условие PASS/FAIL. Покрытие тестами — см. `04-test-plan.yaml`. + +--- + +## Группа A — Вход и стадия анализа + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-1** | `To Analyse` запускает конвейер | Перевод issue без task в `To Analyse` → `handle_status_start` → `start_pipeline` (создаётся task, ветка, enqueue analyst). | Не запускается / запускается на другом статусе. | +| **AC-2** | `To Analyse` делает resume аналитика из Needs Input | Существующий task без active-job + перевод в `To Analyse` → relaunch агента текущей стадии (analyst читает свежие комменты). Fork «старт vs resume» определяется по `get_task_by_plane_id` + `has_active_job_for_task` (как раньше). | Создаётся второй task / двойной запуск / resume не происходит. | +| **AC-3** | Стадия `analysis` индицируется статусом `Analysis` | При старте/relaunch аналитика орк ставит `Analysis`. | Остаётся `In Progress` (при наличии статуса `Analysis` в проекте). | +| **AC-4** | Busy-guard сохранён | `To Analyse` при существующем active-job для task → НЕ relaunch (no double launch). | Двойной запуск агента. | + +## Группа B — Code-Review + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-5** | Стадия `review` индицируется `Code-Review` | Вход в стадию `review` → Plane-статус `Code-Review`. | Остаётся `Review` (при наличии нового статуса). | + +## Группа C — Self-deploy фазы + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-6** | Phase A → `Awaiting Deploy` | `_handle_self_deploy_phase_a` ставит `Awaiting Deploy` (не `In Review`). | Ставит `In Review` (при наличии нового статуса). | +| **AC-7** | Phase B → `Deploying` | `_handle_self_deploy_phase_b` при успешном `initiate_deploy` ставит `Deploying`. | Статус не меняется / иной. | +| **AC-8** | Phase C → `Monitoring after Deploy` (self) | Финализатор SUCCESS для self-hosting → статус `Monitoring after Deploy`, НЕ `Done` сразу. | Ставит `Done` немедленно (для self-hosting). | +| **AC-9** | Не-self deploy → `Done` без регресса | Для не-self репо (`post_deploy_applies==False`) терминальный `deploy → done` ставит `Done` как сейчас. | Не-self репо получает `Monitoring after Deploy` / иной регресс. | + +## Группа D — Post-deploy monitor + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-10** | Чистое окно → `Done` | `run_post_deploy_monitor` HEALTHY + окно исчерпано → статус `Done`. | Остаётся `Monitoring after Deploy` / иной. | +| **AC-11** | Деградация → `Blocked` | `run_post_deploy_monitor` DEGRADED → статус `Blocked` (+ существующий ALERT_ONLY для self). | Остаётся в Monitoring / ставит Done. | +| **AC-12** | Self-hosting монитор не рестартит прод | Тик НИКОГДА не рестартит/откатывает прод-контейнер (ORCH-021 BR-5 сохранён). | Тик трогает прод-контейнер. | + +## Группа E — In Review / Needs Input / ветки + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-13** | `In Review` только за approve-pending конвейера | `In Review` ставится лишь для approve артефактов (analyst BRD/ревью), не для Phase A. | Phase A / иные стадии ставят `In Review`. | +| **AC-14** | `Needs Input` без изменений | Поведение `set_issue_needs_input` (analyst `01-questions.md`) идентично прежнему; не расширено на других агентов. | Механизм изменён / расширен. | +| **AC-15** | `Cancelled` — валидный выход из In Review без действий конвейера | Перевод в `Cancelled` → орк не выполняет advance/rollback (индикация, не управление). | Орк совершает действие конвейера на `Cancelled`. | + +## Группа F — Fail-closed (КРИТИЧНО) + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-16** | Отсутствие нового статуса не ломает конвейер | Проект без новых статусов (enduro/частичный/Plane down) → `get_project_states` отдаёт default-алиасы; все `set_issue_*`/триггеры работают backward-compatible, без исключений и без 404 PATCH. | Падение / необработанное исключение / зависание задачи. | +| **AC-17** | enduro `In Progress` по-прежнему стартует конвейер | Через `to_analyse`-алиас (= `in_progress` UUID) перевод enduro-issue в `In Progress` запускает старт/resume. | enduro-старт сломан. | +| **AC-18** | Резолв по имени | При наличии статуса в проекте по `name` (`_PLANE_NAME_TO_KEY`) используется его UUID, а не default-алиас. | Используется неверный UUID. | + +## Группа G — Reconciler + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-19** | F-2 реконсилирует `To Analyse` | `_reconcile_plane_project` запрашивает `to_analyse` и маршрутизирует к `handle_status_start` (старт/resume при потерянном webhook). | `To Analyse`-старты не реконсилируются. | +| **AC-20** | Guard 2 skip активных ожиданий | Задачи в `Awaiting Deploy` / `Deploying` / `Monitoring after Deploy` НЕ «оживляются» F-1 как зависшие. | Реконсилер advance'ит активное ожидание. | + +## Группа H — Инварианты и документация + +| ID | Критерий | PASS | FAIL | +|----|----------|------|------| +| **AC-21** | `STAGE_TRANSITIONS` не изменён | `src/stages.py` `STAGE_TRANSITIONS` идентичен (diff пуст). | Любое изменение слоя A. | +| **AC-22** | Реестры/контракты не изменены | `QG_CHECKS`, `check_deploy_status`, exit-коды хука, merge-gate, схема БД, `Confirm Deploy` — без изменений. | Любое изменение перечисленного. | +| **AC-23** | Тесты зелёные | `pytest tests/ -q` проходит полностью; новые fail-closed тесты присутствуют и зелёные. | Любой красный тест. | +| **AC-24** | Документация обновлена (golden source) | `CLAUDE.md`, `docs/architecture/README.md`, `CHANGELOG.md` обновлены; заведён `06-adr/ADR-001-*`. | Любой из артефактов не обновлён. | diff --git a/docs/work-items/ORCH-066/04-test-plan.yaml b/docs/work-items/ORCH-066/04-test-plan.yaml new file mode 100644 index 0000000..4355822 --- /dev/null +++ b/docs/work-items/ORCH-066/04-test-plan.yaml @@ -0,0 +1,184 @@ +work_item: ORCH-066 +description: > + Тест-план статусной модели Plane (слой B). Покрывает осмысленные статусы этапов, + возврат аналитика через To Analyse, фазы self-deploy, post-deploy monitor, + fail-closed деградацию и reconciler. Слой A (STAGE_TRANSITIONS) проверяется на + неизменность. Все тесты — pytest; Plane API мокается (httpx), как в существующих + tests/test_plane_*.py / tests/test_orch10_states.py. + +tests: + # --- Группа A: вход и стадия анализа --- + - id: TC-01 + type: unit + description: "To Analyse без существующего task -> handle_status_start -> start_pipeline (старт конвейера)." + module: tests/test_status_trigger.py + covers: [AC-1] + expected: PASS + + - id: TC-02 + type: integration + description: "To Analyse при существующем task без active-job -> relaunch агента стадии (resume из Needs Input), новый task НЕ создаётся." + module: tests/test_plane_to_analyse_resume.py + covers: [AC-2, BR-11] + expected: PASS + + - id: TC-03 + type: unit + description: "Старт/relaunch аналитика ставит Plane-статус Analysis (а не In Progress) при наличии статуса в проекте." + module: tests/test_plane_status_model.py + covers: [AC-3] + expected: PASS + + - id: TC-04 + type: unit + description: "To Analyse при существующем task с active-job -> НЕ relaunch (busy-guard)." + module: tests/test_plane_to_analyse_resume.py + covers: [AC-4] + expected: PASS + + # --- Группа B: Code-Review --- + - id: TC-05 + type: unit + description: "Вход в стадию review -> Plane-статус Code-Review (маппинг _STAGE_TO_STATE_KEY / STAGE_VISIBILITY_STATE)." + module: tests/test_plane_status_model.py + covers: [AC-5] + expected: PASS + + # --- Группа C: self-deploy фазы --- + - id: TC-06 + type: unit + description: "_handle_self_deploy_phase_a ставит Awaiting Deploy (не In Review)." + module: tests/test_deploy_approve.py + covers: [AC-6, AC-13] + expected: PASS + + - id: TC-07 + type: unit + description: "_handle_self_deploy_phase_b при успешном initiate_deploy ставит Deploying." + module: tests/test_deploy_approve.py + covers: [AC-7] + expected: PASS + + - id: TC-08 + type: integration + description: "Phase C (finalizer SUCCESS) для self-hosting ставит Monitoring after Deploy, НЕ Done; армит post-deploy monitor." + module: tests/test_deploy_terminal_sync.py + covers: [AC-8] + expected: PASS + + - id: TC-09 + type: integration + description: "Не-self репо: deploy->done ставит Done (без регресса, Monitoring не применяется)." + module: tests/test_deploy_terminal_sync.py + covers: [AC-9] + expected: PASS + + # --- Группа D: post-deploy monitor --- + - id: TC-10 + type: unit + description: "run_post_deploy_monitor HEALTHY + окно исчерпано -> Plane-статус Done." + module: tests/test_post_deploy.py + covers: [AC-10] + expected: PASS + + - id: TC-11 + type: unit + description: "run_post_deploy_monitor DEGRADED -> Plane-статус Blocked (+ ALERT_ONLY для self)." + module: tests/test_post_deploy.py + covers: [AC-11] + expected: PASS + + - id: TC-12 + type: unit + description: "Self-hosting тик НЕ рестартит/не откатывает прод-контейнер (ORCH-021 BR-5 сохранён)." + module: tests/test_post_deploy.py + covers: [AC-12] + expected: PASS + + # --- Группа E: In Review / Needs Input / Cancelled --- + - id: TC-13 + type: unit + description: "In Review ставится только за approve-pending конвейера (analyst BRD ready), не Phase A." + module: tests/test_analyst_status_only_regression.py + covers: [AC-13] + expected: PASS + + - id: TC-14 + type: unit + description: "set_issue_needs_input (analyst 01-questions.md) поведение идентично прежнему; не расширено на других агентов." + module: tests/test_plane_status_model.py + covers: [AC-14, BR-10] + expected: PASS + + - id: TC-15 + type: unit + description: "Перевод в Cancelled -> handle_issue_updated не выполняет advance/rollback (индикация, не управление)." + module: tests/test_plane_webhook.py + covers: [AC-15] + expected: PASS + + # --- Группа F: fail-closed (критично) --- + - id: TC-16 + type: unit + description: "Проект без новых статусов: get_project_states отдаёт default-алиасы (to_analyse=in_progress, code_review=review, awaiting_deploy=in_review, monitoring=done); исключений нет." + module: tests/test_plane_status_failclosed.py + covers: [AC-16, BR-12] + expected: PASS + + - id: TC-17 + type: unit + description: "Plane API down -> get_project_states fallback на _DEFAULT_STATES; set_issue_* never-raise." + module: tests/test_plane_status_failclosed.py + covers: [AC-16] + expected: PASS + + - id: TC-18 + type: integration + description: "enduro In Progress по-прежнему стартует конвейер через to_analyse-алиас." + module: tests/test_plane_status_failclosed.py + covers: [AC-17] + expected: PASS + + - id: TC-19 + type: unit + description: "Резолв по имени: при наличии статуса в проекте используется его UUID, а не default-алиас." + module: tests/test_orch10_states.py + covers: [AC-18] + expected: PASS + + # --- Группа G: reconciler --- + - id: TC-20 + type: integration + description: "F-2 _reconcile_plane_project запрашивает to_analyse и маршрутизирует к handle_status_start (потерянный webhook старта/resume)." + module: tests/test_reconciler_plane.py + covers: [AC-19] + expected: PASS + + - id: TC-21 + type: unit + description: "Guard 2: задачи в Awaiting Deploy / Deploying / Monitoring after Deploy НЕ оживляются F-1 как зависшие." + module: tests/test_reconciler.py + covers: [AC-20, BR-13] + expected: PASS + + # --- Группа H: инварианты --- + - id: TC-22 + type: unit + description: "STAGE_TRANSITIONS не изменён (явная проверка ключей/значений слоя A)." + module: tests/test_plane_status_model.py + covers: [AC-21] + expected: PASS + + - id: TC-23 + type: unit + description: "QG_CHECKS реестр и check_deploy_status контракты не изменены." + module: tests/test_plane_status_model.py + covers: [AC-22] + expected: PASS + + - id: TC-24 + type: integration + description: "Полный прогон pytest tests/ -q зелёный (регрессия)." + module: tests/ + covers: [AC-23] + expected: PASS