From 62a63ba0c6289d7d6ce3ca89a1240c62ffa796fa Mon Sep 17 00:00:00 2001 From: claude-bot Date: Wed, 10 Jun 2026 03:25:36 +0300 Subject: [PATCH] architect(ET): auto-commit from architect run_id=558 --- docs/architecture/README.md | 37 +++ .../adr/adr-0032-bug-fast-track.md | 95 +++++++ docs/architecture/internals.md | 11 + .../ORCH-019/06-adr/ADR-001-bug-fast-track.md | 231 ++++++++++++++++++ .../ORCH-019/07-infra-requirements.md | 62 +++++ .../ORCH-019/08-data-requirements.md | 64 +++++ docs/work-items/ORCH-019/10-tech-risks.md | 39 +++ 7 files changed, 539 insertions(+) create mode 100644 docs/architecture/adr/adr-0032-bug-fast-track.md create mode 100644 docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md create mode 100644 docs/work-items/ORCH-019/07-infra-requirements.md create mode 100644 docs/work-items/ORCH-019/08-data-requirements.md create mode 100644 docs/work-items/ORCH-019/10-tech-risks.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 3fa4d14..c3d4d73 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -373,6 +373,43 @@ Phase A ждёт ручного `Confirm Deploy`, ORCH-059). ORCH-089 снима `docs/work-items/ORCH-089/06-adr/ADR-001-auto-label-gates.md`, `docs/work-items/ORCH-089/07-infra-requirements.md`. +### Багфикс-трек: укороченный маршрут для багов (ORCH-019 — design) +Задача с меткой Plane `Bug` идёт по **укороченному** маршруту `analysis(lite) → development → +review → testing → deploy-staging → deploy → done`, **минуя стадию `architecture`** (отдельный +прогон opus-агента `architect` + ADR + exit-гейт `check_architecture_done`). **Корневой инвариант +(NFR-1):** срезается ТОЛЬКО аналитика/архитектура; ни один Quality Gate / под-гейт +(security/merge/coverage/image-freshness) / вердикт-ключ — НЕ ослаблен (урок ET-8). Аддитивно, под +kill-switch, per-repo, never-raise, fail-safe → полный цикл; `STAGE_TRANSITIONS`/`QG_CHECKS`/ +`check_*` — **не трогаются**. +- **Багфикс-трек = свойство планировщика/точки входа, НЕ Quality Gate.** Классификация — + leaf `src/bug_fast_track.py` (never-raise, образец `serial_gate`/`labels`): метка `Bug` + читается аппаратом ORCH-089 (`labels.has_label` + `plane_sync.fetch_issue_labels`), задача + помечается `track='bug'`. `applies(repo)` (локально, без сети) — ПЕРВЫМ; `has_label` (сеть) — + только при `applies==True`; чтение метки **только** в `start_pipeline`, никогда в горячем + `claim_next_job` (NFR-4 anti-stall). +- **Хранение типа** — аддитивная колонка `tasks.track TEXT DEFAULT 'full'` (`_ensure_column`, + паттерн `tasks.cancelled_at` ORCH-090); читается в `advance_stage` из БД, не из сети. +- **Routing-override** — `STAGE_TRANSITIONS`/`get_next_stage`/`get_agent_for_stage` остаются + чистыми (1:1). В `advance_stage` на ребре выхода из `analysis` при `track='bug'`: `next_stage` + → `development` (вместо `architecture`), `next_agent` → `developer` (вместо `architect`). +- **Гейт `analysis` не трогаем** — `check_analysis_complete`/`check_analysis_approved` байт-в-байт; + lite-аналитик эмитит все 4 файла (01-bug-report / 02-03 краткие заглушки / 04 план обязательного + регресс-теста, BR-4). Экономия — пропуск всей стадии `architecture`, не число файлов. +- **Эскалация** (обратимость BR-5) — `POST /bug-fast-track/escalate?work_item=` сбрасывает + `track→'full'` (+ self-escalate мини-аналитика) → задача идёт через `architecture`. +- **Флаги** (`config.py`): `bug_fast_track_enabled` (kill-switch), `bug_fast_track_label` + (дефолт `Bug`), `bug_fast_track_repos` (CSV; **пусто → self-hosting only**). `False`/неприменимый + репо → путь старта и маршрут **байт-в-байт** прежние (нулевая регрессия для enduro и orchestrator). +- **Наблюдаемость (AC-7):** read-only блок `bug_fast_track` в `GET /queue` (флаг/область/метка + + счётчик `track='bug'` + метрика экономии стадий/agent-runs/токенов/времени из `agent_runs`); лог + на решение о маршруте; опц. `🐞` в Telegram-карточке. +- **Инфра-предусловие:** создать метку `Bug` в Plane-проекте ORCH; её отсутствие = `has_label` + False = полный цикл (fail-safe). + +Подробнее: [adr-0032](adr/adr-0032-bug-fast-track.md), детально — +`docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md`, +`docs/work-items/ORCH-019/08-data-requirements.md`. + ### STOP / отмена задачи: терминал `cancelled` + закрытие дыры релонча (ORCH-090 — реализовано) До ORCH-090 не было штатного способа отменить задачу (ручная хирургия по БД/процессам) и diff --git a/docs/architecture/adr/adr-0032-bug-fast-track.md b/docs/architecture/adr/adr-0032-bug-fast-track.md new file mode 100644 index 0000000..a134942 --- /dev/null +++ b/docs/architecture/adr/adr-0032-bug-fast-track.md @@ -0,0 +1,95 @@ +--- +work_item: ORCH-019 +stage: architecture +author_agent: architect +status: proposed +created_at: 2026-06-10 +model_used: claude-opus-4-8 +--- + +# adr-0032: Багфикс-трек — укороченный маршрут конвейера для багов (ORCH-019) + +## Статус +Proposed + +## Контекст + +Любая задача идёт по полному конвейеру `analysis → architecture → development → review → testing +→ deploy-staging → deploy → done`. Для мелкого бага стадия `architecture` (отдельный прогон +opus-агента `architect` + ADR + exit-гейт `check_architecture_done`) избыточна и тратит +токены/время (прецедент ET-9/ET-014 ~35 мин). + +**Корневой инвариант (нерушимый):** упрощаем только *аналитику/архитектуру*; ни один Quality +Gate / под-гейт (security/merge/coverage/image-freshness) / exit-код deploy-хука — НЕ ослаблен +(урок ET-8: срезанная проверка = недоделка на проде). + +Кросс-каттинговость: затрагивает семантику маршрутизации (`advance_stage`), вводит новый +leaf-компонент `src/bug_fast_track.py` и аддитивную колонку `tasks.track` → регистрируется +сквозным ADR. + +## Решение + +Багфикс-трек — **свойство планировщика/точки входа, НЕ Quality Gate**. + +1. **Классификация** (`src/bug_fast_track.py`, leaf never-raise по образцу `serial_gate`/`labels`): + задача с меткой Plane `Bug` (`bug_fast_track_label`, читается аппаратом ORCH-089 + `labels.has_label`) помечается `track='bug'`. `applies(repo)` (локально, без сети) — первым; + `has_label` (сеть) — только при `applies==True`; чтение метки **только** в `start_pipeline`, + никогда в горячем `claim_next_job` (anti-stall). + +2. **Хранение** — аддитивная идемпотентная колонка `tasks.track TEXT DEFAULT 'full'` + (`_ensure_column`, паттерн `tasks.cancelled_at` ORCH-090); читается в `advance_stage` из БД + (не из сети). + +3. **Routing-override** — `STAGE_TRANSITIONS` и `get_next_stage`/`get_agent_for_stage` остаются + **чистыми** (1:1). В `advance_stage`, на ребре выхода из `analysis`, при `track='bug'`: + `next_stage` → `development` (вместо `architecture`), `next_agent` → `developer` (вместо + `architect`). Багфикс физически минует стадию `architecture` → её exit-гейт + `check_architecture_done` и `06-adr/` для багфикса не исполняются. + +4. **Гейт `analysis` не трогаем** — `check_analysis_complete`/`check_analysis_approved` байт-в-байт + прежние; lite-аналитик эмитит все 4 файла (01-bug-report / 02-03 краткие заглушки / 04 план + обязательного регресс-теста). Экономия — пропуск всей стадии `architecture`, не число файлов. + +5. **Эскалация** (обратимость) — `POST /bug-fast-track/escalate?work_item=` сбрасывает + `track→'full'` (+ self-escalate мини-аналитика); задача далее идёт через `architecture`. + +6. **Условность/откат** — `bug_fast_track_enabled` (kill-switch), `bug_fast_track_label`, + `bug_fast_track_repos` (CSV; **пусто → self-hosting only**). `False`/неприменимый репо → + путь старта и маршрут **байт-в-байт** прежние. + +7. **Наблюдаемость** — read-only блок `bug_fast_track` в `GET /queue` (флаг/область/метка + + счётчик `track='bug'` + метрика экономии из `agent_runs`); лог на решение о маршруте; опц. + `🐞` в Telegram-карточке. + +## Кросс-каттинговые инварианты (НЕ нарушаются) + +- `STAGE_TRANSITIONS` структурно не меняется (нет новых/удалённых стадий); `cancelled`/`done` + стоки и предикаты терминальности (ORCH-090) не затронуты. +- Реестр `QG_CHECKS`, сигнатуры `check_*`, вердикт-ключи (`verdict:`/`result:`/`deploy_status:`/ + `staging_status:`/`security_status:`/`coverage_status:`), порядок под-гейтов — байт-в-байт. +- Врезка ORCH-019 в `advance_stage` — ТОЛЬКО на ребре выхода из `analysis`, ДО всех deploy-edge + под-гейтов (ORCH-022/043/027/058) и Phase A/B (ORCH-036/059) → их инварианты сохранены. +- Композиция с serial-gate (ORCH-088), auto-label (ORCH-089), coverage-gate (ORCH-027), + merge-gate (ORCH-043) — багфикс-задача остаётся обычной задачей репо. + +## Последствия + +- **+** Багфикс минует стадию `architecture` (основная экономия), гейты качества сохранены. +- **+** Аддитивно, под kill-switch, per-repo, never-raise, fail-safe → полный цикл; нулевая + регрессия для enduro и orchestrator при выключении. +- **−** lite-аналитик эмитит 02/03 заглушки (компромисс ради неизменности гейта); эскалация v1 + требует операторского действия (авто-триаж сложности — будущее, ORCH-13/Вариант 3). +- **Откат:** `bug_fast_track_enabled=False` (мгновенно); колонка `tasks.track` аддитивна и + безвредна (дефолт `'full'`). + +## Связанные решения +- ORCH-089 (auto-label) — переиспользуемый аппарат label-чтения: [adr-0018](adr-0018-auto-label-gates.md) +- ORCH-088 (serial gate) — композиция очереди репо +- ORCH-027 (coverage-gate) — структурный союзник BR-4: [adr-0029](adr-0029-coverage-gate.md) +- ORCH-090 (cancelled) — паттерн аддитивной колонки `tasks.*`: [adr-0026](adr-0026-stop-cancel-task.md) + +## Ссылки +- Детальный ADR задачи: `docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md` +- BRD/TRZ/AC: `docs/work-items/ORCH-019/01-brd.md`, `02-trz.md`, `03-acceptance-criteria.md` + diff --git a/docs/architecture/internals.md b/docs/architecture/internals.md index d68e62e..ec4efcb 100644 --- a/docs/architecture/internals.md +++ b/docs/architecture/internals.md @@ -106,6 +106,17 @@ claude.exe --print --system-prompt --allowedTools Read,Write,Edit,Bash Примечание: переход `review → testing` использует `check_reviewer_verdict` (читается из frontmatter `12-review.md`); `development → review` — `check_tests_local` (оркестратор сам прогоняет тесты, не зависит от Gitea CI). +**Багфикс-трек: routing-override на ребре выхода из `analysis` (ORCH-019 — design).** Для задачи +с `tasks.track='bug'` (помечена в `start_pipeline` по метке Plane `Bug` через аппарат ORCH-089) +`advance_stage` на шаге 3 переопределяет результат `get_next_stage('analysis')`: `next_stage` → +`development` (вместо `architecture`), а на шаге 4 `next_agent` → `developer` (вместо `architect`) +→ стадия `architecture` и её exit-гейт `check_architecture_done` для багфикса не исполняются. +`STAGE_TRANSITIONS`/`get_next_stage`/`get_agent_for_stage` остаются чистыми (1:1) — override живёт +только в `advance_stage`. Чистый предикат `bug_fast_track.skips_architecture(track)` (leaf +`src/bug_fast_track.py`, never-raise) под `bug_fast_track_enabled`; `track` читается из БД, не из +сети (NFR-4). `False`/неприменимый репо → маршрут байт-в-байт прежний. Детали — +[adr-0032](adr/adr-0032-bug-fast-track.md). + ### 6. Review Bounce При REQUEST_CHANGES: diff --git a/docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md b/docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md new file mode 100644 index 0000000..633f0bb --- /dev/null +++ b/docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md @@ -0,0 +1,231 @@ +--- +work_item: ORCH-019 +stage: architecture +author_agent: architect +status: proposed +created_at: 2026-06-10 +model_used: claude-opus-4-8 +--- + +# ADR-001: Багфикс-трек — пропуск стадии `architecture` через track-aware routing override + +Work Item: **ORCH-019** — упрощённый/дешёвый трек для багов (укороченный маршрут конвейера) +Стадия: **architecture** +Сквозная регистрация: **`docs/architecture/adr/adr-0032-bug-fast-track.md`** (решение +кросс-каттинговое: новый leaf-компонент + аддитивная колонка `tasks.track` + семантика +маршрутизации, затрагивающая `advance_stage`). + +## Статус +Proposed + +## Контекст + +Любая задача входит в конвейер через `webhooks/plane.py::start_pipeline`, который +**жёстко** создаёт task-row со стадией `"analysis"` (`create_task_atomic(..., "analysis", ...)`) +и режет ветку. Маршрут стадий полностью управляется `src/stages.py::STAGE_TRANSITIONS` через +`get_next_stage` — `advance_stage` (`src/stage_engine.py`) НЕ зашивает порядок, а спрашивает +`get_next_stage(current_stage)` (строка 214) и `get_agent_for_stage(current_stage)` (строка 464). + +Для мелкого бага полный цикл `analysis → architecture → development → …` избыточен: стадия +`architecture` = отдельный прогон агента `architect` (opus, дорогой) + ADR + exit-гейт +`check_architecture_done`. Прецедент: UI z-index баг ET-9/ET-014 прошёл полный цикл ~35 мин. + +**Корневой инвариант (NFR-1 BRD, нерушимый):** упрощаем только *аналитику/архитектуру*; ни один +Quality Gate / exit-код deploy-хука / под-гейт (security/merge/coverage/image-freshness) — НЕ +ослаблен. Горький урок ET-8: срезанная *проверка* = недоделка на проде. + +**Факты, сверенные с кодом:** +- `src/labels.py::has_label` + `plane_sync.fetch_issue_labels`/`get_project_labels` (ORCH-089) — + готовый, проверенный аппарат чтения метки Plane (TTL-кэш, нормализация, never-raise, + fail-safe → False, источник истины Plane API, не payload). +- `advance_stage` маршрутизирует через `get_next_stage`/`get_agent_for_stage` → точка ветвления + локализуема, `STAGE_TRANSITIONS` ломать не нужно. +- `check_analysis_approved` (exit-гейт `analysis`) вызывает `check_analysis_complete`, требующий + **01/02/03/04** (`src/qg/checks.py:33`). Это и есть точка риска ложной блокировки облегчённого + пакета (FR-6). +- `_ensure_column` (`src/db.py:334`) — идемпотентная аддитивная миграция (паттерн + `tasks.cancelled_at`, ORCH-090). + +## Решение + +### Сводка + +Багфикс-трек — **свойство планировщика/точки входа, не Quality Gate**. Задача с меткой Plane +`Bug` помечается в БД как `track='bug'`; на ребре выхода из `analysis` `advance_stage` применяет +**чистый routing-override**: `next_stage` → `development` (вместо `architecture`), `next_agent` +→ `developer` (вместо `architect`). `STAGE_TRANSITIONS`, реестр `QG_CHECKS`, все `check_*` и +вердикт-ключи — **байт-в-байт прежние**. Распознавание, маршрут и метрика — аддитивно, под +kill-switch, с областью репо, never-raise, fail-safe → полный цикл. + +### D1 — Классификация: метка Plane `Bug`, читаемая в `start_pipeline` (FR-1, AC-1) + +Новый leaf `src/bug_fast_track.py` (пустой импорт-граф как `serial_gate`/`labels`: только +`config`, лениво `labels`/`plane_sync`/`qg.checks`), never-raise. Публичные функции: +- `bug_fast_track_applies(repo) -> bool` — локальный, без сети, по образцу `_auto_label_applies`: + `bug_fast_track_enabled=False` → `False`; `bug_fast_track_repos` (CSV) непустой → только + перечисленные репо; **пусто → self-hosting only** (`is_self_hosting_repo`, см. D6). Проверяется + **ПЕРВЫМ** → при выключенном флаге нулевой сетевой оверхед, enduro не затронут. +- `is_bug_task(work_item_id, project_id) -> bool` — `bug_fast_track_applies` уже проверен + вызывающим; делегирует в `labels.has_label(work_item_id, settings.bug_fast_track_label, + project_id)` (дефолт метки `Bug`). Любая ошибка/неоднозначность → `False` (fail-safe → полный + цикл). + +Чтение метки — **только** в `start_pipeline` (момент старта, сетевой вызов приемлем, как +ORCH-089), **никогда** в горячем `claim_next_job` (NFR-4). + +### D2 — Хранение типа: аддитивная колонка `tasks.track` (OQ-2, NFR-4) + +Идемпотентная миграция `_ensure_column(conn, "tasks", "track", "TEXT DEFAULT 'full'")` рядом с +`tasks.cancelled_at`/`cancel_requested_at` (`src/db.py` init). Значения: `'full'` (дефолт, ВСЕ +существующие и не-баг задачи) | `'bug'`. Хелперы: `db.set_task_track(task_id, track)` (запись), +`db.get_task_track(task_id) -> str` (чтение, дефолт `'full'`). Тип читается из **БД** в +`advance_stage` (NFR-4: горячий путь без сети). Альтернатива «выводить тип повторным чтением +метки» отвергнута — повторный сетевой вызов в горячем пути запрещён. + +`create_task_atomic` НЕ меняет сигнатуру: задача создаётся как `'full'` (DEFAULT), затем +`start_pipeline` после успешного `created=True` при `is_bug_task` вызывает +`db.set_task_track(task_id, 'bug')`. Точка входа стадии остаётся `"analysis"` (мини-анализ +сохраняется, OQ-3/BRD §6 — НЕ чистый hotfix). + +### D3 — Routing-override: пропуск `architecture` без правки `STAGE_TRANSITIONS` (FR-2, AC-2) + +`get_next_stage`/`get_agent_for_stage` остаются **чистыми** (принимают только стадию, 1:1). +Override живёт в `advance_stage`, сразу после строки `next_stage = get_next_stage(current_stage)`: + +```python +next_stage = get_next_stage(current_stage) +# ORCH-019: bug-fast-track skips the architecture stage entirely. +if current_stage == "analysis" and bug_fast_track.skips_architecture(track): + next_stage = "development" +``` + +и при запуске следующего агента (строка 464): + +```python +next_agent = get_agent_for_stage(current_stage) # "analysis" -> "architect" +if current_stage == "analysis" and next_stage == "development": + next_agent = "developer" # skip architect run +``` + +`track` читается один раз в начале `advance_stage` (`db.get_task_track(task_id)`). Чистый +предикат `bug_fast_track.skips_architecture(track) -> bool` (== `track == 'bug'` под +`bug_fast_track_enabled`; иначе `False`). Багфикс-задача физически НЕ попадает в стадию +`architecture` → её exit-гейт `check_architecture_done` и требование `06-adr/` не исполняются для +багфикса. Для не-баг задач (`track='full'`) поведение **байт-в-байт** прежнее. + +**Сопутствующая правка телеметрии:** строка 386 стампит `mark_brd_review_ended` при +`analysis → architecture`. Для багфикса next_stage = `development`, поэтому условие расширяется до +`current_stage == "analysis" and next_stage in ("architecture", "development")` — чтобы метрика +«твоё время» (ORCH-087) оставалась честной на багфикс-треке. Не влияет на гейты. + +### D4 — Quality Gate `analysis`: НЕ трогаем; lite-пакет эмитит все 4 файла (FR-3/FR-6, OQ-6, AC-3) + +**Корневой инвариант диктует минимальную поверхность изменения гейтов = ноль.** +`check_analysis_complete` (требует 01/02/03/04) и `check_analysis_approved` остаются **байт-в-байт +прежними**. Багфикс-аналитик (`analyst.md` lite-режим) всё равно эмитит **все 4** файла, но в +облегчённой багфикс-форме: `01-brd.md` = короткий bug-report (симптом / шаги воспроизведения / +локализация / причина), `02-trz.md` + `03-acceptance-criteria.md` = краткие bug-shaped заглушки, +`04-test-plan.yaml` = план **обязательного регресс-теста** (красный до фикса, зелёный после). + +Обоснование выбора: доминирующая экономия — пропуск **всей стадии `architecture`** (отдельный +прогон opus-агента `architect` + ADR), а не число файлов analysis (они эмитятся в ОДНОМ прогоне +analyst-агента). Сохранение 4-файлового гейта = **сильнейшая** позиция NFR-1 (нулевая поверхность +правок гейта) ценой почти нулевого оверхеда. Альтернатива «track-aware `check_analysis_complete` +(для bug требовать только 01/04)» рассмотрена и отвергнута для v1 (D-Alt) — она трогает `check_*` +и расширяет поверхность риска без существенной экономии. + +### D5 — Эскалация в полный цикл (FR-5, AC-5) + +Два пути возврата сложного/архитектурного/визуального бага в полный цикл, оба сбрасывают +`track='bug'` → `'full'` (после чего `advance_stage` маршрутизирует `analysis → architecture` +штатно): +1. **Операторский (ручной, v1-дефолт):** админ-эндпоинт `POST /bug-fast-track/escalate?work_item=` + (по образцу `POST /serial-gate/unfreeze`, `POST /coverage/baseline`) — `db.set_task_track(..., + 'full')`, лог + Telegram + Plane-коммент, never-raise. Применять, пока задача в `analysis` + (до выхода) — тогда следующий переход уйдёт в `architecture`. +2. **Решение мини-аналитика:** если на багфикс-треке аналитик определяет, что баг архитектурный, + он эмитит **полный** analysis-пакет (включая запрос на `06-adr/`) и помечает в bug-report + `escalate: full-cycle` — оператор подтверждает эскалацию эндпоинтом (1). v1 НЕ включает + автоматический LLM-авто-триаж сложности (вне объёма, BRD §2.2). + +Эскалация обратима, детерминирована, наблюдаема. Багфикс-задача не «застревает» без архитектуры. + +### D6 — Область по умолчанию: self-hosting only (OQ-5, NFR-5) + +Пустой `bug_fast_track_repos` → **self-hosting only** (`is_self_hosting_repo`, как +ORCH-089/027/058). Это безопасный дефолт: режим обкатывается на самом орке (где метка `Bug` +гарантированно заводится оператором), enduro подключается явным добавлением в CSV. Флаги +(`config.py`): `bug_fast_track_enabled` (kill-switch, env `ORCH_BUG_FAST_TRACK_ENABLED`), +`bug_fast_track_label` (дефолт `Bug`, env `ORCH_BUG_FAST_TRACK_LABEL`), `bug_fast_track_repos` +(CSV, env `ORCH_BUG_FAST_TRACK_REPOS`). + +### D7 — Наблюдаемость стоимости (FR-7, AC-7) + +- **`GET /queue`** — аддитивный read-only блок `bug_fast_track` (`bug_fast_track.snapshot()`, + never-raise, по образцу `serial_gate`/`auto_labels`/`coverage`): `enabled`, `repos`, `label`, + счётчик задач с `track='bug'`, агрегатная метрика экономии (пропущенные стадии / Σ agent-runs / + токены / время багфикс-трека против среднего полного цикла из существующей телеметрии + `agent_runs`). Существующие ключи `GET /queue` не меняются. +- **Лог-строка** на решение о маршруте (`analysis → development (bug-fast-track)`). +- **Опц.** отметка `🐞 багфикс-трек` в Telegram-карточке (`notifications.py`, never-raise). + +### D8 — Композиция (NFR-7, AC-9) + +- **serial-gate (ORCH-088):** багфикс-задача — обычная задача репо, учитывается в serial-очереди + как есть (FIFO `t2.id < jobs.task_id`); точка входа `analysis` не меняется, defer-branch логика + не затронута. Маркированный код `serial_gate.py` НЕ правится. +- **auto-label (ORCH-089):** `autoApprove`/`autoDeploy` работают на багфикс-треке — autoApprove + врезка в `_handle_analysis_approved_flow` вызывает `advance_stage(finished_agent=None)`, который + применяет D3-override и уходит в `development`. Переиспользуем `labels.has_label`. +- **coverage-gate (ORCH-027):** союзник BR-4 (структурно ловит «код без теста») — исполняется + штатно на ребре `deploy-staging → deploy`. +- **merge-gate (ORCH-043):** не затронут. + +Правки маркированного кода (`advance_stage` несёт врезки ORCH-088/089/027/059/094) — точечные, +со сверкой их `06-adr/`; зафиксированные инварианты (порядок под-гейтов, merge-lease, +terminal-sync) НЕ нарушаются: ORCH-019 добавляет ветвление ТОЛЬКО на ребре выхода из `analysis`, +до всех deploy-edge под-гейтов. + +## Альтернативы + +- **Track-aware `get_next_stage(stage, task)` / новая стадия в `STAGE_TRANSITIONS`** — отвергнуто: + ломает чистоту `stages.py` и риск задеть структуру таблицы (AC-2 FAIL при структурном изменении). + Override в `advance_stage` локальнее и держит `STAGE_TRANSITIONS` неизменным. +- **Track-aware `check_analysis_complete` (bug → только 01/04)** — отвергнуто для v1 (D-Alt): + трогает `check_*`, расширяет поверхность риска NFR-1 ради почти нулевой экономии (см. D4). + Оставлено как возможное будущее уточнение, если потребуется реальный отказ от 02/03. +- **Чистый hotfix `start_pipeline → development`, минуя `analysis`** — отвергнуто как дефолт + (BRD §6): теряется фиксация регресс-теста как контракта приёмки и трассируемость (урок ET-8). +- **Тип задачи из payload вебхука / повторное чтение метки в `claim_next_job`** — отвергнуто: + payload не несёт `type` (источник истины — Plane API); сеть в горячем claim запрещена (NFR-4). +- **Чтение типа без БД-колонки** — отвергнуто: потребовало бы сетевого вызова в горячем пути. + +## Последствия + +- **+** Багфикс минует целую стадию `architecture` (один прогон opus-агента `architect` + ADR) — + основная экономия токенов/времени; гейты качества **байт-в-байт** сохранены. +- **+** Полностью аддитивно: kill-switch `False` или неприменимый репо → путь старта и маршрут + идентичны текущим (AC-6, нулевая регрессия для enduro и orchestrator). +- **+** Переиспользует проверенный аппарат ORCH-089 (label-чтение) и паттерн leaf+флаги+snapshot. +- **−** Багфикс-аналитик всё равно эмитит 02/03 (краткие заглушки) ради неизменности гейта — + принятый компромисс (D4); экономия на их содержании, не на их наличии. +- **−** Эскалация v1 требует операторского действия (эндпоинт) — авто-триаж сложности отложен + (BRD §2.2). Митигатор: путь эскалации документирован, обратим, наблюдаем (D5). +- **Откат:** `bug_fast_track_enabled=False` (мгновенно, 1:1 прежнее поведение); колонка + `tasks.track` остаётся (аддитивна, дефолт `'full'`, безвредна). Полный откат — revert PR; + миграция идемпотентна, остаточная колонка не мешает. + +## Ссылки +- BRD: `docs/work-items/ORCH-019/01-brd.md` +- TRZ: `docs/work-items/ORCH-019/02-trz.md` +- Acceptance: `docs/work-items/ORCH-019/03-acceptance-criteria.md` +- Сквозной ADR: `docs/architecture/adr/adr-0032-bug-fast-track.md` +- Data: `docs/work-items/ORCH-019/08-data-requirements.md` +- Infra: `docs/work-items/ORCH-019/07-infra-requirements.md` +- Риски: `docs/work-items/ORCH-019/10-tech-risks.md` +- Сверено по коду: `src/stages.py`, `src/stage_engine.py` (advance_stage:175-477), + `src/webhooks/plane.py::start_pipeline` (505-684), `src/labels.py`, + `src/qg/checks.py` (check_analysis_complete:33, check_analysis_approved:286, + check_architecture_done:62), `src/db.py` (_ensure_column:334, create_task_atomic:433) + + diff --git a/docs/work-items/ORCH-019/07-infra-requirements.md b/docs/work-items/ORCH-019/07-infra-requirements.md new file mode 100644 index 0000000..9d0fe52 --- /dev/null +++ b/docs/work-items/ORCH-019/07-infra-requirements.md @@ -0,0 +1,62 @@ +--- +work_item: ORCH-019 +stage: architecture +author_agent: architect +status: proposed +created_at: 2026-06-10 +model_used: claude-opus-4-8 +--- + +# 07 — Инфраструктурные требования (Infra Requirements): ORCH-019 — Багфикс-трек + +Work Item: **ORCH-019** · Repo: **orchestrator** · Стадия: architecture + +> **Топология не меняется.** Один прод-контейнер `orchestrator` (8500) + staging (8501) на mva154, +> общая SQLite-БД. ORCH-019 — чисто прикладное изменение под флагом. Этот документ фиксирует +> **предусловия включения** (Plane-метка + env-флаги), не новую инфраструктуру. + +--- + +## 1. Предусловие: метка `Bug` в Plane-проекте (блокирующее для активации) + +Багфикс-трек активируется по метке Plane с именем `bug_fast_track_label` (дефолт `Bug`), +читаемой аппаратом ORCH-089 (`fetch_issue_labels`/`get_project_labels`). **Метка должна +существовать** в Plane-проекте orchestrator (и в любом проекте, добавленном в +`bug_fast_track_repos`). + +- Её **отсутствие = fail-safe полный цикл** (`has_label → False`), не сбой. Включение флага без + заведённой метки безопасно, но эффекта не даёт. +- Создаётся оператором в Plane вручную (как `autoApprove`/`autoDeploy` для ORCH-089). + +## 2. Конфигурация (env-флаги, `src/config.py`) + +| Флаг | Env | Дефолт | Назначение | +|------|-----|--------|-----------| +| `bug_fast_track_enabled` | `ORCH_BUG_FAST_TRACK_ENABLED` | `False` | kill-switch; `False` → путь старта/маршрут строго прежние (нулевая регрессия) | +| `bug_fast_track_label` | `ORCH_BUG_FAST_TRACK_LABEL` | `Bug` | имя метки Plane для распознавания бага | +| `bug_fast_track_repos` | `ORCH_BUG_FAST_TRACK_REPOS` | `""` (пусто) | CSV-область; пусто → **self-hosting only** (`orchestrator`) | + +> Рекомендация выката: `enabled=False` до момента, когда метка `Bug` заведена в Plane и проведён +> staging-прогон. Дефолт области (пустой CSV) = self-hosting only → enduro не затронут даже при +> включённом флаге. + +## 3. Зависимости / образ + +- **Новых pip-зависимостей нет.** Переиспользуются существующие `httpx`/`plane_sync` (label-чтение) + и `sqlite3` (колонка `tasks.track`). Пересборка образа из-за зависимостей не требуется. +- **Миграция БД** (`tasks.track`) применяется идемпотентно при старте приложения (`_ensure_column`) + — без ручного шага, без даунтайма (ALTER ADD COLUMN на SQLite — мгновенный). + +## 4. Self-hosting безопасность (NFR-6) + +- Механизм **не** рестартит/не роняет прод-контейнер, **не** пушит/force-push в `main`. Это + routing-решение планировщика + аддитивная колонка + read-only наблюдаемость. +- Выкат самого ORCH-019 на прод орка идёт штатным конвейером через обязательный + `deploy-staging` (8501) → `Confirm Deploy` (ORCH-059). Топология/процедура — `docs/operations/INFRA.md`. + +## 5. Новый эндпоинт (эскалация) + +`POST /bug-fast-track/escalate?work_item=` — админ-ручка возврата задачи в полный цикл +(`track → 'full'`), по образцу `POST /serial-gate/unfreeze`. Без новой инфраструктуры (тот же +FastAPI-приложение/порт). Read-only блок `bug_fast_track` добавляется в существующий `GET /queue`. + diff --git a/docs/work-items/ORCH-019/08-data-requirements.md b/docs/work-items/ORCH-019/08-data-requirements.md new file mode 100644 index 0000000..3c7a080 --- /dev/null +++ b/docs/work-items/ORCH-019/08-data-requirements.md @@ -0,0 +1,64 @@ +--- +work_item: ORCH-019 +stage: architecture +author_agent: architect +status: proposed +created_at: 2026-06-10 +model_used: claude-opus-4-8 +--- + +# 08 — Требования к данным (Data Requirements): ORCH-019 — Багфикс-трек + +Work Item: **ORCH-019** · Repo: **orchestrator** · Стадия: architecture + +> ⚠️ Общая прод-БД (self-hosting + enduro). Только **аддитивные, идемпотентные** миграции; +> существующие контракты таблиц не меняются. + +--- + +## 1. Новая колонка `tasks.track` + +| Атрибут | Значение | +|---------|----------| +| Таблица | `tasks` | +| Колонка | `track` | +| Тип | `TEXT` | +| DEFAULT | `'full'` | +| Допустимые значения | `'full'` (дефолт; ВСЕ существующие и не-баг задачи) \| `'bug'` | +| Миграция | `_ensure_column(conn, "tasks", "track", "TEXT DEFAULT 'full'")` (идемпотентно, паттерн `tasks.cancelled_at` ORCH-090) | +| Размещение | рядом с `_ensure_column(conn, "tasks", "cancel_requested_at", ...)` в init `src/db.py` | + +**Семантика:** тип задачи (полный цикл / багфикс). Записывается в `start_pipeline` после +успешного `create_task_atomic` (`created=True`) при `is_bug_task==True`. Читается в `advance_stage` +для routing-override (D3) — из БД, **никогда** из сети (NFR-4). + +## 2. Хелперы доступа (`src/db.py`) + +| Хелпер | Контракт | +|--------|----------| +| `set_task_track(task_id: int, track: str) -> None` | `UPDATE tasks SET track=? WHERE id=?`; идемпотентно; never-raise на уровне вызова в `start_pipeline`/escalate | +| `get_task_track(task_id: int) -> str` | `SELECT track FROM tasks WHERE id=?`; отсутствие/NULL → `'full'` (fail-safe → полный цикл) | + +## 3. Что НЕ меняется + +- Сигнатура `create_task_atomic(plane_id, work_item_id, repo, branch, stage, title)` — + **без изменений** (задача создаётся как `track='full'` по DEFAULT, тип проставляется отдельным + `set_task_track`). +- Существующие колонки `tasks` (прочие), таблицы `jobs`, `job_deps`, `agent_runs`, + `coverage_baseline`, `repo_freeze`, `tracker_messages` — **без изменений**. +- `claim_next_job` — **без изменений** (не читает `track`; сеть/маршрут в горячем claim не вводятся). + +## 4. Обратная совместимость / откат + +- Колонка аддитивна с безопасным DEFAULT `'full'` → существующие строки и enduro-задачи ведут + себя как сегодня без обратной записи. +- Откат фичи (`bug_fast_track_enabled=False`) не требует удаления колонки: при выключенном флаге + `track` не влияет на маршрут (`skips_architecture` → `False`). Остаточная колонка безвредна. +- Полный revert PR: миграция `_ensure_column` идемпотентна; повторный запуск на БД с уже + существующей колонкой — no-op. + +## 5. Объём данных / производительность + +- Одна `TEXT`-колонка на строку `tasks` (низкая кардинальность: 2 значения). Индекс не требуется + (чтение по `id` PK в `advance_stage`; агрегат для `GET /queue` — редкий read-only скан). + diff --git a/docs/work-items/ORCH-019/10-tech-risks.md b/docs/work-items/ORCH-019/10-tech-risks.md new file mode 100644 index 0000000..19bb22a --- /dev/null +++ b/docs/work-items/ORCH-019/10-tech-risks.md @@ -0,0 +1,39 @@ +--- +work_item: ORCH-019 +stage: architecture +author_agent: architect +status: proposed +created_at: 2026-06-10 +model_used: claude-opus-4-8 +--- + +# 10 — Технические риски: ORCH-019 — Багфикс-трек + +Work Item: **ORCH-019** · Repo: **orchestrator** · Стадия: architecture + +> Шкала: вероятность × влияние ∈ {Низк., Средн., Выс.}. Каждый риск — с митигатором, привязанным +> к ADR-001 / AC. + +--- + +| ID | Риск | Вер. | Влияние | Митигатор | +|----|------|------|---------|-----------| +| R-1 | **Срезали лишнее** — ошибочный пропуск гейта качества → недоделка на проде (урок ET-8). | Низк. | Выс. | NFR-1 диктует **нулевую** поверхность правок гейтов (D4): `STAGE_TRANSITIONS`/`QG_CHECKS`/все `check_*`/вердикт-ключи — байт-в-байт; режется ТОЛЬКО стадия `architecture`. Тест AC-3: на багфикс-треке отрабатывают все гейты. | +| R-2 | **Сложный баг под меткой `Bug`** уходит на фаст-трек и упирается в отсутствие архитектуры. | Средн. | Средн. | Эскалация D5 (эндпоинт `escalate` + self-escalate мини-аналитика) сбрасывает `track→full` → задача идёт через `architecture`. AC-5. | +| R-3 | **Регресс-тест не написан** (developer «забыл») → рецидив бага. | Средн. | Выс. | BR-4: обязательный TC в `04-test-plan.yaml` + reviewer-ось (фикс без теста → REQUEST_CHANGES) + структурный союзник coverage-gate ORCH-027. AC-4. | +| R-4 | **Fail-safe инвертирован** — ошибка чтения метки молча срежет стадии. | Низк. | Выс. | never-raise leaf `bug_fast_track.py`: любая ошибка/неоднозначность/`None`-labels → `is_bug_task=False` → полный цикл; `get_task_track` при NULL → `'full'`. AC-6. | +| R-5 | **Конфликт с serial-gate/auto-label** при изменённой точке входа. | Низк. | Средн. | Точка входа НЕ меняется (задача стартует на `analysis`, ветвление — только на ребре выхода). serial_gate/auto-label маркированный код не правится. Интеграционный тест композиции (AC-9). | +| R-6 | **Ложная блокировка** облегчённого пакета exit-гейтом `analysis` (`check_analysis_complete` требует 01/02/03/04). | Низк. | Средн. | D4: гейт НЕ трогаем; lite-аналитик эмитит все 4 файла (02/03 — краткие заглушки). FR-6/OQ-6. | +| R-7 | **Правка маркированного `advance_stage`** (несёт врезки ORCH-088/089/027/059/094) сломает чужой инвариант. | Низк. | Выс. | Врезка ORCH-019 — ТОЛЬКО на ребре выхода из `analysis`, ДО всех deploy-edge под-гейтов; порядок под-гейтов/merge-lease/terminal-sync не затронуты (CLAUDE.md §9: сверка `06-adr/` затронутых ORCH-NNN). | +| R-8 | **Телеметрия `mark_brd_review_ended`** не сработает на багфиксе (next=`development`, не `architecture`) → искажённая метрика «твоё время». | Низк. | Низк. | D3: условие расширено до `next_stage in ("architecture","development")`. Не влияет на гейты. | +| R-9 | **Метрика экономии** (FR-7) вводит в заблуждение (несравнимые задачи). | Низк. | Низк. | Метрика помечена как относительная оценка из существующей телеметрии `agent_runs`; без новой тяжёлой инфраструктуры; read-only, never-raise. AC-7. | + +--- + +## Сводный вывод + +Доминирующий риск — **R-1 (срезали лишнее)**; он структурно закрыт нулевой поверхностью правок +гейтов (D4) — изменение касается планировщика/точки входа, а не Quality Gate. Остальные риски +покрыты паттерном leaf+флаги+fail-safe (ORCH-088/089/027) и обратимой эскалацией (D5). Откат — +мгновенный через `bug_fast_track_enabled=False`. +