Files
orchestrator/docs/work-items/ORCH-115/12-review.md
claude-bot e3ce01b824
All checks were successful
CI / test (push) Successful in 1m16s
CI / test (pull_request) Successful in 1m13s
reviewer(ET): auto-commit from reviewer run_id=735
2026-06-16 02:08:18 +03:00

135 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
verdict: APPROVED
work_item: ORCH-115
stage: review
author_agent: reviewer
status: approved
created_at: 2026-06-16
model_used: claude-opus-4-8
type: review
work_item_id: ORCH-115
version: 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_status` lookup 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` проверяется первым, при выключенном
флаге `_spawn` LLM-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%; непокрытые строки — исключительно defensive `except`-ветви
never-raise). ✅
### 2. Соответствие ADR (`06-adr/ADR-001` + сквозной `adr-0048`)
- D1D11 реализованы как зафиксировано: точка диспетчеризации (перехват до `_spawn`, дискриминатор
по **стадии задачи**, не по имени роли — защита от перехвата прод-`deploy` deployer'а, 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-key `staging_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` сохраняет deployer `avoidable=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**.