169 lines
16 KiB
Markdown
169 lines
16 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
|
||
---
|
||
|
||
# 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 присваивается при заведении задачи.
|
||
|
||
---
|
||
|
||
## 1. Сводка изменения
|
||
|
||
Выпустить **доказательную карту** всех мест вызова LLM в оркестраторе с классификацией и
|
||
упорядоченным roadmap'ом детерминированных замен, а также нормативную **политику использования LLM**;
|
||
прибить инварианты карты к коду набором **структурных тестов**. Реализация замен не входит. Все
|
||
рантайм-контракты (`STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict-ключи / схема БД) —
|
||
**не меняются**.
|
||
|
||
Опорный факт инвентаризации (ground-truth кода на момент задачи; line-привязки уточняет карта):
|
||
|
||
| # | Call-site (LLM-capable) | Где | Что делает |
|
||
|---|--------------------------|-----|------------|
|
||
| S0 | **Единственная точка запуска** | `src/agents/launcher.py::_spawn` (сборка `CLAUDE_BIN --print … --system-prompt "$(cat …)"` + `subprocess.Popen`) | запускает любую из 6 ролей |
|
||
| A1 | analyst | промпт `.openclaw/agents/analyst.md`, стадия `analysis` | анализ бизнес-запроса → 01–04 |
|
||
| A2 | architect | `.openclaw/agents/architect.md`, стадия `architecture` | архитектурные решения → 06-adr |
|
||
| A3 | developer | `.openclaw/agents/developer.md`, стадия `development` | реализация + PR |
|
||
| A4 | reviewer | `.openclaw/agents/reviewer.md`, стадия `review` | ревью → `12-review.md` (`verdict:`) |
|
||
| A5 | tester | `.openclaw/agents/tester.md`, стадия `testing` | `pytest`+smoke → `13-test-report.md` (`result:`) |
|
||
| A6 | deployer | `.openclaw/agents/deployer.md`, стадии `deploy-staging`/`deploy` | `staging_check.py`/exit-code → `15`/`14` логи |
|
||
| D1 | deploy-finalizer | `launch_job` перехват **до** `_spawn` (`launcher.launch_job`) | детерминированный (LLM не запускается) |
|
||
| D2 | post-deploy-monitor | `launch_job` перехват **до** `_spawn` (`launcher.launch_job`) | детерминированный (LLM не запускается) |
|
||
|
||
> Не-агентские control-path'ы (маршрутизация `advance_stage`, `QG_CHECKS`/`check_*`/`_parse_*`,
|
||
> `error_classifier`, `serial_gate`/`merge_gate`/`coverage_gate`/`security_gate`/`staging_verdict`/
|
||
> `review_parse`/`frontmatter`, `self_deploy` Phase 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 — Полнота и привязка инвентаря (BR-1)
|
||
Карта перечисляет **каждый** LLM-capable call-site: `S0` (единственный `_spawn`), `A1…A6` (6 ролей),
|
||
`D1/D2` (детерминированные job-роли — как доказательство паттерна). Поля записи: `id`, `location`
|
||
(`file:line`), `trigger`, `stage/owner`, `output artifact`, `machine-verdict key` (если есть),
|
||
`est. tokens/runtime`, `classification`, `rationale`, `dependency`, `risk`. Каждый `file:line`
|
||
обязан резолвиться в реальный код. Инвариант: иных мест запуска LLM в `src/**`, кроме `S0`, нет — и
|
||
это подтверждается тестом FR-6(a).
|
||
|
||
### 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:
|
||
маршрутизация (`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. Любой найденный неожиданный 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-к-модели), проверяющий инварианты карты:
|
||
- **(a)** В `src/**` ровно **одна** точка сборки/запуска Claude CLI (поиск по `CLAUDE_BIN` +
|
||
`--system-prompt` + `Popen`/`bash -c`), и это `launcher._spawn`.
|
||
- **(b)** Перечисленные детерминированные модули и обработчики `D1/D2` **не** содержат запуска LLM.
|
||
- **(c)** Карта перечисляет ровно те промпт-файлы, что физически лежат в `.openclaw/agents/`
|
||
(двусторонняя сверка — нет дрейфа).
|
||
- **(d)** Классификация покрывает каждый перечисленный call-site **ровно один раз** (тотальность,
|
||
без дублей/пропусков).
|
||
- **(e)** `D1/D2` действительно перехватываются в `launch_job` **до** `_spawn` (детерминированы).
|
||
|
||
> ❌ **Не вводить** тест, прибивающий карту к конкретным 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` — безопасно для общего инстанса.
|