From b67a61ecefa5d1bd323e192875762f07c2868e7a Mon Sep 17 00:00:00 2001 From: claude-bot Date: Sun, 7 Jun 2026 18:54:22 +0000 Subject: [PATCH] analyst(ET): auto-commit from analyst run_id=333 --- docs/work-items/ORCH-059/01-brd.md | 115 ++++++++++++++++++ docs/work-items/ORCH-059/02-trz.md | 103 ++++++++++++++++ .../ORCH-059/03-acceptance-criteria.md | 76 ++++++++++++ docs/work-items/ORCH-059/04-test-plan.yaml | 109 +++++++++++++++++ 4 files changed, 403 insertions(+) create mode 100644 docs/work-items/ORCH-059/01-brd.md create mode 100644 docs/work-items/ORCH-059/02-trz.md create mode 100644 docs/work-items/ORCH-059/03-acceptance-criteria.md create mode 100644 docs/work-items/ORCH-059/04-test-plan.yaml diff --git a/docs/work-items/ORCH-059/01-brd.md b/docs/work-items/ORCH-059/01-brd.md new file mode 100644 index 0000000..67dc05f --- /dev/null +++ b/docs/work-items/ORCH-059/01-brd.md @@ -0,0 +1,115 @@ +# 01 — BRD: Approve прод-деплоя через выделенный статус «Confirm Deploy» + +Work Item: **ORCH-059** +Repo: `orchestrator` +Stage: analysis +Тип: enhancement / risk-reduction (self-hosting) + +## 1. Контекст и проблема + +В ORCH-036 («исполняемый самодеплой стадии `deploy`») прод-деплой self-hosting +инстанса (контейнер `orchestrator`, порт 8500) запускается **Фазой B**: человек +переводит issue в Plane-статус **`Approved`**, webhook +`work_item.updated` → `handle_issue_updated` → `handle_verdict(approved=True)` +→ `_try_advance_stage` → `advance_stage(finished_agent=None)`, и в +`stage_engine.advance_stage` срабатывает блок +`current_stage == "deploy" and finished_agent is None` → +`_handle_self_deploy_phase_b` → detached host-деплой прода. + +**Перегрузка статуса.** Тот же самый Plane-статус `Approved` (UUID +`a519a341-…`) используется как **человеческий гейт одобрения BRD** на ранней +стадии `analysis` (`check_analysis_approved`: analysis → architecture) и в общем +verdict-роутинге `handle_verdict`. Один и тот же визуальный «Approved» на доске +означает две принципиально разные вещи: + +- на `analysis` — «BRD/ТЗ/AC приняты, продолжай конвейер» (дёшево, обратимо); +- на `deploy` — «**ВЫКАТИ В ПРОД** инструмент, который прямо сейчас обслуживает + все проекты из одного инстанса с общей БД» (дорого, групповой риск, см. + раздел Self-hosting в `CLAUDE.md`). + +### Последствия (Pain) +- **Двусмысленность семантики.** Один статус — два смысла; оператор не видит из + названия, что клик на `deploy` запускает реальный прод-рестарт. +- **Риск случайного клика.** Привычный жест «Approved» (которым оператор + штатно одобряет BRD десятки раз) на стадии `deploy` молча триггерит + прод-деплой. Цена ошибки — незапланированный рестарт прод-инстанса, + встающий конвейер всех проектов. +- **Несоответствие ожиданиям ORCH-036.** В scope ORCH-36 заявлялась Telegram + inline-кнопка подтверждения; в коде её **нет** — developer реализовал approve + исключительно через Plane-статус. Отдельного «осознанного» жеста подтверждения + деплоя в системе сейчас не существует. + +## 2. Решение Owner + +Ввести **отдельный Plane-статус `Confirm Deploy`** в проекте ORCH, который +триггерит **ТОЛЬКО** Фазу B self-deploy на стадии `deploy`. Статус `Approved` +перестаёт запускать прод-деплой и сохраняет единственный смысл — человеческое +одобрение на гейтах конвейера (прежде всего BRD на `analysis`). + +Минимальная правка: `handle_verdict` в `src/webhooks/plane.py` + регистрация +нового состояния в проекте ORCH (Plane + резолвер состояний). + +## 3. Бизнес-цели +- **BG-1.** Убрать двусмысленность: жест «запустить прод-деплой» отделён от жеста + «одобрить артефакт». +- **BG-2.** Снизить риск случайного прод-деплоя: запуск прода требует явного, + редко используемого статуса `Confirm Deploy`, а не привычного `Approved`. +- **BG-3.** Не сломать работающий self-hosting конвейер при доработке самого + инструмента (нулевая регрессия `analysis`-гейта и не-self репозиториев). + +## 4. Объём (Scope) + +### В объёме +- Новый логический статус `confirm_deploy` («Confirm Deploy») в резолвере + состояний Plane (`src/plane_sync.py`). +- Маршрутизация нового статуса в `src/webhooks/plane.py` + (`handle_issue_updated` / `handle_verdict`) на путь Фазы B прод-деплоя. +- Прекращение триггера Фазы B по статусу `Approved` на стадии `deploy`. +- Обновление текста CTA Фазы A (Plane-комментарий + Telegram в + `stage_engine._handle_self_deploy_phase_a`): инструктировать оператора + переводить задачу в `Confirm Deploy`, а не в `Approved`. +- Конфигурация Plane: создание статуса «Confirm Deploy» в проекте ORCH + (предусловие эксплуатации — фиксируется в TRZ/AC как требование среды). +- Обновление документации (`CLAUDE.md`, `docs/architecture/README.md` секция + ORCH-036, `CHANGELOG.md`) и ADR per-work-item. + +### Вне объёма +- Telegram inline-кнопки подтверждения деплоя (отдельная задача; здесь не + реализуем — управление по-прежнему статусом Plane). +- Полностью автоматический approve деплоя (ORCH-54). +- Изменение Фаз A/C, exit-кодов хука, merge-gate, `check_deploy_status`, + схемы БД, реестров `STAGE_TRANSITIONS` / `QG_CHECKS`. +- Поведение прод-деплоя для не-self репозиториев (остаётся прежним). +- Post-deploy наблюдение (ORCH-021) — не затрагивается. + +## 5. Заинтересованные стороны +- **Owner/оператор** — переводит задачи по статусам; главный выгодоприобретатель + снижения риска. +- **Self-hosting конвейер** — все проекты на общем инстансе; косвенно зависят от + безопасности прод-деплоя орка. + +## 6. Допущения +- A-1. Plane позволяет добавить кастомный статус «Confirm Deploy» в проект ORCH; + его UUID резолвится через `get_project_states` (API `/states/`). +- A-2. Статус `Confirm Deploy` нужен только проекту ORCH (self-hosting). Прочие + проекты прод-деплой через Plane-approve не используют + (`self_deploy_applies` → только `orchestrator`). +- A-3. Оператор переводит задачу в `Confirm Deploy` только когда она реально + находится на стадии `deploy` (approval-pending после Фазы A). + +## 7. Риски (детально — 10-tech-risks.md, ведёт архитектор) +- R-1. Новый логический ключ `confirm_deploy` отсутствует в fallback + `_DEFAULT_STATES` и в проектах без этого статуса → обращение к ключу должно + быть безопасным (fail-closed: нет статуса → нет деплоя, не падение). +- R-2. Регрессия: `Approved` на `deploy` после правки не должен НИ + запускать деплой, НИ вызывать ложный откат/advance. +- R-3. Самоправка прода: правка не должна потребовать ручного рестарта прод- + контейнера вне штатной стадии deploy-staging → deploy. + +## 8. Definition of Done (бизнес-уровень) +- Перевод задачи стадии `deploy` в `Confirm Deploy` запускает прод-деплой + (Фаза B) ровно так же, как раньше делал `Approved`. +- Перевод задачи стадии `deploy` в `Approved` прод-деплой НЕ запускает. +- `Approved` на `analysis` (и прочих человеческих гейтах) работает без изменений. +- CTA Фазы A просит `Confirm Deploy`. +- Документация и ADR обновлены в том же PR. diff --git a/docs/work-items/ORCH-059/02-trz.md b/docs/work-items/ORCH-059/02-trz.md new file mode 100644 index 0000000..2b4f6cb --- /dev/null +++ b/docs/work-items/ORCH-059/02-trz.md @@ -0,0 +1,103 @@ +# 02 — ТЗ: выделенный статус «Confirm Deploy» как триггер прод-деплоя + +Work Item: **ORCH-059** · Repo: `orchestrator` · Stage: analysis + +> ТЗ описывает **что** должно измениться и **поведенческий контракт**. Конкретный +> дизайн (сигнатуры, способ проброса признака «confirm-deploy» из webhook в +> `stage_engine`, sentinel-обработка) — за архитектором (ADR per-work-item). +> Точки касания ниже заданы бизнес-запросом Owner и текущей реализацией ORCH-036. + +## 1. Задействованные модули `src/` + +| Модуль | Роль в задаче | +|--------|---------------| +| `src/plane_sync.py` | Резолвер состояний Plane. Добавить логический ключ `confirm_deploy` ↔ имя статуса «Confirm Deploy»; обеспечить безопасный доступ при отсутствии статуса (fallback/неполный конфиг). | +| `src/webhooks/plane.py` | `handle_issue_updated` — маршрутизация нового статуса; `handle_verdict` — отделить «подтверждение деплоя» от обычного approve; снять триггер Фазы B со статуса `Approved` на `deploy`. | +| `src/stage_engine.py` | Блок Фазы B (`current_stage == "deploy" and finished_agent is None`) должен срабатывать ТОЛЬКО по сигналу confirm-deploy, не по обычному Approved. Обновить CTA-текст Фазы A (`_handle_self_deploy_phase_a`). | +| `src/config.py` | (опционально, на усмотрение архитектора) флаг/имя статуса, если потребуется конфигурируемость. По умолчанию — не требуется. | + +## 2. Поведенческий контракт (требования) + +### TRZ-1. Регистрация статуса «Confirm Deploy» +Резолвер состояний (`get_project_states`) обязан возвращать UUID статуса +«Confirm Deploy» под логическим ключом `confirm_deploy` для проекта ORCH. +Маппинг имени `"Confirm Deploy" → "confirm_deploy"` добавляется в +`_PLANE_NAME_TO_KEY`. Для проектов/сред, где статус отсутствует (enduro, +fallback `_DEFAULT_STATES`, недоступный API), ключ может отсутствовать — +обращение к нему должно быть **fail-closed**: «нет статуса → ветка confirm-deploy +не активируется», без `KeyError`/исключения. + +### TRZ-2. Триггер прод-деплоя по «Confirm Deploy» +Когда задача находится на стадии `deploy` и issue переводится в статус +`Confirm Deploy`, система обязана инициировать **Фазу B** прод-деплоя +(эквивалент текущего `_handle_self_deploy_phase_b`: idempotency-guard `initiated`, +`self_deploy.initiate_deploy`, постановка `deploy-finalizer`, комментарии/Telegram). +Поведение, идемпотентность и Фаза C — **без изменений** относительно ORCH-036; +меняется только **что именно является триггером**. + +### TRZ-3. `Approved` больше не запускает прод-деплой +Перевод задачи стадии `deploy` в статус `Approved` **не должен** инициировать +Фазу B. Он не должен также вызывать ложный откат (БАГ-8) или ложный advance +по `check_deploy_status` (вердикта ещё нет). Допустимое поведение — **no-op с +логированием** (issue остаётся на `deploy`/approval-pending). Конкретный способ +(игнор на уровне webhook-роутинга или на уровне `stage_engine`) — за архитектором. + +### TRZ-4. Сохранность гейта `Approved` на остальных стадиях +Статус `Approved` обязан продолжать работать как человеческий гейт: +- `analysis` → `architecture` (`check_analysis_approved`, approved-via-status); +- любой иной человеческий approve-advance, существующий сегодня. +Регрессия `handle_verdict(approved=True)` для НЕ-`deploy` стадий недопустима. + +### TRZ-5. CTA Фазы A +Текст запроса approve в `_handle_self_deploy_phase_a` (Plane-комментарий + Telegram) +обязан инструктировать оператора переводить задачу в статус **`Confirm Deploy`** +(а не `Approved`) для запуска прод-деплоя. + +### TRZ-6. Условность (как ORCH-35/36) +Ветка confirm-deploy реальна только для self-hosting +(`self_deploy.self_deploy_applies(repo)` → `orchestrator`). Для прочих репо — +прежнее поведение (синхронный деплой агентом), статус `Confirm Deploy` не +требуется и не влияет. + +## 3. Изменения API +Изменений HTTP-эндпоинтов **нет**. Канал — существующий `POST /webhook/plane` +(событие `work_item.updated`). Внешнее изменение: в проекте ORCH появляется +дополнительный статус доски «Confirm Deploy» (Plane-конфигурация, не код-API). + +## 4. Изменения схемы БД +**Нет.** `STAGE_TRANSITIONS`, реестр `QG_CHECKS`, таблицы `tasks`/`jobs`/ +`agent_runs`/`events` — без изменений. Статусы — на стороне Plane; restart-safe +состояние деплоя — существующие sentinel-файлы ORCH-036 (без миграций). + +## 5. Требования к новым QG checks +**Нет.** Новый Quality Gate не вводится. `check_deploy_status` / +`_parse_deploy_status` и контракт exit-кодов хука (0/1/2) — без изменений. + +## 6. Конфигурация среды (предусловие эксплуатации) +- В проекте ORCH в Plane создаётся статус доски **«Confirm Deploy»** (точное имя, + чувствительно к регистру — должно совпасть с ключом `_PLANE_NAME_TO_KEY`). +- Размещение статуса на доске — рядом со стадией deploy/approval-pending + (рекомендация эксплуатации, не код). +- Кэш состояний (`get_project_states` / `reload_project_states`): после создания + статуса может потребоваться сброс кэша или рестарт по штатной стадии deploy. + +## 7. Артефакты, создаваемые/обновляемые по pipeline +- `docs/work-items/ORCH-059/06-adr/ADR-001-confirm-deploy-status.md` — решение + (как отличается триггер; где разрезается перегрузка `Approved`; fail-closed + при отсутствии статуса) — **ведёт архитектор**. +- `CLAUDE.md` — упоминание выделенного статуса approve прод-деплоя (раздел + self-hosting / артефакты). +- `docs/architecture/README.md` — секция ORCH-036: уточнить, что Фаза B + триггерится статусом `Confirm Deploy`, а не `Approved`. +- `CHANGELOG.md` — запись ORCH-059. +- `12-review.md`, `13-test-report.md`, `14-deploy-log.md`, `15-staging-log.md` — + штатно по стадиям конвейера. + +## 8. Совместимость и инварианты +- Не меняются: `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_deploy_status`, + БАГ-8 (FAILED → откат на development), merge-gate, exit-коды хука, Фазы A/C, + схема БД, post-deploy (ORCH-021). +- Self-hosting safety: правка НЕ требует внепланового рестарта прод-контейнера; + выкат — через штатный deploy-staging (8501) → deploy. +- Never-crash: отсутствие статуса `Confirm Deploy` в резолвере не приводит к + исключению в webhook-пути. diff --git a/docs/work-items/ORCH-059/03-acceptance-criteria.md b/docs/work-items/ORCH-059/03-acceptance-criteria.md new file mode 100644 index 0000000..fdd1fb4 --- /dev/null +++ b/docs/work-items/ORCH-059/03-acceptance-criteria.md @@ -0,0 +1,76 @@ +# 03 — Критерии приёмки: ORCH-059 + +Repo: `orchestrator` · Stage: analysis +Каждый критерий — однозначный PASS/FAIL. Проверка: unit/integration (см. +`04-test-plan.yaml`) + ручная верификация для инфра-предусловий. + +## AC-1 — Статус «Confirm Deploy» резолвится +**Given** проект ORCH со статусом доски «Confirm Deploy» +**When** вызывается резолвер состояний для проекта ORCH +**Then** возвращается логический ключ `confirm_deploy` с непустым UUID, +а маппинг `"Confirm Deploy" → "confirm_deploy"` присутствует в `_PLANE_NAME_TO_KEY`. +**FAIL:** ключ отсутствует или указывает на UUID статуса `Approved`. + +## AC-2 — «Confirm Deploy» на стадии `deploy` запускает Фазу B +**Given** задача self-hosting (`orchestrator`) на стадии `deploy`, +`deploy_require_manual_approve=true`, маркер `initiated` отсутствует +**When** приходит `work_item.updated` со статусом `Confirm Deploy` +**Then** инициируется Фаза B: вызывается `self_deploy.initiate_deploy`, +ставится job `deploy-finalizer`, пишется маркер `initiated`. +**FAIL:** прод-деплой не инициирован, либо finalizer не поставлен. + +## AC-3 — «Approved» на стадии `deploy` НЕ запускает прод-деплой +**Given** та же задача на стадии `deploy` +**When** приходит `work_item.updated` со статусом `Approved` +**Then** `self_deploy.initiate_deploy` **НЕ** вызывается; Фаза B не стартует; +задача не откатывается (БАГ-8 не срабатывает) и не «доходит» по +`check_deploy_status` (вердикта нет); событие залогировано как no-op. +**FAIL:** вызван `initiate_deploy`, либо произошёл откат/ложный advance. + +## AC-4 — «Approved» на `analysis` работает без регрессии +**Given** задача на стадии `analysis` (BRD готов, approval-pending) +**When** issue переводится в `Approved` +**Then** срабатывает approved-via-status и задача продвигается +`analysis → architecture` (как до правки). +**FAIL:** approve на analysis перестал продвигать конвейер. + +## AC-5 — Идемпотентность Фазы B по «Confirm Deploy» +**Given** задача на `deploy`, маркер `initiated` уже существует +**When** повторно приходит статус `Confirm Deploy` (двойной клик / дубль webhook) +**Then** повторного `initiate_deploy` не происходит (no-op, +`self-deploy-already-initiated`). +**FAIL:** прод-деплой запускается повторно. + +## AC-6 — CTA Фазы A просит «Confirm Deploy» +**Given** Фаза A (`deploy-staging → deploy`, approval-pending) +**When** формируются Plane-комментарий и Telegram-уведомление запроса approve +**Then** текст инструктирует перевести задачу в статус **`Confirm Deploy`** +(а не «Approved») для запуска прод-деплоя. +**FAIL:** CTA по-прежнему упоминает только «Approved». + +## AC-7 — Fail-closed при отсутствии статуса +**Given** среда без статуса «Confirm Deploy» (enduro / fallback `_DEFAULT_STATES` +/ недоступный Plane API) +**When** обрабатывается `work_item.updated` +**Then** webhook-путь не выбрасывает исключение; ветка confirm-deploy не +активируется (прод-деплой не запускается «вслепую»). +**FAIL:** `KeyError`/исключение в обработчике, либо ложный запуск Фазы B. + +## AC-8 — Условность для не-self репозиториев +**Given** не-self репозиторий (`self_deploy_applies(repo) == False`) +**When** приходит любой verdict-статус на стадии `deploy` +**Then** поведение прод-деплоя не меняется относительно текущего (синхронный +деплой агентом); статус `Confirm Deploy` не требуется. +**FAIL:** изменилось поведение деплоя не-self проекта. + +## AC-9 — Инварианты не нарушены +**Then** `STAGE_TRANSITIONS`, реестр `QG_CHECKS`, `check_deploy_status`/ +`_parse_deploy_status`, контракт exit-кодов хука (0/1/2), Фазы A/C, merge-gate, +схема БД — без изменений; `pytest tests/ -q` зелёный. +**FAIL:** изменён любой из перечисленных контрактов или красные тесты. + +## AC-10 — Документация обновлена (golden source) +**Then** в том же PR обновлены `CLAUDE.md`, секция ORCH-036 в +`docs/architecture/README.md`, `CHANGELOG.md`; заведён +`06-adr/ADR-001-confirm-deploy-status.md`. +**FAIL:** функционал изменён, документация — нет (Reviewer → REQUEST_CHANGES). diff --git a/docs/work-items/ORCH-059/04-test-plan.yaml b/docs/work-items/ORCH-059/04-test-plan.yaml new file mode 100644 index 0000000..97e8daf --- /dev/null +++ b/docs/work-items/ORCH-059/04-test-plan.yaml @@ -0,0 +1,109 @@ +work_item: ORCH-059 +title: Approve прод-деплоя через выделенный статус «Confirm Deploy» +repo: orchestrator +stage: analysis + +# Контракт-тесты: триггер прод-деплоя смещается с перегруженного `Approved` +# на выделенный статус `Confirm Deploy`. Деплой и сетевые вызовы мокаются. +tests: + - id: TC-01 + type: unit + description: "_PLANE_NAME_TO_KEY содержит маппинг 'Confirm Deploy' -> 'confirm_deploy'" + module: tests/test_plane_states.py + expected: PASS + + - id: TC-02 + type: unit + description: >- + get_project_states для проекта ORCH (мок API со статусом 'Confirm Deploy') + возвращает непустой UUID под ключом 'confirm_deploy', отличный от 'approved' + module: tests/test_plane_states.py + expected: PASS + + - id: TC-03 + type: unit + description: >- + Fail-closed: при отсутствии статуса 'Confirm Deploy' (fallback _DEFAULT_STATES / + недоступный API) доступ к ключу confirm_deploy не выбрасывает исключение + и не активирует ветку confirm-deploy + module: tests/test_plane_states.py + expected: PASS + + - id: TC-04 + type: unit + description: >- + handle_issue_updated: статус 'Confirm Deploy' на задаче стадии deploy + маршрутизируется на путь Фазы B (а не на обычный approve/advance) + module: tests/test_plane_confirm_deploy.py + expected: PASS + + - id: TC-05 + type: unit + description: >- + handle_verdict/Approved на стадии deploy НЕ вызывает self_deploy.initiate_deploy + (initiate_deploy замокан и не должен быть вызван) + module: tests/test_plane_confirm_deploy.py + expected: PASS + + - id: TC-06 + type: unit + description: >- + Approved на стадии analysis по-прежнему продвигает analysis -> architecture + (approved-via-status, регрессия гейта check_analysis_approved) + module: tests/test_plane_confirm_deploy.py + expected: PASS + + - id: TC-07 + type: unit + description: >- + stage_engine: блок Фазы B (current_stage==deploy, finished_agent is None) + инициирует deploy ТОЛЬКО по сигналу confirm-deploy; Approved-сигнал -> no-op + module: tests/test_stage_engine_phase_b.py + expected: PASS + + - id: TC-08 + type: unit + description: >- + Идемпотентность: при существующем маркере 'initiated' повторный + Confirm Deploy не вызывает initiate_deploy (self-deploy-already-initiated) + module: tests/test_stage_engine_phase_b.py + expected: PASS + + - id: TC-09 + type: unit + description: >- + CTA Фазы A (_handle_self_deploy_phase_a): текст Plane-комментария и Telegram + содержат 'Confirm Deploy' и не предлагают 'Approved' как триггер деплоя + module: tests/test_stage_engine_phase_a_cta.py + expected: PASS + + - id: TC-10 + type: integration + description: >- + E2E (мок Plane API + self_deploy): задача на deploy -> webhook Confirm Deploy + -> initiate_deploy вызван, deploy-finalizer поставлен, маркер initiated записан + module: tests/test_confirm_deploy_integration.py + expected: PASS + + - id: TC-11 + type: integration + description: >- + E2E: задача на deploy -> webhook Approved -> прод-деплой НЕ инициирован, + задача остаётся на deploy (нет отката, нет advance в done) + module: tests/test_confirm_deploy_integration.py + expected: PASS + + - id: TC-12 + type: integration + description: >- + Условность: для не-self репозитория verdict-статусы на deploy не меняют + поведение деплоя (self_deploy_applies == False) + module: tests/test_confirm_deploy_integration.py + expected: PASS + +regression: + - id: RG-01 + type: integration + description: "pytest tests/ -q зелёный; STAGE_TRANSITIONS и QG_CHECKS без изменений" + module: tests/ + expected: PASS