11 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 | 4 |
Review ORCH-116 — детерминированный test-раннер вместо LLM-тестера
Машинный вердикт читается ТОЛЬКО из
verdict:во frontmatter.
Summary
Реализация полностью соответствует ТЗ (02-trz.md), критериям приёмки (03-acceptance-criteria.md)
и ADR-001 / adr-0050. ORCH-116 заменяет LLM-агента tester на стадии testing детерминированным
leaf src/test_runner.py, перехватываемым в launch_job до _spawn — точное зеркало эталона
src/staging_runner.py (ORCH-115). Критический инвариант NFR-1 соблюдён байт-в-байт: гейт
check_tests_passed / _parse_tests_verdict, STAGE_TRANSITIONS, QG_CHECKS, machine-key result:
и схема БД не тронуты (это замена продюсера артефакта, не гейта). Тонкая мина D6.1 (52c-status:
↔ парсер с negative-token-priority) обработана корректно и прибита тестом через неизменённый парсер.
Документация обновлена в полном объёме (CLAUDE.md / CHANGELOG / README / internals / витрина
docs/overview/ / LLM-карта/roadmap/policy / tester.md / .env.example). Все 4 оси — зелёные. Findings
уровня P0/P1, относящихся к ORCH-116, нет.
Оси проверки
1. Соответствие ТЗ / AC — PASS
- FR-1 / AC-1 перехват до
_spawn:launcher.launch_jobврезкаif job.get("agent")=="tester" and test_runner.should_intercept(job): return self._run_test_runner_job(job)рядом с D1/D2/ORCH-115;_run_test_runner_job— зеркало_run_staging_runner_job, ведётjobsчерезmark_job, возвращаетNone(нетagent_runs). ✔ (TC-05). - FR-2/3 / AC-3/AC-11 pytest в worktree через
proc_group(tree-kill,_resolve_timeoutfail-safe), маппингmap_exit_code_to_resultповерх единогоself_deploy.map_exit_code_to_status(без второго маппинга). ✔ (TC-02, TC-12). - FR-4 / AC-2
write_test_report—result:UPPERCASE + 52c-схема,author_agent: test-runner/model_used: n/a, push только в фичеветку (без merge вmain). ✔ (TC-03, TC-04). - FR-5 / AC-4
_advanceвызываетadvance_stage(current_stage="testing", finished_agent="tester")— FAIL-ветвьstage_engine.py:849матчит поagent=="tester". ✔ (TC-07). - FR-6 / AC-5 two-level outcome:
suite_ran=(returncode is not None) and (not timed_out); tool-error → bounded DEFER (re-queue именноtester-джоба + restart-safe маркер), на исчерпании → fail-closedFAIL+ advance + INFRA-alert. ✔ (TC-10). - FR-7 / AC-7/AC-8
applies()= kill-switch + скоуп +_has_test_contract(репо без контракта → LLM-tester даже при ручном добавлении в CSV). ✔ (TC-01, TC-08). - FR-8 / AC-13 блок
test_runnerвGET /queue+ счётчики + структурный лог, различающий code-fail / tool-error. ✔ (TC-14). - FR-9 / AC-12 гибрид: LLM вне control-path вердикта. ✔.
2. Соответствие ADR / инварианты — PASS
- NFR-1 / AC-6:
git diff origin/main...HEADНЕ затрагиваетsrc/stages.py,src/qg/,src/stage_engine.py,src/staging_runner.py,src/proc_group.py,src/transition_lease.py,src/git_worktree.py— проверено явно (пустой diff). ✔. - D6.1 (ключевая мина):
_parse_tests_verdict(src/qg/checks.py:263-277) читает вердикт из трёх полей с приоритетом негативного токена. Раннер выравниваетstatus:по вердикту (PASS→success«SUCCESS» — не позитивный и не негативный токен →Trueберётся изresult: PASS;FAIL→failed«FAILED» — негативный →False). Проверено вручную по логике парсера и тестом TC-04 (test_tc04_status_field_never_false_negatives_a_pass) через неизменённый парсер. ✔. - Граница O1:
staging_runner(ORCH-115),transition_lease(ORCH-114),checkout_hygiene(ORCH-112) не модифицированы — соответствует требованию. ✔. - Трассировка: новые врезки корректно ссылаются на прецеденты D1/D2/ORCH-115; зафиксированные инварианты конвейера не сломаны. ✔.
3. Качество кода — PASS
- never-raise соблюдён во всех публичных функциях (
applies/should_intercept/run_test_gate/snapshot/write_test_report/run_smoke— guarded; TC-01/TC-06/TC-11/TC-14 покрывают). - Лениво импортируются тяжёлые модули — leaf-чистота сохранена (импорт на уровне модуля только
config/logging/proc_group). - Тесты содержательные (14 TC + анти-дрейф TC-15), без живого Claude CLI/сети; покрывают happy/FAIL/ tool-error/never-raise/kill-switch/scope/smoke/observability.
- Это feature-трек (не
Bug), регресс-тест-фиксатор (ORCH-019 BR-4) не требуется; покрытие тем не менее исчерпывающее.
4. Документация — PASS (обязательная проверка)
src/ изменён → документация обновлена в том же PR, проверено пофайлово:
CLAUDE.md— новый раздел «Детерминированный test-раннер (ORCH-116)». ✔CHANGELOG.md— детальная запись[Unreleased]. ✔docs/architecture/README.md— компонент Test-runner + блок roadmap «второй срез реализован». ✔docs/architecture/internals.md— примечание о перехвате наtesting. ✔docs/architecture/llm-call-sites.md(A5),llm-determinization-roadmap.md(rank 2),llm-usage-policy.md(§5) — обновлены; инвариант «ровно одинfirst_slice=yes» сохранён (deployer=yes, tester=no), анти-дрейфtests/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'ом (канон 52d цел). ✔.env.example— все 7 ключейORCH_TEST_RUNNER_*. ✔- ADR + сквозной
adr-0050присутствуют. ✔
Тесты (AC-15)
tests/test_orch116_test_runner.py+ LLM анти-дрейф — 45 passed.- Полный регресс
pytest tests/ -q— 2162 passed, 1 failed (84s). Единственный фейл —tests/test_orch123_staging_runner_exec.py::test_r2_held_deploy_staging_not_rolled_back(см. P2).
Findings
P0 — Blocker
- (нет)
P1 — Must fix
- (нет)
P2 — Should fix
- [Вне ORCH-116, для отдельного follow-up] Pre-existing test-isolation flake в ORCH-123.
В полном прогоне падает
tests/test_orch123_staging_runner_exec.py::test_r2_held_deploy_staging_ not_rolled_back. Доказано, что это не дефект ORCH-116: (1) тест зелёный в изоляции и в своём файле; (2) фейл воспроизводится при прогоне полного сьюта безtests/test_orch116_test_runner.py(--ignore) → 1 failed; (3) ORCH-116 не трогаетsrc/staging_runner.py(граница O1, корректно). Это загрязнение глобального состояния от соседнего теста в ORCH-123-коде (недавно влит вmain). AC-15 в части «ORCH-116 не краснит ранее зелёные тесты» удовлетворён. Рекомендация: завести отдельный bug на изоляцию теста ORCH-123 — он вне области ORCH-116 и не должен блокировать этот PR.
P3 — Nice to have
run_smoke(src/test_runner.py:291) дублирует литерал"http://localhost:8500", который уже является дефолтомsettings.post_deploy_base_url. Это безвредный defensive double-default (localhost/8500НЕ в FORBIDDEN-спискеtest_no_host_hardcodes— нарушения нет); можно опереться только на дефолт config. Косметика.- Smoke-провал из-за транзиентного блипа прод-8500 после bounded-ретраев даёт
FAIL→ откат + расход developer-retry (формально инфра, трактуемая как код-фейл — родственно классу ORCH-110). Архитектор осознанно взвесил это в ADR (D3 + Consequences «−»): bounded smoke-ретрай + config-gatetest_runner_smoke_enabled+ developer-retry-cap; поведение эквивалентно прежнему LLM-tester (curl /health). Принято как задокументированный компромисс; не блокирует.
Документация
Обновлена в полном объёме в том же PR (см. ось 4). Изменение src/ сопровождено обновлением
паспорта, чейнджлога, архитектурной карты, internals, витрины docs/overview/, LLM-карты/roadmap/
политики, промпта tester.md, .env.example и ADR (локальный + сквозной). Машинно-проверяемые факты
витрины и LLM-карты держатся зелёными анти-дрейф-тестами. Требование «документация = golden source»
выполнено → блокирующих документационных findings нет.
Вердикт
Нет P0/P1, относящихся к ORCH-116. Все четыре оси (ТЗ, ADR/инварианты, качество кода, документация) пройдены; критические инварианты сохранены байт-в-байт; покрытие исчерпывающее. APPROVED. Единственный красный тест полного сьюта — pre-existing flake ORCH-123 (P2), доказанно независимый от ORCH-116 и вне его области правки.