--- 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` (архитектор).