20 KiB
work_item, stage, author_agent, status, created_at, model_used
| work_item | stage | author_agent | status | created_at | model_used |
|---|---|---|---|---|---|
| ORCH-118 | analysis | analyst | ready-for-review | 2026-06-15 | claude-opus-4-8 |
02 — ТЗ (TRZ): ORCH-118 — replace avoidable LLM control paths with deterministic implementations
Work Item: ORCH-118 · Repo: orchestrator · Стадия: analysis
ТЗ описывает что должно измениться и где (артефакты/контракты/тесты), выведено из BRD и фактического кода. Как (точная структура/размещение документов карты, формат классификации, схема структурных тестов) — решает архитектор в
06-adr/. ТЗ фиксирует требования и границы.⚠️ Скоуп — inventory + классификация + roadmap + политика + структурные тесты. Реализация детерминированных раннеров — вне скоупа (FR-7). Это docs + tests only:
src/**-рантайм не меняется.📌 Follow-up'ы — по роли, без выдуманных Plane-ID (R3, NFR-6). Конкретные ID (напр.
ORCH-115/ORCH-116) в артефактах не фиксируются — этих work item нет в репо/подтверждённом backlog; ID присваивается при заведении задачи.🔁 R4 — единственный блокер R3-ревью. Единица инвентаря/инварианта — LLM-консультация (control-path потребляет суждение LLM), не «спавн процесса / существование Claude CLI». Claude CLI-subprocess через
_spawn— лишь текущий транспорт; «процесс существует» ≠ «LLM консультирован» (capability ≠ consultation). Развёрнуто — BRD §0; затрагивает FR-1/FR-3/FR-6.
1. Сводка изменения
Выпустить доказательную карту всех мест вызова LLM в оркестраторе с классификацией и
упорядоченным roadmap'ом детерминированных замен, а также нормативную политику использования LLM;
прибить инварианты карты к коду набором структурных тестов. Реализация замен не входит. Все
рантайм-контракты (STAGE_TRANSITIONS / QG_CHECKS / check_* / machine-verdict-ключи / схема БД) —
не меняются.
Опорный факт инвентаризации (ground-truth кода на момент задачи; line-привязки уточняет карта):
Единица — LLM-консультация (потребление суждения LLM), а не «спавн процесса» (R4, BRD §0). Колонка ниже помечает, является ли site фактической консультацией или лишь LLM-capable транспортом/ слотом.
| # | Call-site | Где | Что делает | Консультирует LLM? |
|---|---|---|---|---|
| S0 | Единственный транспорт LLM-консультации | src/agents/launcher.py::_spawn (сборка CLAUDE_BIN --print … --system-prompt "$(cat …)" + subprocess.Popen) |
реализует консультацию для любой из 6 ролей | транспорт (capability) |
| A1 | analyst | промпт .openclaw/agents/analyst.md, стадия analysis |
анализ бизнес-запроса → 01–04 | да (через S0) |
| A2 | architect | .openclaw/agents/architect.md, стадия architecture |
архитектурные решения → 06-adr | да (через S0) |
| A3 | developer | .openclaw/agents/developer.md, стадия development |
реализация + PR | да (через S0) |
| A4 | reviewer | .openclaw/agents/reviewer.md, стадия review |
ревью → 12-review.md (verdict:) |
да (через S0) |
| A5 | tester | .openclaw/agents/tester.md, стадия testing |
pytest+smoke → 13-test-report.md (result:) |
да (через S0) |
| A6 | deployer | .openclaw/agents/deployer.md, стадии deploy-staging/deploy |
staging_check.py/exit-code → 15/14 логи |
да (через S0) |
| D1 | deploy-finalizer | launch_job перехват до _spawn (launcher.launch_job) |
детерминированный (LLM не консультируется) | нет (слот агента, перехват до _spawn) |
| D2 | post-deploy-monitor | launch_job перехват до _spawn (launcher.launch_job) |
детерминированный (LLM не консультируется) | нет (слот агента, перехват до _spawn) |
Не-агентские control-path'ы (маршрутизация
advance_stage,QG_CHECKS/check_*/_parse_*,error_classifier,serial_gate/merge_gate/coverage_gate/security_gate/staging_verdict/review_parse/frontmatter,self_deployPhase A/B/C) — уже детерминированы (FR-3).
2. Задействованные модули / пути
| Путь | Действие |
|---|---|
src/agents/launcher.py |
читать (инвентарь S0/D1/D2; _spawn, launch_job, AGENT_CONFIGS, resolve_agent_model/effort) — не менять |
.openclaw/agents/{analyst,architect,developer,reviewer,tester,deployer}.md |
читать (инвентарь 6 ролей) — не менять |
src/stages.py, src/stage_engine.py |
читать (доказать детерминизм маршрутизации) — не менять |
src/qg/checks.py |
читать (QG_CHECKS/check_*/_parse_* — детерминизм) — не менять |
src/{serial_gate,merge_gate,coverage_gate,security_gate,staging_verdict,review_parse,error_classifier,frontmatter,self_deploy,post_deploy,transition_lease,reconciler,job_reaper}.py |
читать (детерминированные leaf'ы — доказательная база) — не менять |
src/usage.py, src/db.py (agent_runs) |
читать (источник оценок экономии токенов/времени) — не менять |
docs/architecture/llm-call-sites.md (имя — пример; финально решает архитектор) |
создать: карта call-site'ов + классификация (FR-1/FR-2/FR-3) |
docs/architecture/llm-determinization-roadmap.md (имя — пример) |
создать: упорядоченный roadmap (FR-4) |
docs/architecture/llm-usage-policy.md (имя — пример) |
создать: нормативная политика (FR-5) |
docs/work-items/ORCH-118/06-adr/ADR-001-*.md |
создать (архитектор): фиксация карты/таксономии/первого среза как ADR |
tests/test_llm_call_site_inventory.py (имя — пример) |
создать: структурные анти-дрейф тесты (FR-6) |
docs/architecture/README.md, docs/overview/*, CHANGELOG.md |
обновить (ссылка на карту/политику; норматив golden-source) |
Документы карты/политики целесообразно разместить в
docs/architecture/(durable, сквозное), а не только вdocs/work-items/ORCH-118/— окончательное размещение/формат решает архитектор.
3. Функциональные требования
FR-1 — Полнота и привязка инвентаря LLM-консультаций (BR-1)
Единица — LLM-консультация (control-path потребляет суждение LLM), а не «спавн процесса» (R4, BRD
§0). Карта перечисляет каждый call-site: S0 (единственный транспорт _spawn), A1…A6 (6 ролей,
консультируют через S0), D1/D2 (job-роли, занимают слот агента, но НЕ консультируют LLM —
перехват в launch_job до _spawn; включены как доказательство паттерна). Поля записи: id,
location (file:line), trigger, stage/owner, output artifact, machine-verdict key (если
есть), est. tokens/runtime, consults-LLM (consultation vs LLM-capable transport/slot, §0.3),
classification, rationale, dependency, risk. Каждый file:line обязан резолвиться в реальный
код. Инвариант (транспорт-агностичный, двусторонний): единственный транспорт LLM-консультации в
src/** — S0; иного LLM-транспорта нет — подтверждается тестами FR-6(a)+(f). «Процесс Claude
CLI существует» ≠ «вторая точка запуска LLM не появилась»: дыру закрывает именно (f), а не подсчёт
Popen.
FR-2 — Таксономия классификации (BR-2)
Ровно 4 взаимоисключающих класса с определениями:
keep-LLM— нужно настоящее суждение; обязательно назвать конкретное суждение.replace-deterministic-now— безопасная детерминированная замена сейчас.replace-later/risky— замена возможна, но позже / с риском (нужны предпосылки).needs-hybrid-fallback— детерминированное ядро + LLM-фолбэк только на суждение.
Каждому call-site присвоен ровно один класс. Ожидаемое (из инвентаризации; финальное решение
фиксирует архитектор в ADR): analyst/architect/developer/reviewer → keep-LLM;
deployer → replace-deterministic-now или replace-later/risky (staging = exit-code-маппинг; прод
self-hosting уже детерминирован Phase A/B/C) — кандидат-замена по роли deployer;
tester → needs-hybrid-fallback (детерминированный прогон pytest+smoke, LLM-суждение только на
маппинг TC↔критерии / триаж падений) — кандидат-замена по роли tester;
deploy-finalizer/post-deploy-monitor → already-deterministic (вне таксономии замен, как эталон).
📌 Follow-up'ы — по роли, без Plane-ID (R3, NFR-6). Кандидаты обозначаются ролью (deployer-замена, tester-гибрid), а не конкретными ID. Привязка к будущему work item делается при заведении задачи; ORCH-118 ID не выдумывает.
FR-3 — Подтверждение детерминизма не-агентских путей (BR-3)
Карта отдельным разделом фиксирует, с file:line-доказательством, что НЕ консультируют LLM (не зависят
от суждения LLM ни через _spawn, ни иным транспортом): маршрутизация (advance_stage/
STAGE_TRANSITIONS), все QG_CHECKS/check_*, парсеры вердиктов (_parse_* через
frontmatter.parse_frontmatter), error_classifier (regex), под-гейты (security/merge/coverage/
image-freshness), self_deploy Phase A/B/C, reconciler/reaper/serial-gate/transition-lease. ⚠️ Эти
модули спавнят subprocess'ы (git/pytest/docker/ssh/сканеры) — это детерминированные
инструменты, не LLM-консультации (§0): доказательство детерминизма — отсутствие LLM-транспорта,
а не отсутствие subprocess. Любая найденная неожиданная LLM-консультация добавляется в инвентарь
(FR-1) и классифицируется (FR-2).
FR-4 — Упорядоченный roadmap замен (BR-4)
Ранжированный список кандидатов (названных по роли); для каждого: зависимости (предпосылки/блокеры),
оценка экономии токенов/времени (из agent_runs), риск безопасности, нужен ли hybrid-fallback,
ожидание kill-switch/обратимости, и тип будущей follow-up задачи по роли (без конкретного
Plane-ID — заводится отдельно, NFR-6). Явно: рекомендованный первый срез + обоснование (самый
низкорисковый, опирающийся на существующий прецедент D1/D2).
FR-5 — Политика использования LLM (BR-5)
Нормативный durable-документ: принцип «LLM — только где нужно настоящее суждение»; критерии решения keep vs replace (детерминируемость выхода, наличие machine-verdict, обратимость, влияние на автономность); требование к новым/изменённым control-path'ам обосновывать любое использование LLM против политики. Может включать рекомендацию reviewer-оси (как ORCH-079) — как требование, не как реализацию гейта (новый QG не вводится, FR-6 §QG).
FR-6 — Структурные анти-дрейф тесты (BR-6)
Новый offline-тест-файл (без сети/LLM/subprocess-к-модели), проверяющий инварианты карты. ⚠️ R4 —
инвариант формулируется вокруг LLM-консультации/транспорта, а не «существования процесса Claude CLI».
Дискриминатор тестов — «консультирует LLM», а не «спавнит subprocess»; десятки прочих subprocess
(git/pytest/docker/ssh/сканеры/staging_check.py) явно исключаются из матчинга, иначе тест
выродился бы в «подсчёт всех Popen».
- (a) Единственный транспорт. В
src/**ровно одна точка сборки/запуска Claude CLI (матчинг по совокупности признаков LLM-транспорта:CLAUDE_BIN+--system-prompt+Popen/bash -c), и этоlauncher._spawn. (Необходимое, но не достаточное условие — дополняется (f).) - (f) Отсутствие иного LLM-транспорта (новое, R4). В
src/**нет альтернативного транспорта LLM-консультации: ни импортаanthropic/openai/иного LLM-SDK, ни прямого HTTP-эндпоинта Anthropic/Claude (api.anthropic.com,/v1/messagesи т.п.), ни второго model-invoking subprocess-сборщика (другой бинарь с--system-prompt/--model). Это закрывает дыру «один_spawnзелёный, а рядом проросла новая консультация другим транспортом» — то, чего тест (a) в одиночку не ловит. Allowlist единственного разрешённого транспорта =S0. - (b) Нет консультации в детерминированных путях. Перечисленные детерминированные модули и
обработчики
D1/D2не консультируют LLM (не содержат ни_spawn-транспорта, ни альтернативного по (f)); их subprocess-вызовы инструментов LLM-консультацией не считаются. - (c) Карта перечисляет ровно те промпт-файлы, что физически лежат в
.openclaw/agents/(двусторонняя сверка — нет дрейфа). - (d) Классификация покрывает каждый перечисленный call-site ровно один раз (тотальность, без дублей/пропусков).
- (e) Capability ≠ consultation.
D1/D2действительно перехватываются вlaunch_jobдо_spawn→ занимают слот агента, но консультации LLM не происходит (эталон «процесс/слот есть — суждение не потребляется», §0.3).
❌ Не вводить тест, прибивающий карту к конкретным follow-up Plane-ID → ✅ тесты проверяют только инварианты, резолвящиеся в код/файлы репозитория (R3, NFR-6). Привязка к несуществующим ID была корнем отклонённой R2.
FR-7 — Скоуп-гард (BR-7)
Раннеры замен не реализуются в ORCH-118. Карта/roadmap явно помечают кандидатов по роли (deployer-замена, tester-гибрid) как follow-up, старт которых гейтится утверждением карты. Тест/диф не должны содержать новых детерминированных раннеров tester/deployer. Конкретные follow-up Plane-ID не фиксируются ни в одном артефакте (NFR-6).
4. Изменения API
Нет. (Опциональная read-only наблюдаемость в GET /queue/GET /metrics — вне скоупа ORCH-118;
если архитектор сочтёт полезным — отдельная аддитивная врезка, но не требуется этой задачей.)
5. Изменения схемы БД
Нет. (Источник оценок экономии — существующие колонки agent_runs: model/effort/токены/стоимость/
время; только чтение.)
6. Требования к новым/изменённым QG checks
Нет. QG_CHECKS / check_* / _parse_* / machine-verdict-ключи — байт-в-байт. Структурные тесты
FR-6 — обычные pytest-тесты, не Quality Gate и не стадия. Политика LLM (FR-5) — нормативный
документ, а не машинный гейт.
7. Совместимость / регресс
- Docs + tests only: рантайм
src/**не меняется → нулевая регрессия; enduro-trails не затронут; kill-switch не нужен (нет рантайм-поведения), как в ORCH-077/079/101/102/103/011. - Обратимость: артефакты — документы и тесты; откат = удаление/правка docs (рантайм-риска нет).
- Анти-дрейф: структурные тесты держат карту синхронной с кодом; норматив сопровождения — «менял места вызова LLM → обнови карту и политику в том же PR» (фиксируется в политике и golden-source docs).
- Анти-фабрикация (R3): артефакты фиксируют только проверяемые ссылки; follow-up'ы — по роли, без выдуманных Plane-ID (NFR-6).
- Self-hosting: не деплоит/не рестартит прод/не трогает
main— безопасно для общего инстанса.