Files
orchestrator/docs/work-items/ORCH-089/02-trz.md

211 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`, ~стр. 584599):
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 лишь авто-инициирует существующий путь деплоя.