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-115 | review | reviewer | approved | 2026-06-16 | claude-opus-4-8 | review | ORCH-115 | 1 |
Review ORCH-115 — детерминированный staging-раннер вместо LLM-деплойера
Summary
Замена LLM-агента deployer на стадии deploy-staging (self-hosting orchestrator)
детерминированным leaf src/staging_runner.py, перехватываемым в launch_job до _spawn
(прецедент deploy-finalizer/post-deploy-monitor). Реализация строго соблюдает корневой
инвариант NFR-1 — это замена продюсера артефакта 15-staging-log.md, а не гейта:
STAGE_TRANSITIONS, QG_CHECKS, check_staging_status/_parse_staging_status, machine-key
staging_status: и схема БД — байт-в-байт не тронуты. Все FR-1…FR-7 реализованы, все
AC-1…AC-12 выполнены, документация обновлена в том же PR на всех требуемых поверхностях,
полный регресс зелёный (2105 passed), новый сьют (24 теста) зелёный, анти-дрейф LLM-карты
зелёный.
Вердикт: APPROVED — P0/P1 findings отсутствуют.
Проверка по осям
1. Соответствие ТЗ (02-trz.md) / критериям (03-acceptance-criteria.md)
- FR-1 / AC-1 — перехват в
launch_jobдо_spawnприagent=="deployer"+should_intercept(стадияdeploy-staging+applies); возвращаетNone,_spawnне вызывается,agent_runsне создаётся,jobs-строка ведётсяmark_jobчерез_run_staging_runner_job(зеркало_run_deploy_finalizer_job). ✅ (TC-05) - FR-2 / AC-9 / AC-8 — та же каноническая staging-сюита через
proc_group.run_in_process_group(tree-kill, таймаут). Команда из config (без host-хардкодов). ✅ (TC-11/TC-12) - FR-3 / AC-3 — exit-код →
staging_status:через единый контрактself_deploy.map_exit_code_to_status(0→SUCCESS, иначе/None/нечисло→FAILED), второй маппинг не введён. ✅ (TC-02) - FR-4 / AC-2 —
15-staging-log.mdсstaging_status: SUCCESS|FAILED(UPPERCASE) + полной 52c-схемой (work_item/stage: deploy-staging/author_agent: staging-runner/status/created_at/model_used: n/a); INFRA-WAIVED копируется в тело; best-effort commit/push в фичеветку (не вmain), гейт читает worktree первым (check_staging_statuslookup order подтверждён вsrc/qg/checks.py:627). ✅ (TC-03/TC-04) - FR-5 / AC-4 — после вердикта вызывается существующий
advance_stage(current_stage="deploy-staging", finished_agent="deployer")— параметры в точности соответствуют сигнатуреstage_engine.advance_stage:191и зеркалятrun_deploy_finalizer:2092; SUCCESS → под-гейты + Phase A; FAILED → существующий откатdeploy-staging → development(stage_engine.py:932, веткаagent=="deployer" and qg=="check_staging_status"). Новой ветви маршрутизации нет. ✅ (TC-07/TC-10) - FR-6 / AC-6 — kill-switch
staging_runner_enabled+ скоупstaging_runner_repos(пусто → self-hosting only черезis_self_hosting_repo);appliesпроверяется первым, при выключенном флаге_spawnLLM-deployer'а байт-в-байт. ✅ (TC-01/TC-08) - FR-7 / AC-10 — read-only блок
staging_runnerвGET /queue+ один структурный лог-вердикт на прогон, различающийcode-pass/code-fail/tool-error. ✅ (TC-13) - AC-7 (never-raise) — все публичные функции изолированы; tool-error (spawn-error/таймаут/
returncode None) даёт bounded DEFER, затем fail-closed FAILED; никогда тихий advance/ложный green. ✅ (TC-10) - AC-12 —
pytest tests/ -qзелёный (2105 passed); новыйtests/test_orch115_staging_runner.pyзелёный (24 теста, покрытие leaf 83%; непокрытые строки — исключительно defensiveexcept-ветви never-raise). ✅
2. Соответствие ADR (06-adr/ADR-001 + сквозной adr-0048)
- D1–D11 реализованы как зафиксировано: точка диспетчеризации (перехват до
_spawn, дискриминатор по стадии задачи, не по имени роли — защита от перехвата прод-deploydeployer'а, TC-06), чистота leaf'а (на импорте толькоconfig/proc_group;db/git_worktree/stage_engine/qg.checks/self_deploy/notifications— лениво), переиспользованиеproc_groupи единого маппинга, двухуровневый исход D5 (анти-ORCH-110) — инфра-сбой ≠ код-фейл, restart-safe маркер-счётчик вtask_contentбез правки схемы БД, push только в фичеветку, инициация существующего гейта, бюджет времени без правкиreaper_max_running_s, наблюдаемость. - Инвариант NFR-1 / AC-5 соблюдён байт-в-байт — анти-дрейф TC-09 подтверждает неизменность
STAGE_TRANSITIONS["deploy-staging"], наличиеcheck_staging_statusвQG_CHECKS, отсутствие новых таблиц/колонок, неизменность machine-keystaging_status:. - Граница O1 (трассировка маркеров) — код ORCH-114 (
transition_lease) и ORCH-112 (checkout_hygiene) не модифицируется; lease берётся внутриadvance_stage, раннер его не трогает — зафиксированный инвариант цепочки ORCH-110/111/112/113/114 не сломан.
3. Качество кода
- Docstrings на всех публичных функциях; следование установленным паттернам (
self_deploy/proc_group/merge_gate); классификацияsuite_ran = returncode is not None and not timed_outкорректно трактует timeout-kill (returncode может быть-9, ноtimed_out=True) как tool-error, а не код-фейл. - Сверены все интеграционные сигнатуры:
ProcResult,run_in_process_group(grace_s/tree_kill),enqueue_job(available_at_delay_s),mark_job,get_worktree_path,link_for/send_telegram,is_self_hosting_repo/SELF_HOSTING_REPO— все совпадают. - Self-hosting safety (AC-8/BR-7) — в командной строке нет рестарта 8500 /
docker compose up/--build/ force-push / правок.env; git push строго в фичеветку, никогда вmain. ✅ (TC-12) - Багфикс-трек (BR-4) неприменим: ORCH-115 — полный цикл (метка не
Bug, прошёлarchitecture), регресс-тест-фиксатор не требуется; покрытие обеспечено новым сьютом.
4. Документация (обязательная проверка)
src/ изменён → документация обновлена в том же PR на всех требуемых поверхностях:
CLAUDE.md(раздел-паспорт ORCH-115),CHANGELOG.md([Unreleased]).docs/architecture/README.md(компонент Staging-runner + adr-link),internals.md(детерминированные перехватыlaunch_job).- Норматив сопровождения ORCH-118:
llm-call-sites.md(A6 — срез реализован, машинныйORCH-118-INVENTORY-BLOCKсохраняет deployeravoidable=yes/axis=Cкак fallback),llm-determinization-roadmap.md(rank 1 — ✅, инвариант «ровно одинfirst_slice» цел),llm-usage-policy.md(§5 — единственный транспорт S0 не нарушен). Анти-дрейфtests/test_llm_call_site_inventory.py/test_llm_determinization_docs.pyзелёные (TC-14). - Витрина системы
docs/overview/(ORCH-011) — обновленыtech-pipeline.md,tech-agents.md,tech-quality-security.md;tests/test_system_docs.pyзелёный. .openclaw/agents/deployer.md(LLM-ветвьdeploy-staging— fallback),.env.example(5 ключей), ADR work-item + сквознойadr-0048.- README «Известные ограничения» (ORCH-079) — корректно не тронут: ни один из трёх открытых пунктов (Telegram 48h / intra-repo deps / batch-autonomy) не закрывается ORCH-115; ложного «решённое за открытое» нет.
Findings
P0 — Blocker
- Нет.
P1 — Must fix
- Нет.
P2 — Should fix
- Нет.
P3 — Nice-to-have
run_staging_gateпри отсутствииwork_item_id/branch(повреждённая строкаtasks— задача наdeploy-stagingбез branch) делает раннийreturn; обёртка_run_staging_runner_jobзатем помечает джобdone, оставляя задачу «висеть» наdeploy-stagingдо ре-драйва reconciler/reaper. Это крайний кейс (любая задача наdeploy-stagingимеет branch), логируется как ERROR и согласуется с never-raise-контрактом, но опционально можно сделать defensive-defer вместоdone-без-эффекта. Не блокирует приёмку.
Документация
Обновлена полностью и в том же PR. Изменение src/ сопровождено синхронным обновлением паспорта,
чейнджлога, архитектурных доков, LLM-карты/roadmap/политики (+ зелёные анти-дрейф тесты), витрины
docs/overview/ (ORCH-011), промпта deployer.md, .env.example и обоих ADR. Обзорная витрина
README не требует правок (нет закрытого ORCH-115 пункта). Документационная ось — PASS.