361 lines
39 KiB
Markdown
361 lines
39 KiB
Markdown
---
|
||
work_item: ORCH-118
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-15
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# 01 — BRD (бизнес-требования): ORCH-118 — replace avoidable LLM control paths with deterministic implementations
|
||
|
||
Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||
|
||
> ⚠️ **Inventory-first.** Это **зонтичная inventory/architecture-задача**, а НЕ реализация
|
||
> детерминированных раннеров. Её результат — **карта** всех мест вызова LLM + классификация +
|
||
> упорядоченный roadmap + нормативная политика использования LLM, защищённая структурными тестами.
|
||
> Реализация конкретных замен — **последующие задачи**, запускаемые ПОСЛЕ утверждения карты. Их код
|
||
> в ORCH-118 **не вносится** (см. §2 «Вне объёма»).
|
||
|
||
> 📌 **Follow-up'ы именуются по РОЛИ, без выдуманных Plane-ID.** Roadmap рекомендует отдельные
|
||
> follow-up задачи по ролям-кандидатам (**deployer-замена**, **tester-гибрид** и т.д.). Конкретные
|
||
> Plane-ID этих задач в артефактах ORCH-118 **НЕ фиксируются** — они присваиваются при фактическом
|
||
> заведении задач в backlog. Аналитик не имеет доказательного источника на конкретные ID и не должен
|
||
> их выдумывать (см. NFR-6).
|
||
|
||
> 🔁 **Revision R3 (2026-06-15).** Из пакета **удалена** нормативная привязка follow-up'ов к
|
||
> конкретным ID `ORCH-115`/`ORCH-116` (этих work item нет ни в репозитории, ни в подтверждённом
|
||
> backlog — claim «источник истины: live Plane backlog» был **непроверяемым**). Вместе с ней удалены
|
||
> навязывавший её структурный тест (бывш. TC-11) и отдельный критерий приёмки (бывш. AC-9). Follow-up'ы
|
||
> теперь описаны **по роли**, ID — TBD. Содержательная классификация ролей не менялась
|
||
> (deployer = кандидат на детерминированную замену, tester = кандидат на hybrid-fallback).
|
||
> *(R1→R2 ранее «чинил» порядок этих ID; R3 убирает корень проблемы — фиксацию несуществующих ID.)*
|
||
|
||
> 🔁 **Revision R4 (2026-06-15).** Закрыт блокер R3-ревью: инвариант «места вызова LLM» **смешивал**
|
||
> факт *«существует процесс Claude CLI / спавнится subprocess»* (транспорт/механизм) с фактом
|
||
> *«потребляется суждение LLM»* (LLM-консультация). R4 развёл **транспорт** (`_spawn`) и **слот/
|
||
> capability** (D1/D2) от факта **консультации** во всех артефактах (см. §0). Содержательная
|
||
> классификация ролей и весь R3-материал (анти-фабрикация ID) — без изменений.
|
||
|
||
> 🔁 **Revision R5 (2026-06-15) — единственный оставшийся блокер R4-ревью.** Рецензент подтвердил R4
|
||
> (консультация ≠ транспорт/слот; no-alternative-LLM-transport; follow-up'ы по роли/TBD; нет
|
||
> runtime-дифа) — **менять их не нужно**. Закрывается **один** блокер: артефакты разводили
|
||
> «консультация ≠ транспорт/слот», но **не делали явной третью ось — самую важную для названия
|
||
> задачи** *«replace avoidable LLM **control paths**»*: среди фактических консультаций **не
|
||
> различались** (i) **control-path-консультации** — где LLM-вердикт **потребляется потоком управления**
|
||
> (на нём ветвится `check_*`-гейт), и (ii) **artifact-producer-консультации** — где LLM лишь
|
||
> **производит артефакт**, а ветвление делает **детерминированный гейт** (наличие файлов / CI), и
|
||
> суждение LLM в control flow **не входит**. И главное — нигде **явно не определена «avoidable LLM
|
||
> control path»**. R5 добавляет эту ось и определение во **все** артефакты (новый §0-bis, уточнённые
|
||
> BR-1/BR-2 + новые BR-8/BR-9, FR-1/FR-2 + новый FR-8, AC-1/AC-2 + новый AC-10, TC-13/TC-14).
|
||
> Содержательная классификация (analyst/architect/developer/reviewer → keep-LLM; deployer →
|
||
> replace-deterministic; tester → hybrid) **не меняется** — R5 даёт ей **доказательный control-path
|
||
> вывод** из кода (`check_*`/`_parse_*` в `src/qg/checks.py`).
|
||
|
||
---
|
||
|
||
## 0. Единица анализа: «LLM-консультация» ≠ «процесс Claude CLI» (R4)
|
||
|
||
Задача — про **LLM control paths**, поэтому единица инвентаря/классификации/инвариантов — это
|
||
**LLM-консультация (call-site)**, а НЕ «спавн процесса / существование Claude CLI». Три ортогональных
|
||
факта фиксируются **раздельно** (их смешение и было блокером R3-ревью):
|
||
|
||
1. **LLM-консультация (семантическая единица).** Точка потока управления, где решение/артефакт
|
||
конвейера **потребляет суждение LLM** (инференс модели). Именно её перечисляет и классифицирует
|
||
карта. «Заменить avoidable LLM control path» = убрать *консультацию* там, где суждение не нужно, —
|
||
независимо от того, каким транспортом она реализована.
|
||
2. **Транспорт (механизм) ≠ консультация.** Claude CLI-subprocess через `launcher._spawn`
|
||
(`src/agents/launcher.py`, сборка `CLAUDE_BIN --print … --system-prompt "$(cat …)"` + `Popen`) —
|
||
**текущий единственный транспорт**, которым реализуется LLM-консультация. Транспорт — это одна
|
||
*реализация* понятия, а НЕ его *определение*. «Существует процесс Claude CLI» само по себе **не**
|
||
равно «принято решение на основе суждения LLM».
|
||
3. **Capability ≠ consultation (способность ≠ факт консультации).** Спавн процесса делает site
|
||
*LLM-capable*; происходит ли консультация фактически — **гейтится потоком управления**:
|
||
- `D1/D2` (`deploy-finalizer`/`post-deploy-monitor`) — job-роли, **занимающие слот агента**, но
|
||
перехватываемые в `launch_job` **до** `_spawn` (`src/agents/launcher.py:389,394`, код прямо
|
||
помечает «Not an LLM spawn») → **консультации LLM нет**, хотя «агент» как job существует;
|
||
- timeout-kill (`exit_code=-9`) / salvage-guard (`if exit_code==0`) → спавненный процесс может **не
|
||
произвести** потреблённого суждения.
|
||
Поэтому «процесс спавнится» **переоценивает** «суждение потреблено».
|
||
|
||
Следствие для инварианта единственной точки (детализируется в BR-1/BR-6): он должен быть
|
||
**транспорт-агностичным и двусторонним** — (i) единственный транспорт LLM-консультации в `src/**` —
|
||
`_spawn`, И (ii) **отсутствует любой иной транспорт** (импорт `anthropic`/`openai`/LLM-SDK, прямой
|
||
HTTP-эндпоинт Anthropic/Claude, второй model-invoking subprocess-сборщик `--system-prompt`/`--model`).
|
||
Дискриминатор — **«консультирует LLM», а не «спавнит subprocess»**: десятки subprocess-вызовов в
|
||
`src/**` (`git`/`pytest`/`docker`/`ssh`/сканеры/`staging_check.py`) **не** являются LLM-консультациями
|
||
и не должны попадать под инвариант (см. FR-6 матчинг).
|
||
|
||
---
|
||
|
||
## 0-bis. Третья ось: control-path-консультация ≠ artifact-producer-консультация; что такое «avoidable» (R5)
|
||
|
||
§0 (R4) отделил **факт консультации** от **транспорта** и **слота**. Но название задачи —
|
||
«replace **avoidable** LLM **control paths**» — требует ещё одного, **решающего** различия **внутри
|
||
множества фактических консультаций** (A1…A6). Без него «control path» и «avoidable» остаются
|
||
неопределёнными, и карта не отвечает на главный вопрос задачи: *какие именно консультации — это
|
||
avoidable LLM control paths*. Это и есть оставшийся блокер R4-ревью.
|
||
|
||
### Ось 3 — как именно LLM-вывод соотносится с потоком управления
|
||
|
||
Каждая фактическая консультация (роль-агент) относится **ровно к одному** из двух типов:
|
||
|
||
- **(C) Control-path-консультация.** LLM эмитит **machine-verdict**, который **потребляется потоком
|
||
управления конвейера**: соответствующий `check_*`-гейт **ветвится на этом вердикте**
|
||
(PASS→дальше / FAIL→откат). Суждение LLM **входит в control flow** — это и есть «**LLM control
|
||
path**» в точном смысле названия задачи.
|
||
- **(P) Artifact-producer-консультация.** LLM **производит артефакт** (документы/код/PR), а решение
|
||
о продвижении принимает **детерминированный гейт**, судящий артефакт **независимо** от
|
||
самоотчёта LLM (наличие файлов, статус CI). Суждение LLM **в control flow не входит** → это **не**
|
||
«LLM control path» (хотя консультация реальна и может требовать настоящего суждения).
|
||
|
||
Различие доказывается кодом — **кто потребляет вывод роли** (`src/qg/checks.py`, ground-truth на
|
||
момент задачи):
|
||
|
||
| Роль | Потребитель вывода (control-flow consumer) | Тип (C/P) | Control path? |
|
||
|------|--------------------------------------------|-----------|---------------|
|
||
| analyst | `check_analysis_complete` (checks.py:33) — **наличие файлов** 01–04 | **P** | нет |
|
||
| architect | `check_architecture_done` (checks.py:62) — **наличие** 06-adr/07 | **P** | нет |
|
||
| developer | `check_ci_green` (checks.py:82) + `check_branch_mergeable` (657) — **CI/merge** | **P** | нет |
|
||
| reviewer | `check_reviewer_verdict` (checks.py:336) читает **`verdict:`** → REQUEST_CHANGES-откат | **C** | **да** |
|
||
| tester | `check_tests_passed` (checks.py:182) → `_parse_tests_verdict` (226) читает **`result:`** | **C** | **да** |
|
||
| deployer | `check_staging_status` (599)→`_parse_staging_status` (538) **`staging_status:`**; `check_deploy_status` (473)→`_parse_deploy_status` (413) **`deploy_status:`** | **C** | **да** |
|
||
|
||
> Для **P**-ролей гейт читает **не самоотчёт LLM**, а независимый детерминированный сигнал
|
||
> (файлы/CI) — поэтому подделать ветвление «самооценкой» нельзя; это структурно НЕ control path.
|
||
> Для **C**-ролей гейт читает **именно machine-verdict, который написал LLM** — суждение LLM и есть
|
||
> точка ветвления.
|
||
|
||
### Определение «avoidable LLM control path» (нормативное, R5)
|
||
|
||
Call-site — **avoidable LLM control path** ⟺ выполнены **оба** условия:
|
||
|
||
1. **(control path)** это **C**-консультация — её LLM-вердикт потребляется потоком управления
|
||
(`check_*` ветвится на нём); **и**
|
||
2. **(deterministically derivable)** этот вердикт по сути есть **детерминированная функция от
|
||
tool-сигналов** (exit-code `pytest`/smoke, `staging_check.py`, exit-code деплоя), которые
|
||
оркестратор **уже вычисляет сам** → суждение LLM **не добавляет информации** → консультацию можно
|
||
снять без потери смысла.
|
||
|
||
Отсюда — **точный целевой набор задачи** (доказательно, не «на глаз»):
|
||
|
||
- **avoidable LLM control paths = {tester, deployer}** — C **и** вердикт деривируем из exit-кодов
|
||
(`_parse_tests_verdict` судит то, что есть исход `pytest`; `_parse_staging_status`/
|
||
`_parse_deploy_status` судят то, что есть исход `staging_check.py`/деплоя; прод-деплой
|
||
self-hosting **уже** идёт детерминированным путём Phase A/B/C, ORCH-036).
|
||
- **control path, но НЕ avoidable = {reviewer}** — C, но вердикт **не** деривируем: «приемлем ли
|
||
код?» — настоящее суждение (keep-LLM). Это показывает, что «control path» **сам по себе** не равен
|
||
«avoidable» — отсекает условие 2.
|
||
- **НЕ control path (avoidable-вопрос неприменим) = {analyst, architect, developer}** — P:
|
||
детерминированный гейт судит артефакт, суждение LLM в control flow не входит; авторская работа
|
||
требует настоящего суждения (keep-LLM). Это отсекает условие 1.
|
||
- **уже детерминированы (вне консультаций) = {deploy-finalizer, post-deploy-monitor}** — §0.3.
|
||
|
||
Эта ось **выводит** R3/R4-классификацию из кода, а не постулирует её: класс call-site'а есть
|
||
**функция** его (C/P)-типа и деривируемости вердикта (см. BR-2). «Avoidable» больше не «удобство на
|
||
глаз», а проверяемый двухбитный предикат над `src/qg/checks.py`.
|
||
|
||
---
|
||
|
||
## 1. Бизнес-контекст и проблема
|
||
|
||
Зонтичный follow-up по итогам RCA-цепочки **ORCH-114/117** (и предшествующих ORCH-110/111/112/113):
|
||
корневым классом инцидентов было то, что **side-effectful и решающие control-path'ы не имели единого
|
||
детерминированного владения** — где-то решение принималось «потому что так удобно» через LLM-агента,
|
||
хотя по сути это исполнение фиксированных команд и маппинг результата.
|
||
|
||
Установленный факт по текущему коду (инвентаризация — §1 TRZ, артефакт-карта):
|
||
|
||
- В оркестраторе **единственный транспорт LLM-консультации** — `src/agents/launcher.py::_spawn` (одна
|
||
`subprocess.Popen` сборка Claude CLI: `CLAUDE_BIN --print … --system-prompt "$(cat …)"`), которым
|
||
пользуются **6 ролей-агентов** (analyst, architect, developer, reviewer, tester, deployer).
|
||
Прямых вызовов Anthropic API / LLM-SDK / иных model-invoking транспортов в `src/**` **нет**
|
||
(подтверждено инвентаризацией; впредь — держится тестом FR-6). ⚠️ Это утверждение про **транспорт**,
|
||
а не про «единственный subprocess»: в `src/**` десятки прочих `subprocess`-вызовов (`git`/`pytest`/
|
||
`docker`/`ssh`/сканеры) — они **не** консультируют LLM (см. §0).
|
||
- **Из 6 консультаций только 3 — это LLM control paths** (вердикт потребляется потоком управления,
|
||
§0-bis): **reviewer / tester / deployer**. Остальные 3 (**analyst / architect / developer**) —
|
||
artifact-producer'ы: их выход судит **детерминированный** гейт (наличие файлов / CI), суждение LLM
|
||
в control flow не входит. Среди 3 control path'ов **avoidable** — те, чей вердикт деривируем из
|
||
exit-кодов: **tester** и **deployer**; **reviewer** — control path с **настоящим** суждением
|
||
(keep).
|
||
- **Все остальные control-path'ы уже детерминированы (без LLM):** маршрутизация стадий
|
||
(`STAGE_TRANSITIONS`/`advance_stage`), все Quality Gate'ы и под-гейты (`check_*`, security/merge/
|
||
coverage/image-freshness), парсеры вердиктов (`_parse_*` через `frontmatter.py`), классификатор
|
||
ретраев (`error_classifier.py`), serial-gate/transition-lease/reconciler/reaper, а также **две
|
||
зарезервированные job-роли** `deploy-finalizer` и `post-deploy-monitor` (перехватываются в
|
||
`launch_job` **до** `_spawn` — это рабочий прецедент детерминированной замены агента).
|
||
|
||
Боль/риск, который закрывает задача: LLM на **механических control path'ах** — это (а) лишний
|
||
источник недетерминизма и инцидентов (ложный вердикт/действие в точке ветвления), (б) задержка
|
||
(запуск opus-агента вместо прямого вызова), (в) расход токенов/денег. При этом «вслепую» убирать LLM
|
||
нельзя — часть путей несёт **настоящее суждение** (анализ, архитектура, написание кода, **ревью**), и
|
||
автономность/гибкость должны сохраниться. Точный дискриминатор «убирать/оставить» — определение
|
||
«avoidable LLM control path» (§0-bis).
|
||
|
||
ORCH-118 даёт **доказательную карту** «где LLM действительно нужен, а где это avoidable control path»
|
||
и **упорядоченный план** безопасных замен — фундамент, на котором последующие срезы (по
|
||
ролям-кандидатам) выполняются предсказуемо и без регресса.
|
||
|
||
## 2. Объём (scope)
|
||
|
||
### В объёме
|
||
- **BR-1** Полная инвентаризация всех мест вызова LLM и всех ролей-агентов (карта call-site'ов).
|
||
- **BR-2** Классификация каждого call-site в один из 4 классов (keep / replace-now / replace-later /
|
||
hybrid-fallback) с явным обоснованием, **выведенным** из control-path-оси (§0-bis): класс есть
|
||
функция (C/P)-типа и деривируемости вердикта.
|
||
- **BR-3** Доказательное подтверждение (с привязкой `file:line`), что не-агентские control-path'ы
|
||
(маршрутизация / ретраи / QG / парсеры / finalizer'ы) уже детерминированы.
|
||
- **BR-4** Упорядоченный roadmap замен: зависимости, оценка экономии токенов/времени, риски
|
||
безопасности, потребность в hybrid-fallback, рекомендованный **первый срез** — кандидаты названы
|
||
**по роли** (follow-up ID — TBD).
|
||
- **BR-5** Нормативная **политика использования LLM** («LLM — только там, где нужно настоящее
|
||
суждение») как durable-документ.
|
||
- **BR-6** Структурные regression-тесты, **прибивающие инварианты карты к коду** (транспорт-агностичный
|
||
двусторонний инвариант + control-path-ось) — анти-дрейф.
|
||
- **BR-7** Явно позиционировать **роль deployer** и **роль tester** как **кандидаты-follow-up** для
|
||
детерминированной замены — **по роли, без привязки к конкретным Plane-ID** (см. NFR-6).
|
||
- **BR-8 (R5)** Карта **явно** размечает каждую консультацию по оси (C) control-path /
|
||
(P) artifact-producer с доказательством — **кто потребляет вывод роли** (`check_*`/`_parse_*` с
|
||
`file:line`).
|
||
- **BR-9 (R5)** Карта/политика **явно** определяют термин **«avoidable LLM control path»** (двухбитный
|
||
предикат §0-bis) и **поимённо** называют целевой набор `{tester, deployer}`, явно отделяя его от
|
||
control-path-но-keep (`reviewer`) и от не-control-path (`analyst`/`architect`/`developer`).
|
||
|
||
### Вне объёма
|
||
- ❌ **Реализация** детерминированных раннеров deployer / tester и любых других замен — это отдельные
|
||
follow-up задачи ПОСЛЕ утверждения карты (явное требование заказчика в business request).
|
||
- ❌ **Выдумывание/фиксация конкретных follow-up Plane-ID** (напр. `ORCH-115`/`ORCH-116`) в любых
|
||
артефактах ORCH-118 — ID присваиваются при заведении задач (NFR-6).
|
||
- ❌ Изменение `STAGE_TRANSITIONS` / реестра `QG_CHECKS` / семантики и имён `check_*` /
|
||
machine-verdict-ключей (`verdict:`/`result:`/`staging_status:`/`deploy_status:`/`security_status:`/
|
||
`coverage_status:`) / схемы БД.
|
||
- ❌ Включение model-routing (G3 ORCH-41) или смена модели/эффорта ролей.
|
||
- ❌ Любая правка поведения `src/**` в рантайме (ORCH-118 — **docs + tests only**, по образцу
|
||
ORCH-077/079/101/102/103/011).
|
||
- ❌ Снижение автономности или гибкости конвейера.
|
||
|
||
## 3. Заинтересованные стороны
|
||
- **Заказчик / Owner** — инициатор RCA-трека ORCH-114/117; принимает карту и roadmap (gate утверждения).
|
||
- **Сопровождающие платформы (self-hosting)** — выигрывают в стабильности, скорости, экономии токенов.
|
||
- **Downstream-проекты (enduro-trails)** — делят общий прод/очередь; для них требуется **нулевая
|
||
регрессия** (NFR-1).
|
||
- **Будущие исполнители follow-up'ов** — потребители карты, roadmap и политики.
|
||
|
||
## 4. Бизнес-требования (BR)
|
||
|
||
- **BR-1 — Инвентарь LLM-консультаций (call-site'ов).** Выпустить durable-документ, перечисляющий
|
||
**каждое** место, где control-path **потребляет суждение LLM** или может его потребить (единица —
|
||
*LLM-консультация*, §0, а не «спавн процесса»): единственный транспорт `_spawn`, все 6 ролей-агентов
|
||
и обе зарезервированные job-роли `D1/D2` (включаются как доказательство «слот агента есть, но
|
||
консультации LLM нет» — перехват до `_spawn`). Для каждого — `file:line`, триггер, стадия/владелец,
|
||
выходной артефакт, machine-verdict-ключ (если есть), **потребитель вывода (`check_*`/`_parse_*` с
|
||
`file:line`)**, оценка токенов/времени, **признак capability-vs-consultation** (§0.3) и **признак
|
||
оси (C) control-path / (P) artifact-producer** (§0-bis, BR-8). Проверяемо: каждый `file:line`
|
||
резолвится в реальный код.
|
||
- **BR-2 — Классификация.** Каждому call-site присвоить **ровно один** класс из таксономии:
|
||
`keep-LLM` (нужно настоящее суждение), `replace-deterministic-now` (безопасная замена сейчас),
|
||
`replace-later/risky` (замена позже / рискованно), `needs-hybrid-fallback` (детерминированное ядро +
|
||
LLM-фолбэк на суждение). Класс **выводится** из control-path-оси (§0-bis): **P** → `keep-LLM`
|
||
(артефактная авторская работа); **C + не-деривируемый вердикт** → `keep-LLM` (reviewer); **C +
|
||
деривируемый вердикт** → `replace-*` / `needs-hybrid-fallback` (tester/deployer = avoidable). Для
|
||
`keep-LLM` — **назвать конкретное суждение**, ради которого LLM сохраняется (для **C**-keep —
|
||
почему вердикт **не** деривируем).
|
||
- **BR-3 — Подтверждение детерминизма не-агентских путей.** Документально, с `file:line`-доказательством,
|
||
зафиксировать, что маршрутизация стадий, ретраи, QG-проверки, парсеры вердиктов и finalizer'ы **не
|
||
консультируют LLM** (не зависят от суждения LLM — ни через `_spawn`, ни через иной транспорт; их
|
||
subprocess-вызовы git/pytest/docker/ssh/сканеров — детерминированные инструменты, не LLM, §0). Если
|
||
инвентаризация найдёт неожиданную LLM-консультацию — она попадает в карту (BR-1) и классификацию
|
||
(BR-2).
|
||
- **BR-4 — Упорядоченный roadmap.** Ранжированный план замен: для каждого кандидата (названного **по
|
||
роли**) — зависимости, **оценка** экономии токенов/времени (из телеметрии `agent_runs`), риск
|
||
безопасности, нужен ли hybrid-fallback, ожидание kill-switch/обратимости. Явно указать
|
||
**рекомендованный первый срез** и обоснование выбора (опора на control-path-вывод: первым берётся
|
||
самый «чисто деривируемый» control path). Привязка к follow-up задаче — **по роли**; конкретный
|
||
Plane-ID НЕ фиксируется (заводится отдельно, NFR-6).
|
||
- **BR-5 — Политика использования LLM.** Нормативный durable-документ: «LLM — только там, где требуется
|
||
настоящее суждение»; критерии решения keep vs replace, **сформулированные через ось §0-bis**
|
||
(является ли путь control path; деривируем ли вердикт); требование к новым/изменённым control-path'ам
|
||
обосновывать любое использование LLM против этой политики.
|
||
- **BR-6 — Анти-дрейф структурными тестами.** Тесты, привязывающие инварианты карты к коду:
|
||
транспорт-агностичный двусторонний инвариант единственной точки (§0); перечисленные
|
||
детерминированные модули/job-роли не несут LLM-консультации; карта перечисляет ровно те 6 промптов,
|
||
что лежат в `.openclaw/agents/`; тотальность классификации; **плюс control-path-ось (R5):** карта
|
||
размечает каждую роль (C/P) согласованно с фактическим потребителем в `src/qg/checks.py`, а
|
||
avoidable-набор = `{tester, deployer}`. Тесты — offline. **Тест на привязку к конкретным follow-up
|
||
ID не вводится** (анти-паттерн R3).
|
||
- **BR-7 — Позиционирование follow-up'ов по роли.** Карта/roadmap явно отмечают **роль deployer** и
|
||
**роль tester** как кандидаты-замены, **не** реализуемые в ORCH-118; их старт гейтится утверждением
|
||
карты. Привязка — **по роли**, без конкретных Plane-ID (NFR-6).
|
||
- **BR-8 (R5) — Явная control-path-разметка.** Карта несёт для каждой консультации поле оси
|
||
**(C) control-path / (P) artifact-producer** + доказательство (потребитель вывода с `file:line`).
|
||
Разметка **проверяема** структурным тестом против `src/qg/checks.py` (BR-6, TC-13).
|
||
- **BR-9 (R5) — Явное определение «avoidable LLM control path» и поимённый целевой набор.** Карта/
|
||
политика дают нормативное определение термина (двухбитный предикат §0-bis) и **поимённо** называют
|
||
`{tester, deployer}` как avoidable, явно отделяя их от `reviewer` (control path, keep) и от
|
||
`analyst/architect/developer` (не control path). Набор **проверяем** тестом (BR-6, TC-14).
|
||
|
||
## 5. Нефункциональные требования (NFR)
|
||
|
||
- **NFR-1 — Сохранение поведения (нулевая регрессия).** ORCH-118 — docs+tests only:
|
||
`STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict-ключи/схема БД — **байт-в-байт**; поведение
|
||
конвейера 1:1; enduro-trails не затронут.
|
||
- **NFR-2 — Сохранение автономности и гибкости.** Ни инвентаризация, ни политика не должны
|
||
предлагать решений, снижающих автономный/пакетный режим (ORCH-088/089) или гибкость; политика
|
||
**защищает** автономность как инвариант любой будущей замены.
|
||
- **NFR-3 — Self-hosting безопасность.** Задача только **читает** код и пишет docs+tests — не
|
||
деплоит, не рестартит прод-контейнер, не трогает `main`/force-push, не запускает процессов/сети.
|
||
- **NFR-4 — Трассируемость и сопровождаемость.** Карта привязана к коду маркерами/тестом и остаётся
|
||
честной при эволюции кода; формат — по `docs/_standards/PIPELINE_DOCS.md` и `TRACEABILITY.md`.
|
||
- **NFR-5 — Доказательность экономии.** Цифры экономии берутся из реальной телеметрии `agent_runs`
|
||
(модель/эффорт/токены/стоимость/время по ролям) и помечаются как **оценки** до фактического замера
|
||
после реализации.
|
||
- **NFR-6 — Только проверяемые ссылки (анти-фабрикация, R3).** В артефактах фиксируются только
|
||
ссылки, резолвящиеся в код/документы репозитория. Конкретные **follow-up Plane-ID не выдумываются**:
|
||
кандидаты-замены именуются по роли; ID присваивается при заведении задачи. (Это закрывает корень
|
||
отклонённой ревизии R2.)
|
||
- **NFR-7 (R5) — Контроль-ориентированность определений.** «LLM control path» и «avoidable»
|
||
определяются **через потребление вывода потоком управления** (кто из `check_*` ветвится на выводе),
|
||
а не через «есть ли вообще LLM-вызов на стадии». Любое утверждение «это avoidable LLM control path»
|
||
обязано резолвиться в конкретный `check_*`/`_parse_*` + tool-сигнал, из которого вердикт деривируем.
|
||
|
||
## 6. Допущения и ограничения
|
||
- Единственный транспорт LLM сейчас — Claude CLI через `launcher._spawn`; прямых вызовов Anthropic API
|
||
в `src/**` нет (подтверждается инвентаризацией).
|
||
- Model-routing не включён — все 6 ролей на `claude-opus-4-8` (ORCH-41), что упрощает оценку экономии.
|
||
- Карта — **снимок на момент задачи**, защищённый структурными тестами от тихого расхождения с кодом.
|
||
- Прецедент детерминированной замены агента уже существует и работает (`deploy-finalizer`/
|
||
`post-deploy-monitor` в `launch_job` до `_spawn`) — это снижает архитектурный риск follow-up'ов.
|
||
- На момент анализа конкретные follow-up work item для замены ролей в backlog **не подтверждены** —
|
||
поэтому ID не фиксируются (NFR-6).
|
||
- **(R5)** Control-path-разметка опирается на ground-truth `src/qg/checks.py` на момент задачи; при
|
||
эволюции кода её честность держит структурный тест (TC-13/TC-14).
|
||
|
||
## 7. Критерии успеха
|
||
Карта LLM-консультаций полна и привязана к коду, и **разводит три ортогональных факта**: транспорт/слот
|
||
(«процесс Claude CLI существует», R4 §0), факт консультации, **и — control-path-ось (R5 §0-bis):
|
||
потребляется ли LLM-вывод потоком управления (`check_*` ветвится на нём) или его независимо судит
|
||
детерминированный гейт**. Термин **«avoidable LLM control path» явно определён** (двухбитный предикат)
|
||
и целевой набор **поимённо** назван `{tester, deployer}` с доказательным отделением от `reviewer`
|
||
(control path, keep) и от `analyst/architect/developer` (не control path). Каждый site классифицирован
|
||
с обоснованием, **выведенным** из этой оси; детерминизм не-агентских путей доказан (отсутствием
|
||
LLM-консультации, не отсутствием subprocess); есть упорядоченный roadmap с зависимостями/экономией/
|
||
рисками и рекомендованным первым срезом (кандидаты — по роли); есть нормативная политика; структурные
|
||
тесты зелёные и осмысленные (инвариант единственной точки транспорт-агностичен и двусторонен; control-path
|
||
-разметка сверена с `src/qg/checks.py`; avoidable-набор зафиксирован); ни один рантайм-инвариант не
|
||
тронут; раннеры замен НЕ реализованы; ни один артефакт не фиксирует непроверяемых follow-up ID.
|
||
Детальные PASS/FAIL — в `03-acceptance-criteria.md`.
|
||
|
||
## 8. Риски
|
||
- **Недо-/пере-классификация** (LLM убран там, где нужно суждение, или сохранён там, где не нужен) →
|
||
митигирует **control-path-вывод** (§0-bis: класс выводится из (C/P)-типа и деривируемости вердикта,
|
||
а не «на глаз») + требование «назвать конкретное суждение» для `keep-LLM` + ревью карты.
|
||
- **Конфляция «есть LLM на стадии» с «это control path»** (рецидив корня R4-блокера) → митигирует
|
||
явная разметка оси и тест TC-13 (сверка с фактическим потребителем `check_*`).
|
||
- **Дрейф карты** относительно кода со временем → митигируют структурные тесты (BR-6), включая
|
||
control-path-инварианты (TC-13/TC-14).
|
||
- **Преждевременная замена** в погоне за экономией ценой автономности/гибкости → инвентаризация
|
||
отделена от реализации; первый срез — самый низкорисковый «чисто деривируемый» control path.
|
||
- **Фабрикация ссылок/ID** (рецидив дефекта R2) → митигирует NFR-6 (только проверяемые ссылки;
|
||
follow-up'ы — по роли) и ревью. Детали техн.рисков — `10-tech-risks.md` (архитектор).
|