analyst(ET): auto-commit from analyst run_id=441
This commit is contained in:
123
docs/work-items/ORCH-089/01-brd.md
Normal file
123
docs/work-items/ORCH-089/01-brd.md
Normal file
@@ -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) — точки врезки авто-деплоя.
|
||||
210
docs/work-items/ORCH-089/02-trz.md
Normal file
210
docs/work-items/ORCH-089/02-trz.md
Normal file
@@ -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": <approved_uuid>}` | Индикация авто-аппрува 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 лишь авто-инициирует существующий путь деплоя.
|
||||
153
docs/work-items/ORCH-089/03-acceptance-criteria.md
Normal file
153
docs/work-items/ORCH-089/03-acceptance-criteria.md
Normal file
@@ -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).
|
||||
172
docs/work-items/ORCH-089/04-test-plan.yaml
Normal file
172
docs/work-items/ORCH-089/04-test-plan.yaml
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user