# 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 лишь авто-инициирует существующий путь деплоя.