architect(ET): auto-commit from architect run_id=558
This commit is contained in:
@@ -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=<id>` сбрасывает
|
||||
`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 не было штатного способа отменить задачу (ручная хирургия по БД/процессам) и
|
||||
|
||||
95
docs/architecture/adr/adr-0032-bug-fast-track.md
Normal file
95
docs/architecture/adr/adr-0032-bug-fast-track.md
Normal file
@@ -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=<id>` сбрасывает
|
||||
`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`
|
||||
</content>
|
||||
@@ -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:
|
||||
|
||||
231
docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md
Normal file
231
docs/work-items/ORCH-019/06-adr/ADR-001-bug-fast-track.md
Normal file
@@ -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=<id>`
|
||||
(по образцу `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)
|
||||
</content>
|
||||
</invoke>
|
||||
62
docs/work-items/ORCH-019/07-infra-requirements.md
Normal file
62
docs/work-items/ORCH-019/07-infra-requirements.md
Normal file
@@ -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=<id>` — админ-ручка возврата задачи в полный цикл
|
||||
(`track → 'full'`), по образцу `POST /serial-gate/unfreeze`. Без новой инфраструктуры (тот же
|
||||
FastAPI-приложение/порт). Read-only блок `bug_fast_track` добавляется в существующий `GET /queue`.
|
||||
</content>
|
||||
64
docs/work-items/ORCH-019/08-data-requirements.md
Normal file
64
docs/work-items/ORCH-019/08-data-requirements.md
Normal file
@@ -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 скан).
|
||||
</content>
|
||||
39
docs/work-items/ORCH-019/10-tech-risks.md
Normal file
39
docs/work-items/ORCH-019/10-tech-risks.md
Normal file
@@ -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`.
|
||||
</content>
|
||||
Reference in New Issue
Block a user