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

179 lines
13 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 — Техническое задание (ТЗ)
**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` — без регресса.