13 KiB
verdict, work_item, stage, author_agent, status, created_at, model_used, type, work_item_id, version
| verdict | work_item | stage | author_agent | status | created_at | model_used | type | work_item_id | version |
|---|---|---|---|---|---|---|---|---|---|
| APPROVED | ORCH-116 | review | reviewer | approved | 2026-06-16 | claude-opus-4-8 | review | ORCH-116 | 2 |
Review ORCH-116 — детерминированный test-раннер вместо LLM-тестера
Summary
PR заменяет LLM-агента tester на стадии testing (self-hosting orchestrator) детерминированным
leaf src/test_runner.py, перехватываемым в launch_job до _spawn — точное зеркало уже
работающего в проде ORCH-115/staging_runner. Проверено независимо по всем четырём осям
(соответствие ТЗ/AC, соответствие ADR, качество кода, документация) с самостоятельным прогоном
тестов. Все 15 критериев приёмки выполнены; критический инвариант NFR-1 («замена продюсера
артефакта, не гейта») соблюдён байт-в-байт (только 4 файла в src/, stages.py/qg/checks.py не
тронуты); документация = golden source обновлена в том же PR. Полный регресс проверен лично:
pytest tests/ -q → 2137 passed; ORCH-116 + LLM-анти-дрейф + system-docs → 74 passed. P0/P1
findings отсутствуют → APPROVED.
Оси проверки
1. Соответствие ТЗ / Acceptance Criteria — PASS
Верифицировано по коду + тестам + личному прогону каждое AC:
- AC-1 (перехват до
_spawn) —launcher.launch_job:if job.get("agent")=="tester" and test_runner.should_intercept(job): return self._run_test_runner_job(job);_run_test_runner_jobведётjobsчерезmark_job, возвращаетNone(нетagent_runs). TC-05 воспроизводит без CLI. - AC-2 (контракт
13-test-report.md) —build_test_reportэмититresult: PASS|FAILUPPERCASE- полную 52c-схему; читается неизменённым
_parse_tests_verdict(TC-04, лично подтверждено).
- полную 52c-схему; читается неизменённым
- AC-3 (exit→verdict) —
map_exit_code_to_result— тонкий транслятор над единымself_deploy.map_exit_code_to_status(0→PASS, иначе/None/нечисло→FAIL); второй маппинг не введён (TC-02). - AC-4 (эквивалентность маршрутизации) —
_advance(finished_agent="tester", current_stage="testing"), без новых рёбер; PASS→advance, FAIL→существующий откатtesting→development(TC-07/TC-10). - AC-5 (two-level outcome) —
run_test_gate:suite_ran = returncode is not None and not timed_out; tool-error → bounded DEFER re-queuetester-джоба (TC-10 проверяетagent == "tester"), не код-фейл-откат, не жжёт developer-retry. - AC-6 (анти-дрейф) —
git diffпоsrc/затрагивает толькоlauncher.py/config.py/main.py/test_runner.py;src/stages.pyиsrc/qg/checks.pyбайт-в-байт не тронуты (провереноgit diffлично); новых таблиц нет (TC-09). - AC-7/AC-8 (kill-switch / backward-compat) —
applies()гасит приenabled=False, скоупит CSV, и_has_test_contract→Falseдля не-self репо даже при ручном добавлении в CSV (TC-01/TC-08). - AC-9 (never-raise) — все публичные функции в
try/except;run_test_gateне роняет воркер (TC-11). - AC-10 (self-hosting safety) —
build_test_commandбез литералов рестарта/compose/build/force-push/.env; smoke строго read-only GET (TC-13). - AC-11 (proc_group/worktree/timeout) — pytest в
get_worktree_pathчерезrun_in_process_group,_resolve_timeoutдефолтит на малформе (TC-12). - AC-12/AC-13/AC-14/AC-15 — гибрид off-control-path, блок
test_runnerв/queue, обновление LLM-карты/политики/витрины, полный регресс — все зелёные (AC-15 проверен личным прогоном).
2. Соответствие ADR — PASS
Реализация дословно следует ADR-001 (D1–D12) и сквозному adr-0049. Ключевые места сверены:
- D6.1 (анти-коллизия 52c-
status:↔_parse_tests_verdict) — корректно и проверено против неизменённого парсера (src/qg/checks.py:263-277):result: PASS → status: success(конкатенация"SUCCESS PASS"— нет негативного токена, позитивPASSизresult:→True);result: FAIL → status: failed("FAILED FAIL"— негативный токен →False). Вbuild_test_reportжёстко:sub_status = "success" if result == "PASS" else "failed". Прибито TC-04/test_tc04_status_field_never_false_negatives_a_pass. Самая тонкая мина задачи — снята верно. - D5 DEFER — зеркало
staging_runner._handle_tool_error, но re-queuetester-джоба (неdeployer) — проверено TC-10. Счётчик restart-safe по маркеруtest-runner infra-retryвtask_content, без правки схемы БД. - Трассировка маркеров (TRACEABILITY): правки рядом с ORCH-115 (
launcher), ORCH-114 (transition-lease берётся внутриadvance_stage— раннер не трогает, граница O1), ORCH-110 (proc_groupпереиспользуется как есть) — ни один зафиксированный инвариант не сломан. - Глобальные ADR (INV-4 «мерж только через PR», запрет рестарта прод-контейнера) — соблюдены: лог
пушится только в фичеветку, никакой работы с
main.
3. Качество кода — PASS
- Docstrings на всех публичных функциях; контракт never-raise выдержан сквозно (каждый внешний вызов
обёрнут; наблюдательные счётчики через
_bumpне ломают решение). - Тесты содержательные (32 тест-функции, не тривиальные): kill-switch/scope/contract, маппинг по классам входа, рендер+парсер, перехват, two-level outcome, never-raise, timeout, smoke read-only (включая транзиент-ретрай и missing-serial_gate), анти-дрейф, наблюдаемость.
- Сигнатуры зависимостей сверены лично (риск latent false-FAIL устранён):
db.enqueue_job(..., task_id=, available_at_delay_s=),db.mark_job,self_deploy.map_exit_code_to_status,git_worktree.get_worktree_path(repo, branch),qg.checks.is_self_hosting_repo,config.post_deploy_base_url(дефолтhttp://localhost:8500) — все существуют ровно как используются. - Security: smoke — только
urllibGET к локальному оркестратору; мутирующих запросов нет. - Это не багфикс-трек (стадия
architectureотработана, full-cycle) → требование регресс-фиксатора ORCH-019/BR-4 неприменимо; тем не менее покрытие исчерпывающее.
4. Документация — PASS (обязательная проверка)
src/ изменён → документация обновлена в том же PR, проверено явно по git diff:
- Паспорт
CLAUDE.md— новый раздел «Детерминированный test-раннер (ORCH-116)». - Компонент-карта
docs/architecture/README.md— запись Test-runner + блок roadmap «второй срез реализован». - Внутренности
docs/architecture/internals.md— примечание о перехвате наtesting. - LLM-карта/политика/roadmap —
llm-call-sites.md(A5),llm-determinization-roadmap.md(rank 2 ✅),llm-usage-policy.md(§5); инвариант «ровно одинfirst_slice=yes» цел (у rank 1 deployer); анти-дрейф-тестыtest_llm_call_site_inventory.py/test_llm_determinization_docs.py— зелёные (лично прогнаны). - Витрина системы
docs/overview/(ORCH-011) — обновленыtech-pipeline.md,tech-agents.md,tech-quality-security.md;tests/test_system_docs.pyзелёный (лично прогнан). - Промпт
.openclaw/agents/tester.md— врезка «детерминированный раннер ведёт стадию; LLM — fallback». CHANGELOG.md— запись[Unreleased].- ADR заведён (
06-adr/ADR-001+ сквознойadr-0049).
Обзорные доки / «Известные ограничения» README не затронуты этим PR (раннер — новая способность, не закрытие документированного ограничения) → дополнительных правок не требуется.
Findings
P0 — Blocker
- Нет.
P1 — Must fix
- Нет.
P2 — Should fix
- Нет.
P3 — Nice-to-have (не блокирует)
_http_getчитает только первые 8192 байта тела (resp.read(8192)), а smoke проверяет наличиеserial_gateв ответе/queue.serial_gate— 11-й ключ ответа (src/main.py:261), идёт до основной массы аддитивных блоков (coverage/fs_ownership/auto_labels/stop/bug_fast_track/ checkout_hygiene/transition_lease/staging_runner/test_runner/lessons) → запас комфортный, сейчас корректно. Латентная хрупкость при разрастании ранних блоков — опционально поднять лимит чтения для/queueили искать ключ потоково. Не блокирует.build_test_commandдобавляет флаг-q, отсутствующий в литеральной команде ADR (python -m pytest <target>). Безвредно и согласовано с прежним промптом tester (pytest tests/ -q); фиксирую лишь как расхождение текст↔код.
Контекст (не finding)
- В истории ветки присутствует
15-staging-log.mdсоstaging_status: FAILED(exit_code: None— staging-сюита не исполнилась, tool-error/инфра, бюджет инфра-ретраев исчерпан → fail-closed). Это исход deploy-staging стадии (downstream от review), относится к staging-раннеру ORCH-115 и является инфра-сбоем, а не дефектом кода ORCH-116 — вне осей код-ревью. Поведение гейта корректно (fail-closed на исчерпании инфра-бюджета); правок в коде задачи не требует. Отмечено как контекст для последующих стадий.
Документация
Обновлена в полном объёме в том же PR (см. ось 4): CLAUDE.md, docs/architecture/README.md,
internals.md, llm-call-sites.md, llm-determinization-roadmap.md, llm-usage-policy.md,
docs/overview/{tech-pipeline,tech-agents,tech-quality-security}.md, .openclaw/agents/tester.md,
CHANGELOG.md, ADR-001 + сквозной adr-0049. Анти-дрейф-тесты документации
(test_llm_call_site_inventory.py, test_llm_determinization_docs.py, test_system_docs.py) —
зелёные. Невыполненных требований к обновлению документации нет.
Вердикт
Нет P0/P1 findings; критический инвариант NFR-1 соблюдён байт-в-байт (stages.py/qg/checks.py не
тронуты); документация = golden source обновлена синхронно с кодом; полный регресс зелёный лично
проверен (2137 passed). verdict: APPROVED.