analyst(ET): auto-commit from analyst run_id=725
All checks were successful
CI / test (push) Successful in 1m9s
All checks were successful
CI / test (push) Successful in 1m9s
This commit is contained in:
@@ -31,6 +31,50 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
> (deployer = кандидат на детерминированную замену, tester = кандидат на hybrid-fallback).
|
||||
> *(R1→R2 ранее «чинил» порядок этих ID; R3 убирает корень проблемы — фиксацию несуществующих ID.)*
|
||||
|
||||
> 🔁 **Revision R4 (2026-06-15) — единственный оставшийся блокер R3-ревью.** Рецензент подтвердил:
|
||||
> follow-up'ы по роли / TBD — ОК, `00-business-request.md=TBD` (конвенция репо) — НЕ блокер, скоуп
|
||||
> docs+tests — ОК; **менять их не нужно**. Закрывается **один** блокер: инвариант «места вызова LLM»
|
||||
> **смешивал** факт *«существует процесс Claude CLI / спавнится subprocess»* (транспорт/механизм) с
|
||||
> фактом *«на control-path происходит **LLM-консультация** — поток управления потребляет суждение
|
||||
> LLM»* (семантическая единица, ради которой и существует задача «replace avoidable **LLM** control
|
||||
> paths»). R4 **разводит** эти два понятия во всех артефактах (см. новый блок «Единица анализа» ниже,
|
||||
> уточнённые BR-1/BR-3/BR-6, FR-1/FR-3/FR-6, AC-1/AC-3/AC-6, TC-01/TC-02 + новый TC-12). Содержательная
|
||||
> классификация ролей и весь R3-материал (анти-фабрикация ID) — **без изменений**.
|
||||
|
||||
---
|
||||
|
||||
## 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`, код прямо помечает
|
||||
«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 матчинг).
|
||||
|
||||
---
|
||||
|
||||
## 1. Бизнес-контекст и проблема
|
||||
@@ -42,9 +86,13 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
Установленный факт по текущему коду (инвентаризация — §1 TRZ, артефакт-карта):
|
||||
|
||||
- В оркестраторе **ровно одна точка запуска LLM** — `src/agents/launcher.py::_spawn` (одна
|
||||
`subprocess.Popen` сборка Claude CLI: `CLAUDE_BIN --print … --system-prompt "$(cat …)"`), которой
|
||||
- В оркестраторе **единственный транспорт 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).
|
||||
- **Все остальные control-path'ы уже детерминированы (без LLM):** маршрутизация стадий
|
||||
(`STAGE_TRANSITIONS`/`advance_stage`), все Quality Gate'ы и под-гейты (`check_*`, security/merge/
|
||||
coverage/image-freshness), парсеры вердиктов (`_parse_*` через `frontmatter.py`), классификатор
|
||||
@@ -78,8 +126,9 @@ ORCH-118 даёт **доказательную карту** «где LLM дей
|
||||
**по роли** (follow-up ID — TBD).
|
||||
- **BR-5** Нормативная **политика использования LLM** («LLM — только там, где нужно настоящее
|
||||
суждение») как durable-документ.
|
||||
- **BR-6** Структурные regression-тесты, **прибивающие инварианты карты к коду** (единственная точка
|
||||
запуска; детерминированные модули не несут запуска LLM; карта покрывает все промпты; тотальность
|
||||
- **BR-6** Структурные regression-тесты, **прибивающие инварианты карты к коду** (транспорт-агностичный
|
||||
двусторонний инвариант: единственный транспорт LLM-консультации `_spawn` **и** отсутствие иного
|
||||
LLM-транспорта; детерминированные модули не консультируют LLM; карта покрывает все промпты; тотальность
|
||||
классификации) — анти-дрейф.
|
||||
- **BR-7** Явно позиционировать **роль deployer** и **роль tester** как **кандидаты-follow-up** для
|
||||
детерминированной замены — **по роли, без привязки к конкретным Plane-ID** (см. NFR-6).
|
||||
@@ -106,11 +155,14 @@ ORCH-118 даёт **доказательную карту** «где LLM дей
|
||||
|
||||
## 4. Бизнес-требования (BR)
|
||||
|
||||
- **BR-1 — Инвентарь call-site'ов LLM.** Выпустить durable-документ, перечисляющий **каждое** место,
|
||||
где LLM вызывается или может быть вызван: единственную точку `_spawn`, все 6 ролей-агентов и обе
|
||||
зарезервированные детерминированные job-роли (как доказательство «уже без LLM»). Для каждого —
|
||||
`file:line`, триггер, стадия/владелец, выходной артефакт, machine-verdict-ключ (если есть), оценка
|
||||
токенов/времени. Проверяемо: каждый `file:line` резолвится в реальный код.
|
||||
- **BR-1 — Инвентарь LLM-консультаций (call-site'ов).** Выпустить durable-документ, перечисляющий
|
||||
**каждое** место, где control-path **потребляет суждение LLM** или может его потребить (единица —
|
||||
*LLM-консультация*, §0, а не «спавн процесса»): единственный транспорт `_spawn`, все 6 ролей-агентов
|
||||
и обе зарезервированные job-роли `D1/D2` (включаются как доказательство «слот агента есть, но
|
||||
консультации LLM нет» — перехват до `_spawn`). Для каждого — `file:line`, триггер, стадия/владелец,
|
||||
выходной артефакт, machine-verdict-ключ (если есть), оценка токенов/времени, **признак
|
||||
capability-vs-consultation** (LLM-capable vs фактически консультирует, §0.3). Проверяемо: каждый
|
||||
`file:line` резолвится в реальный код.
|
||||
- **BR-2 — Классификация.** Каждому call-site присвоить **ровно один** класс из таксономии:
|
||||
`keep-LLM` (нужно настоящее суждение), `replace-deterministic-now` (безопасная замена сейчас),
|
||||
`replace-later/risky` (замена позже / рискованно), `needs-hybrid-fallback` (детерминированное ядро +
|
||||
@@ -118,8 +170,10 @@ ORCH-118 даёт **доказательную карту** «где LLM дей
|
||||
сохраняется.
|
||||
- **BR-3 — Подтверждение детерминизма не-агентских путей.** Документально, с `file:line`-доказательством,
|
||||
зафиксировать, что маршрутизация стадий, ретраи, QG-проверки, парсеры вердиктов и finalizer'ы **не
|
||||
вызывают LLM**. Если инвентаризация найдёт неожиданный LLM-путь — он попадает в карту и
|
||||
классификацию.
|
||||
консультируют LLM** (не зависят от суждения LLM — ни через `_spawn`, ни через иной транспорт; их
|
||||
subprocess-вызовы git/pytest/docker/ssh/сканеров — детерминированные инструменты, не LLM, §0). Если
|
||||
инвентаризация найдёт неожиданную LLM-консультацию — она попадает в карту (BR-1) и классификацию
|
||||
(BR-2).
|
||||
- **BR-4 — Упорядоченный roadmap.** Ранжированный план замен: для каждого кандидата (названного **по
|
||||
роли**) — зависимости, **оценка** экономии токенов/времени (из телеметрии `agent_runs`), риск
|
||||
безопасности, нужен ли hybrid-fallback, ожидание kill-switch/обратимости. Явно указать
|
||||
@@ -128,9 +182,15 @@ ORCH-118 даёт **доказательную карту** «где LLM дей
|
||||
- **BR-5 — Политика использования LLM.** Нормативный durable-документ: «LLM — только там, где требуется
|
||||
настоящее суждение»; критерии решения keep vs replace; требование к новым/изменённым control-path'ам
|
||||
обосновывать любое использование LLM против этой политики.
|
||||
- **BR-6 — Анти-дрейф структурными тестами.** Тесты, привязывающие инварианты карты к коду:
|
||||
единственная точка запуска LLM; перечисленные детерминированные модули/job-роли не несут запуска;
|
||||
карта перечисляет ровно те 6 промптов, что лежат в `.openclaw/agents/`; классификация покрывает все
|
||||
- **BR-6 — Анти-дрейф структурными тестами.** Тесты, привязывающие инварианты карты к коду. Инвариант
|
||||
единственной точки формулируется **транспорт-агностично и двусторонне** (R4, §0): (i) единственный
|
||||
транспорт LLM-консультации в `src/**` — `_spawn`; **и** (ii) **отсутствует любой иной LLM-транспорт**
|
||||
(импорт `anthropic`/`openai`/LLM-SDK, прямой HTTP-эндпоинт Anthropic/Claude, второй model-invoking
|
||||
subprocess-сборщик `--system-prompt`/`--model`) — это и закрывает дыру «один `_spawn` зелёный, а
|
||||
рядом проросла новая консультация другим транспортом». Дискриминатор теста — **«консультирует LLM»,
|
||||
а не «спавнит subprocess»** (прочие subprocess git/pytest/docker/ssh/сканеров явно исключены из
|
||||
матчинга). Плюс: перечисленные детерминированные модули/job-роли не несут LLM-консультации; карта
|
||||
перечисляет ровно те 6 промптов, что лежат в `.openclaw/agents/`; классификация покрывает все
|
||||
call-site'ы по одному разу. Тесты — offline (без сети/LLM/subprocess-к-модели). **Тест на привязку
|
||||
к конкретным follow-up ID не вводится** (анти-паттерн: прибивал бы карту к непроверяемым ID, R3).
|
||||
- **BR-7 — Позиционирование follow-up'ов по роли.** Карта/roadmap явно отмечают **роль deployer** и
|
||||
@@ -168,11 +228,15 @@ ORCH-118 даёт **доказательную карту** «где LLM дей
|
||||
поэтому ID не фиксируются (NFR-6).
|
||||
|
||||
## 7. Критерии успеха
|
||||
Карта call-site'ов полна и привязана к коду; каждый site классифицирован с обоснованием; детерминизм
|
||||
не-агентских путей доказан; есть упорядоченный roadmap с зависимостями/экономией/рисками и
|
||||
Карта LLM-консультаций полна и привязана к коду, и **разводит транспорт/слот («процесс Claude CLI
|
||||
существует») от факта консультации («поток управления потребляет суждение LLM»)** (R4, §0); каждый
|
||||
site классифицирован с обоснованием; детерминизм не-агентских путей доказан (отсутствием LLM-консультации,
|
||||
не отсутствием subprocess); есть упорядоченный roadmap с зависимостями/экономией/рисками и
|
||||
рекомендованным первым срезом (кандидаты — по роли); есть нормативная политика; структурные тесты
|
||||
зелёные и осмысленные; ни один рантайм-инвариант не тронут; раннеры замен НЕ реализованы; ни один
|
||||
артефакт не фиксирует непроверяемых follow-up ID. Детальные PASS/FAIL — в `03-acceptance-criteria.md`.
|
||||
зелёные и осмысленные — инвариант единственной точки **транспорт-агностичен и двусторонен** (единственный
|
||||
транспорт `_spawn` **и** отсутствие иного LLM-транспорта); ни один рантайм-инвариант не тронут; раннеры
|
||||
замен НЕ реализованы; ни один артефакт не фиксирует непроверяемых follow-up ID. Детальные PASS/FAIL —
|
||||
в `03-acceptance-criteria.md`.
|
||||
|
||||
## 8. Риски
|
||||
- **Недо-/пере-классификация** (LLM убран там, где нужно суждение, или сохранён там, где не нужен) →
|
||||
|
||||
@@ -22,6 +22,11 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
> 📌 **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.
|
||||
|
||||
---
|
||||
|
||||
@@ -35,17 +40,21 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
Опорный факт инвентаризации (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 не запускается) |
|
||||
> Единица — **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`/
|
||||
@@ -73,13 +82,18 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
## 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-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 взаимоисключающих класса с определениями:
|
||||
@@ -101,12 +115,15 @@ self-hosting уже детерминирован Phase A/B/C) — **кандид
|
||||
> заведении задачи; 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).
|
||||
Карта отдельным разделом фиксирует, с `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)
|
||||
Ранжированный список кандидатов (названных **по роли**); для каждого: зависимости (предпосылки/блокеры),
|
||||
@@ -123,15 +140,30 @@ keep vs replace (детерминируемость выхода, наличие
|
||||
реализацию гейта** (новый 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.
|
||||
Новый 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)** `D1/D2` действительно перехватываются в `launch_job` **до** `_spawn` (детерминированы).
|
||||
- **(e) Capability ≠ consultation.** `D1/D2` действительно перехватываются в `launch_job` **до**
|
||||
`_spawn` → занимают слот агента, но **консультации LLM не происходит** (эталон «процесс/слот есть —
|
||||
суждение не потребляется», §0.3).
|
||||
|
||||
> ❌ **Не вводить** тест, прибивающий карту к конкретным follow-up Plane-ID → ✅ тесты проверяют
|
||||
> только инварианты, резолвящиеся в код/файлы репозитория (R3, NFR-6). Привязка к несуществующим ID
|
||||
|
||||
@@ -18,16 +18,23 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
---
|
||||
|
||||
## AC-1 — Полнота и привязка инвентаря call-site'ов
|
||||
## AC-1 — Полнота и привязка инвентаря LLM-консультаций
|
||||
|
||||
**Условие:** Документ-карта перечисляет каждый LLM-capable call-site с обязательными полями, привязанными к коду.
|
||||
- **PASS:** Карта содержит `S0` (`launcher._spawn` — единственная точка запуска), все 6 ролей
|
||||
(analyst/architect/developer/reviewer/tester/deployer) и обе детерминированные job-роли
|
||||
(deploy-finalizer/post-deploy-monitor); у каждой записи заполнены `location (file:line)` / `trigger` /
|
||||
`stage/owner` / `output` / `machine-verdict key (если есть)` / `est. tokens-runtime` /
|
||||
`classification` / `rationale`; каждый `file:line` резолвится в реальный код.
|
||||
- **FAIL:** Пропущен любой LLM-capable site; отсутствует любое обязательное поле; `file:line` не
|
||||
резолвится; заявлена «вторая точка запуска LLM», не подтверждённая кодом.
|
||||
**Условие:** Документ-карта перечисляет каждый call-site, где control-path потребляет (или способен
|
||||
потребить) суждение LLM — **единица = LLM-консультация, не «спавн процесса»** (R4) — с обязательными
|
||||
полями, привязанными к коду.
|
||||
- **PASS:** Карта содержит `S0` (`launcher._spawn` — **единственный транспорт LLM-консультации**), все
|
||||
6 ролей (analyst/architect/developer/reviewer/tester/deployer, консультируют через S0) и обе job-роли
|
||||
(deploy-finalizer/post-deploy-monitor, помеченные **«занимают слот агента, но LLM не консультируют»** —
|
||||
перехват до `_spawn`); у каждой записи заполнены `location (file:line)` / `trigger` / `stage/owner` /
|
||||
`output` / `machine-verdict key (если есть)` / `est. tokens-runtime` / **`consults-LLM`
|
||||
(consultation vs LLM-capable transport/slot)** / `classification` / `rationale`; каждый `file:line`
|
||||
резолвится в реальный код. Карта явно разводит «транспорт/слот существует» и «LLM фактически
|
||||
консультируется» (§0 BRD).
|
||||
- **FAIL:** Пропущен любой call-site; отсутствует любое обязательное поле (включая `consults-LLM`);
|
||||
`file:line` не резолвится; карта смешивает «процесс Claude CLI существует» с «LLM-консультация
|
||||
происходит» (напр. помечает `D1/D2` консультирующими LLM, или называет `_spawn` «точкой запуска» без
|
||||
оговорки транспорт-vs-консультация); заявлен второй транспорт LLM, не подтверждённый кодом.
|
||||
|
||||
---
|
||||
|
||||
@@ -44,13 +51,16 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
## AC-3 — Доказанный детерминизм не-агентских путей
|
||||
|
||||
**Условие:** Карта отдельно фиксирует, что control-path'ы вне 6 агентов не вызывают LLM, с доказательством.
|
||||
**Условие:** Карта отдельно фиксирует, что control-path'ы вне 6 агентов не консультируют LLM, с доказательством.
|
||||
- **PASS:** Перечислены маршрутизация (`advance_stage`/`STAGE_TRANSITIONS`), все `QG_CHECKS`/`check_*`,
|
||||
парсеры `_parse_*`, `error_classifier`, под-гейты (security/merge/coverage/image-freshness),
|
||||
`self_deploy` Phase A/B/C, reconciler/reaper/serial-gate/transition-lease — каждый с `file:line`,
|
||||
подтверждающим отсутствие вызова LLM.
|
||||
подтверждающим отсутствие **LLM-консультации** (ни `_spawn`-транспорта, ни альтернативного). Их
|
||||
subprocess-вызовы инструментов (`git`/`pytest`/`docker`/`ssh`/сканеры) явно квалифицированы как
|
||||
**не-LLM** (детерминизм доказывается отсутствием LLM-транспорта, а не отсутствием subprocess).
|
||||
- **FAIL:** Утверждение о детерминизме без `file:line`-доказательства; путь, заявленный
|
||||
детерминированным, фактически запускает LLM (и это не отражено в инвентаре/классификации).
|
||||
детерминированным, фактически консультирует LLM (и это не отражено в инвентаре/классификации); либо
|
||||
детерминизм «доказан» простым отсутствием subprocess (подмена дискриминатора, §0).
|
||||
|
||||
---
|
||||
|
||||
@@ -80,15 +90,24 @@ Work Item: **ORCH-118** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
## AC-6 — Структурные анти-дрейф тесты: зелёные и осмысленные
|
||||
|
||||
**Условие:** Новый offline-тест-файл прибивает инварианты карты к коду.
|
||||
- **PASS:** Тесты проверяют: (a) единственную точку запуска LLM в `src/**` (= `launcher._spawn`);
|
||||
(b) отсутствие запуска LLM в перечисленных детерминированных модулях и в обработчиках
|
||||
**Условие:** Новый offline-тест-файл прибивает инварианты карты к коду; инвариант сформулирован вокруг
|
||||
**LLM-консультации/транспорта**, а не «существования процесса Claude CLI» (R4).
|
||||
- **PASS:** Тесты проверяют: (a) единственный транспорт LLM-консультации в `src/**` (= `launcher._spawn`);
|
||||
**(f) отсутствие любого иного LLM-транспорта** (нет импорта `anthropic`/`openai`/LLM-SDK, нет прямого
|
||||
HTTP-эндпоинта Anthropic/Claude, нет второго model-invoking subprocess-сборщика `--system-prompt`/
|
||||
`--model`) — именно (f), а не (a), закрывает «вторую консультацию другим транспортом»;
|
||||
(b) отсутствие LLM-консультации в перечисленных детерминированных модулях и в обработчиках
|
||||
deploy-finalizer/post-deploy-monitor; (c) двустороннюю сверку списка промптов карты с
|
||||
`.openclaw/agents/`; (d) тотальность классификации (каждый site ровно один раз); (e) перехват
|
||||
`D1/D2` в `launch_job` до `_spawn`. Тесты не используют сеть/LLM/subprocess-к-модели. Полный
|
||||
`pytest tests/ -q` — зелёный.
|
||||
- **FAIL:** Тестов нет; тест тривиально проходит (не привязан к коду); любой тест красный; полный
|
||||
прогон `tests/` падает; введён тест, прибивающий карту к конкретным follow-up Plane-ID (анти-паттерн R3).
|
||||
`D1/D2` в `launch_job` до `_spawn` (слот агента без консультации LLM — capability ≠ consultation).
|
||||
Дискриминатор тестов — **«консультирует LLM», а не «спавнит subprocess»**: прочие subprocess
|
||||
(`git`/`pytest`/`docker`/`ssh`/сканеры) явно исключены из матчинга. Тесты не используют сеть/LLM/
|
||||
subprocess-к-модели. Полный `pytest tests/ -q` — зелёный.
|
||||
- **FAIL:** Тестов нет; тест тривиально проходит (не привязан к коду); инвариант проверяет лишь «один
|
||||
`Popen` Claude CLI» **без** проверки (f) отсутствия альтернативного LLM-транспорта (конфлация
|
||||
«процесс существует» ↔ «единственная консультация» — корень блокера R4); тест выродился в «подсчёт
|
||||
всех subprocess» (ловит git/pytest/docker как LLM); любой тест красный; полный прогон `tests/` падает;
|
||||
введён тест, прибивающий карту к конкретным follow-up Plane-ID (анти-паттерн R3).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,30 +7,41 @@ model_used: claude-opus-4-8
|
||||
title: "LLM call-site inventory + classification + roadmap + usage policy (inventory-first, docs+tests only)"
|
||||
framework: pytest
|
||||
scope: >
|
||||
Покрываются СТРУКТУРНЫЕ инварианты карты вызовов LLM и анти-дрейф (FR-6), плюс скоуп-гард
|
||||
Покрываются СТРУКТУРНЫЕ инварианты карты LLM-консультаций и анти-дрейф (FR-6), плюс скоуп-гард
|
||||
(рантайм-контракты не тронуты, раннеры не реализованы) и анти-фабрикация ссылок/ID (TC-11).
|
||||
ВНЕ покрытия: реализация детерминированных раннеров deployer / tester — отдельные follow-up
|
||||
задачи (именуются по роли; конкретные Plane-ID в ORCH-118 не фиксируются, R3/NFR-6).
|
||||
Единица — LLM-КОНСУЛЬТАЦИЯ (control-path потребляет суждение LLM), а не «спавн процесса / Claude
|
||||
CLI существует» (R4, BRD §0). Инвариант единственной точки — транспорт-агностичный и двусторонний:
|
||||
TC-01 (единственный транспорт = _spawn) + TC-12 (отсутствует иной LLM-транспорт). ВНЕ покрытия:
|
||||
реализация детерминированных раннеров deployer / tester — отдельные follow-up задачи (именуются по
|
||||
роли; конкретные Plane-ID в ORCH-118 не фиксируются, R3/NFR-6).
|
||||
notes: >
|
||||
Все тесты детерминированы и offline: без сети, без запуска LLM, без subprocess-к-модели.
|
||||
Имена файла теста и документов карты — примерные (финально решает архитектор); тест-кейсы
|
||||
привязываются к фактическим путям артефактов, выбранным в 06-adr. Полный регресс tests/
|
||||
должен оставаться зелёным (TC-10). Регрессом считается: появление второй точки запуска LLM,
|
||||
запуск LLM в детерминированном модуле, дрейф карты относительно .openclaw/agents/, изменение
|
||||
рантайм-контрактов (STAGE_TRANSITIONS / QG_CHECKS / check_* / machine-verdict / схема БД).
|
||||
должен оставаться зелёным (TC-10). Дискриминатор всех structural-тестов — "консультирует LLM",
|
||||
а НЕ "спавнит subprocess": прочие subprocess (git/pytest/docker/ssh/сканеры/staging_check.py) явно
|
||||
исключаются из матчинга, иначе тест выродился бы в подсчёт всех Popen. Регрессом считается:
|
||||
появление второго ТРАНСПОРТА LLM-консультации (новый _spawn ИЛИ импорт anthropic/openai/LLM-SDK ИЛИ
|
||||
прямой HTTP Anthropic/Claude ИЛИ второй model-invoking subprocess), LLM-консультация в
|
||||
детерминированном модуле, дрейф карты относительно .openclaw/agents/, изменение рантайм-контрактов
|
||||
(STAGE_TRANSITIONS / QG_CHECKS / check_* / machine-verdict / схема БД).
|
||||
R4 (единственный блокер R3-ревью): инвариант "места вызова LLM" разведён на ТРАНСПОРТ ("процесс
|
||||
Claude CLI существует") и КОНСУЛЬТАЦИЮ ("поток управления потребляет суждение LLM"); TC-01 уточнён
|
||||
(необходимое, но не достаточное), добавлен TC-12 (no-alternative-transport), TC-02 уточнён по
|
||||
дискриминатору, TC-06 закрепляет capability ≠ consultation (D1/D2 — слот без консультации).
|
||||
R3: тест на привязку follow-up'ов к конкретным Plane-ID УДАЛЁН (бывш. TC-11) как анти-паттерн —
|
||||
прибивал карту к несуществующим ID; вместо него TC-11 проверяет анти-фабрикацию (ID не выдуманы).
|
||||
|
||||
tests:
|
||||
- id: TC-01
|
||||
type: unit
|
||||
description: "Единственная точка запуска LLM: ровно одно место в src/** собирает/запускает Claude CLI (CLAUDE_BIN + --system-prompt + Popen/bash -c), и это launcher._spawn (FR-6a / AC-1)"
|
||||
description: "Единственный ТРАНСПОРТ LLM-консультации: ровно одно место в src/** собирает/запускает Claude CLI (матчинг по совокупности признаков LLM-транспорта CLAUDE_BIN + --system-prompt + Popen/bash -c), и это launcher._spawn. Необходимое, но НЕ достаточное условие — дополняется TC-12 (отсутствие иного транспорта); сам по себе подсчёт _spawn не доказывает 'единственная LLM-консультация' (R4 / FR-6a / AC-1)"
|
||||
module: tests/test_llm_call_site_inventory.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-02
|
||||
type: unit
|
||||
description: "Детерминированные модули без LLM: перечисленные leaf'ы (serial_gate, merge_gate, coverage_gate, security_gate, staging_verdict, review_parse, error_classifier, frontmatter, self_deploy, post_deploy, transition_lease, reconciler, job_reaper) не содержат запуска Claude CLI (FR-6b / AC-3)"
|
||||
description: "Детерминированные модули без LLM-консультации: перечисленные leaf'ы (serial_gate, merge_gate, coverage_gate, security_gate, staging_verdict, review_parse, error_classifier, frontmatter, self_deploy, post_deploy, transition_lease, reconciler, job_reaper) не консультируют LLM (нет ни _spawn-транспорта, ни альтернативного по TC-12); их subprocess-вызовы git/pytest/docker/ssh/сканеров LLM-консультацией НЕ считаются — дискриминатор 'консультирует LLM', а не 'спавнит subprocess' (R4 / FR-6b / AC-3)"
|
||||
module: tests/test_llm_call_site_inventory.py
|
||||
expected: PASS
|
||||
|
||||
@@ -54,7 +65,7 @@ tests:
|
||||
|
||||
- id: TC-06
|
||||
type: unit
|
||||
description: "Детерминированные job-роли: launch_job перехватывает deploy-finalizer и post-deploy-monitor ДО _spawn (LLM не запускается) — эталон паттерна замены (FR-6e / AC-3)"
|
||||
description: "Capability ≠ consultation: launch_job перехватывает deploy-finalizer и post-deploy-monitor ДО _spawn — job занимает слот агента, но LLM НЕ консультируется (процесс/слот существует, суждение не потребляется) — эталон паттерна замены и прямая иллюстрация R4-различия (FR-6e / AC-3)"
|
||||
module: tests/test_llm_call_site_inventory.py
|
||||
expected: PASS
|
||||
|
||||
@@ -87,3 +98,9 @@ tests:
|
||||
description: "Анти-фабрикация follow-up ID (R3 / NFR-6 / AC-9): документы карты/roadmap НЕ содержат привязки кандидатов-замен к конкретным follow-up Plane-ID несуществующих work item (паттерн ORCH-1\\d\\d, не равный самому ORCH-118 и не присутствующий в docs/work-items/); кандидаты именуются по роли. Заменяет ошибочный mapping-тест R2, прибивавший карту к выдуманным ID."
|
||||
module: tests/test_llm_determinization_docs.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-12
|
||||
type: unit
|
||||
description: "Отсутствие иного LLM-транспорта (R4 / FR-6f / AC-1, AC-6): в src/** НЕТ альтернативного транспорта LLM-консультации помимо _spawn — ни импорта anthropic/openai/иного LLM-SDK, ни прямого HTTP-эндпоинта Anthropic/Claude (api.anthropic.com, /v1/messages), ни второго model-invoking subprocess-сборщика (другой бинарь с --system-prompt/--model). Закрывает дыру 'один _spawn зелёный, а рядом проросла новая консультация другим транспортом', которую TC-01 в одиночку не ловит. Allowlist единственного разрешённого транспорта = S0/launcher._spawn."
|
||||
module: tests/test_llm_call_site_inventory.py
|
||||
expected: PASS
|
||||
|
||||
Reference in New Issue
Block a user