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