From 0b5fede802340a9aad6c1072465a12bfff0414e9 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Tue, 9 Jun 2026 11:54:22 +0300 Subject: [PATCH] analyst(ET): auto-commit from analyst run_id=441 --- docs/work-items/ORCH-089/01-brd.md | 123 ++++++++++ docs/work-items/ORCH-089/02-trz.md | 210 ++++++++++++++++++ .../ORCH-089/03-acceptance-criteria.md | 153 +++++++++++++ docs/work-items/ORCH-089/04-test-plan.yaml | 172 ++++++++++++++ 4 files changed, 658 insertions(+) create mode 100644 docs/work-items/ORCH-089/01-brd.md create mode 100644 docs/work-items/ORCH-089/02-trz.md create mode 100644 docs/work-items/ORCH-089/03-acceptance-criteria.md create mode 100644 docs/work-items/ORCH-089/04-test-plan.yaml diff --git a/docs/work-items/ORCH-089/01-brd.md b/docs/work-items/ORCH-089/01-brd.md new file mode 100644 index 0000000..d0476d3 --- /dev/null +++ b/docs/work-items/ORCH-089/01-brd.md @@ -0,0 +1,123 @@ +# 01 — BRD: Авто-режим по лейблам (autoApprove + autoDeploy) + +**Work Item:** ORCH-089 +**Repo:** orchestrator (self-hosting) +**Стадия:** analysis +**Приоритет:** Бэклог (запуск по решению Славы, serial e2e после ORCH-88) + +> ⚠️ Прошлый подход (09.06) ОТМЕНЁН: «Стрим ревьюит и апрувит BRD» — НЕ реализовывать. +> Актуальная модель: автономность управляется **лейблами Plane на задаче**, без участия людей. + +## 1. Проблема / зачем + +В конвейере два **человеческих** гейта — точки, где конвейер останавливается и ждёт +ручного клика человека (Слава/Стрим): + +1. **Гейт BRD** (стадия `analysis`): после завершения analyst задача переводится в + `In Review` и ждёт, пока человек вручную выставит Plane-статус **Approved**, чтобы + уйти на `architecture`. +2. **Гейт деплоя** (стадия `deploy`): после зелёного staging задача переводится в + `Awaiting Deploy` (Phase A, ORCH-036/059) и ждёт, пока человек вручную выставит + статус **Confirm Deploy**, чтобы запустить прод-деплой (Phase B). + +Для задач, которым **доверяем**, оба ручных решения избыточны и тормозят пакетный +автономный прогон («10–20 задач за ночь», эпик ORCH-088). Нужно снять эти два +человеческих решения **выборочно и декларативно** — через лейблы на конкретной задаче. + +## 2. Бизнес-цель + +Дать оператору возможность пометить задачу лейблом и тем самым **разрешить орку +самому пройти соответствующий человеческий гейт**, не трогая ни одну техническую +проверку. Доверие выражается лейблом — на уровне отдельной задачи, обратимо, прозрачно. + +## 3. Модель (решение Славы, 09.06) + +| Лейбл на задаче | Эффект | +|-----------------|--------| +| `autoApprove` | Орк САМ подтверждает BRD (гейт 1: `In Review → Approved`), без человека. Конвейер идёт на `architecture`. | +| `autoDeploy` | Орк САМ подтверждает прод-деплой (гейт 2: `Confirm Deploy`) и деплоит в прод после зелёного staging + всех тех-гейтов, без человека. | + +**Лейблы независимы:** +- только `autoApprove` → BRD авто, деплой вручную; +- только `autoDeploy` → BRD вручную, деплой авто; +- оба → полная автономность (анализ → деплой без единого ручного клика); +- без лейблов → **текущее поведение** (оба гейта ручные, нулевая регрессия). + +## 4. Критический инвариант — авто-режим снимает ТОЛЬКО человеческое решение + +Авто-режим **не отключает и не ослабляет ни одну техническую проверку**. Все +тех-гейты остаются на месте и блокируют при провале ровно как сейчас: + +- `check_ci_green` (CI зелёный); +- `check_staging_status` (staging healthy, ORCH-035); +- security-гейт (gitleaks + pip-audit, ORCH-022); +- merge-gate / re-test / merge-lease (ORCH-043); +- image-freshness / provenance guard (ORCH-058); +- merge-verify + regression-guard (ORCH-071/073); +- post-deploy monitor (ORCH-021). + +`autoDeploy` **никогда не деплоит сломанное** — он лишь заменяет ручной клик +«Confirm Deploy» на авто-проход, и только когда все тех-гейты на ребре +`deploy-staging → deploy` уже зелёные. `autoApprove` заменяет ручной клик «Approved», +но артефакты анализа (BRD/TRZ/AC/test-plan) должны существовать (`check_analysis_complete`). + +## 5. Fail-safe (безопасность по умолчанию) + +При любой неоднозначности — **откат к ручному гейту** (never auto): + +- лейбл не распознан / Plane API недоступен / ошибка чтения лейблов; +- неоднозначность сопоставления имени лейбла; +- любое исключение в логике определения авто-режима. + +Лучше подождать человека, чем авто-пропустить гейт по ошибке. Это согласуется с +fail-closed-практикой проекта (ORCH-059 «нет статуса → нет деплоя»). + +## 6. Прозрачность (обязательно) + +Каждый авто-проход гейта **логируется и виден** оператору: + +- запись в лог (кто/почему: `label autoApprove → auto-approved BRD` / + `label autoDeploy → auto-confirmed prod deploy`); +- Telegram-уведомление + строка/обновление в live-карточке задачи (ORCH-042/087); +- Plane-коммент в задаче (как при ручном проходе гейта). + +Слава должен по карточке/Telegram видеть, что задача прошла гейт автоматически (а не +руками), и какой именно лейбл это разрешил. + +## 7. Бизнес-требования (BR) + +- **BR-1.** Лейбл `autoApprove` на задаче → BRD подтверждается автоматически + (`In Review → Approved`) сразу после успешного analyst (артефакты готовы), + конвейер идёт на `architecture`. Закрывается клок `brd_review_ended_at`. +- **BR-2.** Лейбл `autoDeploy` на задаче → после зелёного staging и всех тех-гейтов + прод-деплой (Phase B) триггерится автоматически, без ручного `Confirm Deploy`. +- **BR-3.** Лейблы независимы; комбинация обоих даёт полную автономность анализ→деплой. +- **BR-4.** Без лейблов поведение конвейера **не меняется** (оба гейта ручные). +- **BR-5.** Тех-гейт красный → авто-режим НЕ проходит гейт; задача встаёт/заворачивается + ровно как сейчас (авто-режим не маскирует провал тех-проверки). +- **BR-6.** Нераспознанный/спорный лейбл / ошибка чтения → fail-safe к ручному гейту. +- **BR-7.** Каждый авто-проход гейта логируется и виден в карточке/Telegram + Plane. +- **BR-8.** Лейблы `autoApprove` и `autoDeploy` должны существовать в Plane-проекте ORCH + (сейчас их нет — создать через labels API; инфра-предусловие). +- **BR-9.** Раскат под kill-switch (как ORCH-035/043/059/088); выключенный флаг → + строго прежнее поведение (нулевая регрессия для enduro-trails и для самого ORCH). +- **BR-10.** Авто-проходы — только для self-hosting/applicable репо по тому же + условному принципу, что и self-deploy (Phase A/B существуют только для self-hosting). + Гейт BRD логически применим к любому репо, но раскат гейтится флагом/scope. + +## 8. Вне scope (НЕ делаем в этой задаче) + +- Любая логика «Стрим/человек ревьюит BRD» (отменённый подход). +- Управление лейблами из UI оркестратора. +- Авто-режим для REQUEST_CHANGES / откатов reviewer/tester (это не человеческие гейты — + это технические вердикты, они и так автоматические). +- Снятие/ослабление любого технического гейта. +- Авто-снятие per-repo freeze (ORCH-088) — freeze остаётся ручным. + +## 9. Допущения и зависимости + +- Plane labels API v1 работает (`POST /labels/` подтверждён в бизнес-запросе; GET + лейблов проекта и поле `labels` issue — проверить на этапе архитектуры/разработки). +- Идёт поверх ORCH-088 (serial gate) — авто-режим совместим с serial e2e: serial-gate + сериализует задачи, авто-режим убирает человеческие паузы внутри прохода одной задачи. +- Self-deploy Phase A/B/C (ORCH-036/059/071) — точки врезки авто-деплоя. diff --git a/docs/work-items/ORCH-089/02-trz.md b/docs/work-items/ORCH-089/02-trz.md new file mode 100644 index 0000000..443a703 --- /dev/null +++ b/docs/work-items/ORCH-089/02-trz.md @@ -0,0 +1,210 @@ +# 02 — ТЗ: Авто-режим по лейблам (autoApprove + autoDeploy) + +**Work Item:** ORCH-089 +**Базируется на BRD:** `01-brd.md` + +> ТЗ фиксирует **что** должно измениться (модули, API, БД, гейты, артефакты, +> флаги) и предметные требования к поведению. Архитектурное **как** (структура +> leaf-модуля, стратегия кэша лейблов, точная сигнатура хелперов) — за архитектором +> (ADR `06-adr/`). ТЗ задаёт границы, которые архитектура обязана соблюсти. + +--- + +## 1. Обзор изменения + +Ввести два независимых авто-прохода человеческих гейтов, управляемых лейблами Plane +на конкретной задаче: + +- **autoApprove** — авто-проход гейта BRD (`analysis`: `In Review → Approved`). +- **autoDeploy** — авто-проход гейта прод-деплоя (`deploy`: `Confirm Deploy` → Phase B). + +Принцип врезки — аддитивно, по образцу условных под-гейтов (ORCH-035/043/058/088): +leaf-модуль чистой логики (never-raise) + точечные врезки в существующие точки +принятия решений + флаги в `config.py`. **`STAGE_TRANSITIONS` и реестр `QG_CHECKS` +НЕ трогаются** — авто-режим переиспользует уже существующие переходы и гейты, лишь +устраняя ожидание человеческого сигнала. + +--- + +## 2. Задействованные модули `src/` + +| Модуль | Роль изменения | +|--------|----------------| +| `src/labels.py` (**новый, leaf**) | Чистая логика авто-режима: `auto_approve_applies(repo)`, `auto_deploy_applies(repo)`, `has_label(work_item_id, label, project_id) -> bool/None`, нормализация имён лейблов, fail-safe. never-raise. | +| `src/plane_sync.py` | Новая функция чтения лейблов issue из Plane API (`fetch_issue_labels`) + резолв карты лейблов проекта (имя↔uuid, с кэшем по образцу `get_project_states`). Новый сеттер статуса `set_issue_approved` (PATCH в Approved-UUID) для индикации авто-аппрува. | +| `src/stage_engine.py` | Врезка autoApprove в `_handle_analysis_approved_flow` (ветка `files_ok`, после `set_issue_in_review`). Врезка autoDeploy в `_handle_self_deploy_phase_a` (после advance на `deploy`, перед возвратом). | +| `src/config.py` | Новые флаги `auto_label_enabled`, `auto_approve_label`, `auto_deploy_label`, `auto_label_repos` (+ при необходимости TTL кэша лейблов). | +| `src/main.py` (`GET /queue`) | Аддитивный блок наблюдаемости `auto_labels` (опционально: счётчики авто-проходов). | +| `src/webhooks/plane.py` | (Опц.) если payload вебхука несёт `labels` — использовать как быстрый путь; иначе чтение через `fetch_issue_labels`. Источник истины лейблов — Plane API (надёжнее payload). | + +> Точные имена функций/флагов — ориентир; финальные сигнатуры закрепляет ADR. +> Обязательное требование: вся логика определения авто-режима — **never-raise** и +> при ошибке возвращает «нет авто» (fail-safe к ручному гейту, BR-6). + +--- + +## 3. Точки врезки (insertion points) — предметные требования + +### 3.1 Гейт BRD (autoApprove) + +**Текущее поведение** (`src/stage_engine.py::_handle_analysis_approved_flow`, ветка +`files_ok`, ~стр. 584–599): +1. `set_issue_in_review(work_item_id)`; +2. Plane-коммент «артефакты готовы»; +3. `notify_approve_requested(task_id)`; +4. `return` — **без advance**; ждёт ручного Approved через webhook + (`handle_verdict(approved=True)` → `_try_advance_stage` → advance на `architecture`). + +**Требуемое поведение при `autoApprove`:** +- ПОСЛЕ установки `In Review` и коммента (для прозрачности и клока) проверить лейбл + `autoApprove` на задаче; +- если лейбл есть И `auto_approve_applies(repo)` И `auto_label_enabled`: + - выставить Plane-статус **Approved** (индикация; `set_issue_approved`); + - залогировать авто-проход (`label autoApprove → BRD auto-approved`); + - отправить Telegram + Plane-коммент о факте авто-аппрува (BR-7, прозрачность); + - инициировать тот же advance, что делает ручной Approved, т.е. переход + `analysis → architecture` через штатный путь (`advance_stage(..., finished_agent=None)` + с `qg_passed`/`approved-via-status`-семантикой), чтобы: + - закрылся клок `brd_review_ended_at` (`mark_brd_review_ended`), + - выполнились все стандартные пост-переходные эффекты (карточка, plane-sync); +- если лейбла нет / ошибка чтения → **прежнее поведение** (return, ждём человека). + +> Требование к реализации advance: НЕ дублировать переходную логику. Авто-аппрув +> обязан идти через тот же advance-путь, что и человеческий Approved (единый источник +> истины перехода). Защита от двойного advance/гонки с реальным webhook — идемпотентность +> (advance применяется один раз; повторный сигнал — no-op). + +### 3.2 Гейт прод-деплоя (autoDeploy) + +**Текущее поведение** (`src/stage_engine.py::_handle_self_deploy_phase_a`, ~стр. 1151): +вызывается на ребре `deploy-staging → deploy` ПОСЛЕ зелёных под-гейтов (security → +merge-gate → image-freshness → staging). Делает: +1. `update_task_stage(task_id, "deploy")` + `notify_stage_change`; +2. `set_issue_awaiting_deploy`; +3. `write_marker(APPROVE_REQUESTED)`; +4. Plane-коммент + Telegram «смените статус на Confirm Deploy»; +5. `return` — ждёт ручного `Confirm Deploy` → `handle_confirm_deploy` → + `advance_stage(confirm_deploy=True)` → `_handle_self_deploy_phase_b` (initiate_deploy). + +**Требуемое поведение при `autoDeploy`:** +- Все тех-гейты ребра `deploy-staging → deploy` уже зелёные к моменту Phase A + (иначе сюда не дошли бы) — это структурно гарантирует BR-5 (авто не деплоит сломанное); +- ПОСЛЕ advance на `deploy` (шаг 1) проверить лейбл `autoDeploy`; +- если лейбл есть И `auto_deploy_applies(repo)` И `auto_label_enabled`: + - залогировать авто-проход (`label autoDeploy → prod deploy auto-confirmed`); + - Telegram + Plane-коммент о факте авто-деплоя (BR-7); + - инициировать Phase B тем же путём, что ручной Confirm Deploy + (`_handle_self_deploy_phase_b(...)`), сохранив идемпотентность (маркер `INITIATED`); + - индикация статуса — `Deploying` (ставит уже сам Phase B); +- если лейбла нет / ошибка → **прежнее поведение** (Phase A ждёт человека). + +> Требование: НЕ обходить и НЕ дублировать тех-гейты. autoDeploy запускается строго +> в точке, где Phase A уже прошёл все под-гейты. Phase C (finalizer) + merge-verify + +> regression-guard + post-deploy monitor остаются неизменны и продолжают верифицировать +> результат деплоя. + +--- + +## 4. Изменения Plane API + +Новых endpoint оркестратора (FastAPI) — **нет**. Изменяется только клиентское +взаимодействие с Plane API v1: + +| Действие | Endpoint Plane | Назначение | +|----------|----------------|------------| +| Чтение лейблов issue | `GET /workspaces/{slug}/projects/{pid}/issues/{issue_id}/` → поле `labels` (список uuid) | Узнать, какие лейблы навешены на задачу. | +| Карта лейблов проекта | `GET /workspaces/{slug}/projects/{pid}/labels/` → `[{id,name}]` | Сопоставить uuid лейбла ↔ имя (`autoApprove`/`autoDeploy`). Кэшировать (TTL, образец `get_project_states`/`plane_states_ttl_s`). | +| Установка Approved | `PATCH /…/issues/{issue_id}/` `{"state": }` | Индикация авто-аппрува BRD (`set_issue_approved`, через `get_project_states(...)["approved"]`). | +| (Инфра) создание лейблов | `POST /…/labels/` | Однократно создать `autoApprove` и `autoDeploy` в проекте ORCH (см. `07-infra-requirements.md`). | + +**Требования:** +- Все GET/PATCH к Plane — через существующие `PLANE_HEADERS`/`_resolve_project_id`, + таймаут как у соседей (10с), never-raise. +- Сопоставление лейбла — по **имени** (нормализованному: регистр/пробелы), резолвенному + из карты лейблов проекта; неоднозначность/нет совпадения → «нет лейбла» (fail-safe). +- Чтение лейблов НЕ должно блокировать конвейер при недоступности Plane: ошибка → + «нет авто» → ручной гейт. + +--- + +## 5. Изменения схемы БД + +**Не требуются.** Авто-режим — stateless относительно БД: +- источник истины лейблов — Plane (читается на гейте); +- идемпотентность авто-деплоя обеспечена существующими sentinel-маркерами + (`APPROVE_REQUESTED`/`INITIATED`, ORCH-036), а не новой колонкой; +- клок `brd_review_*` уже существует (ORCH-087). + +Если архитектура решит кэшировать факт авто-прохода для наблюдаемости — допускается +**аддитивная** идемпотентная миграция (`_ensure_column`, образец ORCH-065 `jobs.pid`), +но это не требование ТЗ (предпочтительно без миграции, restart-safe через Plane/маркеры). + +--- + +## 6. Новые QG checks + +**Не вводятся.** Авто-режим не добавляет проверок качества — он устраняет ожидание +человеческого сигнала на существующих гейтах. Реестр `QG_CHECKS` и +`check_analysis_approved` / `check_deploy_status` / `check_staging_status` — +**без изменений**. (Это сознательно: добавление QG-чека усложнило бы матрицу и нарушило +инвариант «STAGE_TRANSITIONS/QG_CHECKS не трогаются», характерный для соседних под-гейтов.) + +--- + +## 7. Конфигурация (флаги `src/config.py`) + +По образцу ORCH-035/043/059/088 (kill-switch + CSV scope): + +| Флаг | Тип / дефолт | Назначение | +|------|--------------|------------| +| `auto_label_enabled` | `bool = True` (env `ORCH_AUTO_LABEL_ENABLED`) | Глобальный kill-switch обоих авто-режимов. `False` → строго прежнее поведение (оба гейта ручные). | +| `auto_approve_label` | `str = "autoApprove"` | Имя лейбла гейта BRD. | +| `auto_deploy_label` | `str = "autoDeploy"` | Имя лейбла гейта деплоя. | +| `auto_label_repos` | `str = ""` (CSV) | Scope. Пусто → self-hosting only (как ORCH-035/043), либо «все репо» — выбор фиксирует ADR; дефолт безопасный (self-hosting). | +| `auto_label_states_ttl_s` | `int` (опц.) | TTL кэша карты лейблов проекта (образец `plane_states_ttl_s`). | + +**Требование:** при `auto_label_enabled=False` — нулевая регрессия (ни одного нового +сетевого вызова на гейтах, поведение 1:1 как до ORCH-089). + +--- + +## 8. Наблюдаемость + +- Каждый авто-проход → `logger.info` с причиной (label X → действие). +- Telegram-уведомление + обновление live-карточки (ORCH-042/087, never-raise). +- Plane-коммент в задаче (автор — `analyst` для BRD, `deployer` для деплоя — по образцу + существующих комментов гейтов). +- (Опц.) аддитивный блок `auto_labels` в `GET /queue` (enabled, label-имена, scope, + счётчики `auto_approved_total`/`auto_deployed_total`) — образец блоков + `reconcile`/`serial_gate`. + +--- + +## 9. Артефакты pipeline + +Новых обязательных артефактов задачи **нет**. Авто-проходы отражаются в: +- Plane-комментах и Telegram/карточке (прозрачность, BR-7); +- существующих логах деплоя (`14-deploy-log.md` для autoDeploy — пишется Phase C как сейчас). + +Документация golden-source (обязательно в этом же PR): +- `CLAUDE.md` — раздел про авто-режим по лейблам (флаги, инвариант «снимает только + человеческое решение»); +- `docs/architecture/README.md` — описание врезок autoApprove/autoDeploy + флаги; +- `06-adr/ADR-001-*.md` — архитектурное решение (точки врезки, fail-safe, чтение лейблов); +- `07-infra-requirements.md` — создание лейблов `autoApprove`/`autoDeploy` в Plane ORCH; +- `CHANGELOG.md` — `## [Unreleased]`. + +--- + +## 10. Инварианты (что НЕ должно измениться) + +- `STAGE_TRANSITIONS`, реестр `QG_CHECKS`, `check_analysis_approved`, + `check_deploy_status`, `check_staging_status` — без изменений. +- Все технические под-гейты (security/merge-gate/image-freshness/merge-verify/ + regression-guard/post-deploy) — без изменений; авто-режим их не обходит. +- Ручной путь (без лейблов) — 1:1 как сейчас. +- Схема БД, exit-коды deploy-хука, merge-lease, sentinel-маркеры self-deploy — без изменений. +- never-raise: ни одна ошибка авто-режима не роняет конвейер и не пропускает гейт + ошибочно (fail-safe к ручному). +- Self-hosting: авто-режим НЕ рестартит/не роняет прод вне штатного Phase B (который + и так есть); autoDeploy лишь авто-инициирует существующий путь деплоя. diff --git a/docs/work-items/ORCH-089/03-acceptance-criteria.md b/docs/work-items/ORCH-089/03-acceptance-criteria.md new file mode 100644 index 0000000..bb00f91 --- /dev/null +++ b/docs/work-items/ORCH-089/03-acceptance-criteria.md @@ -0,0 +1,153 @@ +# 03 — Критерии приёмки: Авто-режим по лейблам (ORCH-089) + +Каждый критерий — чёткое условие PASS/FAIL. Маппинг на BR (`01-brd.md`) и AC +бизнес-запроса указан в скобках. + +--- + +## AC-1 — autoApprove проходит гейт BRD (BR-1 / BizAC-1) + +**Дано:** задача с лейблом `autoApprove`, analyst успешно завершился (артефакты +BRD/TRZ/AC/test-plan на месте), `auto_label_enabled=True`, репо в scope. +**Когда:** срабатывает `_handle_analysis_approved_flow` (ветка `files_ok`). +**Тогда:** +- задача автоматически переходит `analysis → architecture` без человеческого Approved; +- Plane-статус выставлен в `Approved` (индикация); +- клок `brd_review_ended_at` закрыт (`mark_brd_review_ended`); +- авто-проход залогирован + Telegram/карточка/Plane-коммент уведомляют о факте. + +**PASS:** стадия задачи стала `architecture` без внешнего webhook Approved; клок закрыт. +**FAIL:** задача осталась в `In Review`/`analysis` ИЛИ advance прошёл без индикации/лога. + +--- + +## AC-2 — autoDeploy триггерит прод-деплой (BR-2 / BizAC-2) + +**Дано:** задача с лейблом `autoDeploy` дошла до ребра `deploy-staging → deploy`, +все тех-гейты (security, merge-gate, image-freshness, staging) зелёные, Phase A advance +на `deploy` выполнен, `auto_label_enabled=True`, репо в scope (self-hosting). +**Когда:** срабатывает `_handle_self_deploy_phase_a`. +**Тогда:** +- Phase B (`_handle_self_deploy_phase_b`) инициируется автоматически, без ручного + `Confirm Deploy`; +- маркер `INITIATED` выставлен (идемпотентность), finalizer-job (Phase C) поставлен; +- Plane-статус → `Deploying`; авто-проход залогирован + Telegram/Plane-коммент. + +**PASS:** прод-деплой инициирован без статуса Confirm Deploy от человека; Phase C армлен. +**FAIL:** задача застряла в `Awaiting Deploy`, ожидая ручного Confirm Deploy. + +--- + +## AC-3 — оба лейбла → полная автономность (BR-3 / BizAC-3) + +**Дано:** задача с лейблами `autoApprove` И `autoDeploy`, все тех-гейты по пути зелёные. +**Когда:** задача проходит конвейер `analysis → … → deploy`. +**Тогда:** задача проходит от анализа до прод-деплоя без единого ручного клика +(ни Approved, ни Confirm Deploy). + +**PASS:** ноль человеческих гейт-кликов; задача достигла `deploy`/`done` автономно. +**FAIL:** конвейер остановился хотя бы на одном из двух человеческих гейтов. + +--- + +## AC-4 — без лейблов поведение НЕ меняется (BR-4 / BizAC-4) + +**Дано:** задача без лейблов `autoApprove`/`autoDeploy`. +**Когда:** проходит гейты BRD и деплоя. +**Тогда:** оба гейта остаются ручными — задача ждёт `In Review → Approved` (человек) и +`Awaiting Deploy → Confirm Deploy` (человек), ровно как до ORCH-089. + +**PASS:** на гейте BRD задача в `In Review` ждёт человека; на гейте деплоя — в +`Awaiting Deploy` ждёт человека. Нулевая регрессия. +**FAIL:** задача без лейблов авто-прошла любой гейт. + +--- + +## AC-5 — красный тех-гейт блокирует авто-режим (BR-5 / BizAC-5) + +**Дано:** задача с лейблом `autoDeploy`, но один из тех-гейтов на ребре +`deploy-staging → deploy` красный (например, staging unhealthy / merge-gate конфликт / +security FAIL / image-freshness mismatch). +**Когда:** конвейер достигает ребра деплоя. +**Тогда:** Phase A НЕ достигается (под-гейт завернул задачу) → autoDeploy НЕ +инициирует Phase B; задача откатывается/встаёт ровно как при ручном режиме. + +**PASS:** при красном тех-гейте прод-деплой НЕ инициирован, несмотря на лейбл; поведение +тождественно ручному режиму при том же провале. +**FAIL:** autoDeploy инициировал прод-деплой при красном тех-гейте. + +> Аналогично для autoApprove: при отсутствии артефактов (`check_analysis_complete` FAIL) +> авто-аппрув не срабатывает (нет advance), задача не уходит на architecture. + +--- + +## AC-6 — fail-safe к ручному гейту (BR-6 / BizAC-6) + +**Дано:** одно из: лейбл не распознан; Plane API недоступен при чтении лейблов; +неоднозначное сопоставление имени; исключение в логике авто-режима. +**Когда:** гейт BRD или деплоя. +**Тогда:** авто-режим НЕ срабатывает → откат к ручному гейту (задача ждёт человека); +конвейер НЕ падает. + +**PASS:** при ошибке/неоднозначности задача переходит в ручное ожидание (никогда не +авто-проход по ошибке); ни одно исключение не всплывает наружу (never-raise). +**FAIL:** ошибка чтения лейблов привела к авто-проходу ИЛИ к падению/застреванию конвейера. + +--- + +## AC-7 — прозрачность каждого авто-прохода (BR-7 / BizAC-7) + +**Дано:** любой сработавший авто-проход (autoApprove или autoDeploy). +**Когда:** гейт пройден автоматически. +**Тогда:** факт виден в: (а) логе с причиной (label X → действие); (б) Telegram + +live-карточке задачи; (в) Plane-комменте. + +**PASS:** все три канала несут отметку об авто-проходе и о том, какой лейбл его разрешил. +**FAIL:** авто-проход произошёл «молча» (нет отметки хотя бы в одном из обязательных +каналов: лог + Telegram/карточка + Plane). + +--- + +## AC-8 — kill-switch и scope (BR-9 / BR-10) + +**Дано:** `auto_label_enabled=False` (или репо вне `auto_label_repos`). +**Когда:** задача с лейблами проходит гейты. +**Тогда:** авто-режим полностью отключён — оба гейта ручные, никаких новых сетевых +вызовов на гейтах; поведение 1:1 как до ORCH-089 (включая нулевую регрессию для enduro). + +**PASS:** при выключенном флаге лейблы игнорируются, поведение прежнее. +**FAIL:** при `False` авто-режим сработал ИЛИ появилась регрессия для не-scope репо. + +--- + +## AC-9 — независимость лейблов (BR-3) + +**Дано:** задача только с `autoApprove` (без `autoDeploy`) — и симметрично наоборот. +**Тогда:** +- только `autoApprove`: BRD авто-проходит, деплой ждёт ручного Confirm Deploy; +- только `autoDeploy`: BRD ждёт ручного Approved, деплой авто-проходит. + +**PASS:** каждый лейбл влияет строго на свой гейт, второй гейт остаётся ручным. +**FAIL:** один лейбл повлиял на оба гейта. + +--- + +## AC-10 — инварианты неизменны (TRZ §10) + +**Тогда:** `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_analysis_approved`, +`check_deploy_status`, `check_staging_status`, схема БД, все технические под-гейты, +sentinel-маркеры self-deploy, exit-коды deploy-хука — **не изменены**. + +**PASS:** diff не затрагивает перечисленные контракты; существующие тесты этих +компонентов зелёные. +**FAIL:** любой из инвариантных контрактов изменён. + +--- + +## AC-11 — документация обновлена (CLAUDE.md §правила 2/6) + +**Тогда:** в том же PR обновлены `CLAUDE.md`, `docs/architecture/README.md`, +заведён `06-adr/ADR-001-*`, `07-infra-requirements.md` (создание лейблов), `CHANGELOG.md`. + +**PASS:** документация-golden-source синхронна с кодом. +**FAIL:** функционал изменён, документация — нет (reviewer → REQUEST_CHANGES). diff --git a/docs/work-items/ORCH-089/04-test-plan.yaml b/docs/work-items/ORCH-089/04-test-plan.yaml new file mode 100644 index 0000000..e0597c5 --- /dev/null +++ b/docs/work-items/ORCH-089/04-test-plan.yaml @@ -0,0 +1,172 @@ +work_item: ORCH-089 +title: "Авто-режим по лейблам: autoApprove (авто-BRD) + autoDeploy (авто-деплой)" +description: > + План тестов авто-прохода двух человеческих гейтов по лейблам Plane. + Фокус юнит-тестов — чистая логика src/labels.py (never-raise, fail-safe) и + врезки в stage_engine (autoApprove в _handle_analysis_approved_flow, + autoDeploy в _handle_self_deploy_phase_a). Сеть Plane — мокается. + Инвариант: STAGE_TRANSITIONS/QG_CHECKS/тех-гейты не трогаются. + +tests: + # --- src/labels.py: чистая логика авто-режима (never-raise, fail-safe) ----- + - id: TC-01 + type: unit + description: "has_label возвращает True, когда лейбл присутствует на issue (мок Plane labels)" + module: tests/test_labels.py + expected: PASS + + - id: TC-02 + type: unit + description: "has_label возвращает False, когда лейбла нет на issue" + module: tests/test_labels.py + expected: PASS + + - id: TC-03 + type: unit + description: "has_label при ошибке Plane API / таймауте → fail-safe (нет авто, never-raise)" + module: tests/test_labels.py + expected: PASS + + - id: TC-04 + type: unit + description: "Сопоставление имени лейбла нормализовано (регистр/пробелы); неоднозначность → нет авто" + module: tests/test_labels.py + expected: PASS + + - id: TC-05 + type: unit + description: "auto_approve_applies/auto_deploy_applies: scope CSV + self-hosting; пустой scope по дефолту" + module: tests/test_labels.py + expected: PASS + + - id: TC-06 + type: unit + description: "auto_label_enabled=False → has_label/applies дают 'нет авто' без сетевых вызовов" + module: tests/test_labels.py + expected: PASS + + # --- plane_sync: чтение лейблов + сеттер Approved --------------------------- + - id: TC-07 + type: unit + description: "fetch_issue_labels парсит поле labels issue и резолвит uuid→имя по карте проекта (мок httpx)" + module: tests/test_plane_sync_labels.py + expected: PASS + + - id: TC-08 + type: unit + description: "Карта лейблов проекта кэшируется с TTL (повтор в окне TTL не делает второй GET)" + module: tests/test_plane_sync_labels.py + expected: PASS + + - id: TC-09 + type: unit + description: "set_issue_approved PATCHит issue в Approved-UUID (get_project_states['approved']); never-raise при ошибке" + module: tests/test_plane_sync_labels.py + expected: PASS + + # --- autoApprove: врезка в _handle_analysis_approved_flow ------------------ + - id: TC-10 + type: unit + description: "autoApprove + артефакты готовы → авто-advance analysis→architecture, Approved выставлен, клок brd_review_ended закрыт" + module: tests/test_auto_approve_brd.py + expected: PASS + + - id: TC-11 + type: unit + description: "Без лейбла autoApprove → прежнее поведение: In Review, return без advance (ждёт человека)" + module: tests/test_auto_approve_brd.py + expected: PASS + + - id: TC-12 + type: unit + description: "autoApprove, но артефактов нет (check_analysis_complete FAIL) → НЕ advance (AC-5 для BRD)" + module: tests/test_auto_approve_brd.py + expected: PASS + + - id: TC-13 + type: unit + description: "autoApprove идёт через тот же advance-путь, что ручной Approved (нет дублирования логики; идемпотентно при повторе)" + module: tests/test_auto_approve_brd.py + expected: PASS + + - id: TC-14 + type: unit + description: "autoApprove: авто-проход логируется + Telegram/карточка/Plane-коммент вызваны (прозрачность AC-7)" + module: tests/test_auto_approve_brd.py + expected: PASS + + # --- autoDeploy: врезка в _handle_self_deploy_phase_a ---------------------- + - id: TC-15 + type: unit + description: "autoDeploy + Phase A advance на deploy → автоматически вызывается _handle_self_deploy_phase_b (initiate_deploy)" + module: tests/test_auto_deploy.py + expected: PASS + + - id: TC-16 + type: unit + description: "Без лейбла autoDeploy → прежнее поведение: Awaiting Deploy, ждёт ручного Confirm Deploy" + module: tests/test_auto_deploy.py + expected: PASS + + - id: TC-17 + type: unit + description: "autoDeploy идемпотентен: маркер INITIATED уже стоит → повторный авто-триггер = no-op" + module: tests/test_auto_deploy.py + expected: PASS + + - id: TC-18 + type: unit + description: "autoDeploy не-self репо / вне scope → no-op (Phase A/B существуют только для self-hosting)" + module: tests/test_auto_deploy.py + expected: PASS + + - id: TC-19 + type: unit + description: "autoDeploy: авто-проход логируется + Telegram + Plane-коммент (прозрачность AC-7)" + module: tests/test_auto_deploy.py + expected: PASS + + # --- независимость лейблов + kill-switch ----------------------------------- + - id: TC-20 + type: unit + description: "Только autoApprove (без autoDeploy): BRD авто, деплой ждёт человека (AC-9)" + module: tests/test_auto_label_combinations.py + expected: PASS + + - id: TC-21 + type: unit + description: "Только autoDeploy (без autoApprove): BRD ждёт человека, деплой авто (AC-9)" + module: tests/test_auto_label_combinations.py + expected: PASS + + - id: TC-22 + type: unit + description: "auto_label_enabled=False → оба гейта ручные при наличии обоих лейблов (kill-switch AC-8)" + module: tests/test_auto_label_combinations.py + expected: PASS + + # --- интеграция: сквозной авто-проход на ребрах конвейера ------------------ + - id: TC-23 + type: integration + description: "Оба лейбла + все тех-гейты зелёные → задача проходит analysis→deploy без ручных кликов (AC-3)" + module: tests/test_auto_labels_integration.py + expected: PASS + + - id: TC-24 + type: integration + description: "autoDeploy + красный staging/merge-gate → Phase A не достигнут, Phase B не инициирован (AC-5)" + module: tests/test_auto_labels_integration.py + expected: PASS + + # --- инварианты / регрессия ------------------------------------------------ + - id: TC-25 + type: integration + description: "Регресс: задача без лейблов проходит оба гейта ровно как до ORCH-089 (AC-4)" + module: tests/test_auto_labels_integration.py + expected: PASS + + - id: TC-26 + type: unit + description: "Инвариант: STAGE_TRANSITIONS и реестр QG_CHECKS не изменены ORCH-089 (snapshot-сверка)" + module: tests/test_auto_labels_invariants.py + expected: PASS