---
result: PASS
work_item: ORCH-115
stage: testing
author_agent: tester
status: pass
created_at: 2026-06-16
model_used: claude-opus-4-8
type: test-report
work_item_id: ORCH-115
---

# Test Report — ORCH-115 — детерминированный staging-раннер вместо LLM-деплойера

## Окружение
- Python: 3.12.13
- pytest: 8.3.3 (plugins: cov-5.0.0, anyio-4.13.0, asyncio-0.23.8)
- Worktree (изолированный, ветка задачи): `/repos/_wt/orchestrator/feature_ORCH-115-orch-replace-llm-deployer-with`
- Ветка: `feature/ORCH-115-orch-replace-llm-deployer-with`
- Дата: 2026-06-16
- Review verdict (`12-review.md`): **APPROVED** (P0/P1 — нет) ✅ предусловие стадии выполнено

## Команды
- Полный регресс: `pytest tests/ -q --tb=short`
- Целевой сьют + анти-дрейф LLM: `pytest tests/test_orch115_staging_runner.py tests/test_llm_call_site_inventory.py tests/test_llm_determinization_docs.py -v`
- Покрытие leaf: `pytest tests/test_orch115_staging_runner.py --cov=src.staging_runner --cov-report=term-missing`
- Smoke (read-only): `curl -s http://localhost:8500/{health,status,queue}`

## Результаты — покрытие плана тестов (`04-test-plan.yaml`)

Каждый TC сопоставлен с критериями `03-acceptance-criteria.md` и подтверждён конкретными
тест-функциями.

| TC ID | Тип | Описание (кратко) | AC | Тест-функции | Результат |
|-------|-----|-------------------|----|--------------|-----------|
| TC-01 | unit | `applies(repo)`: kill-switch / скоуп / not-self / never-raise→False | AC-6/AC-7 | `test_tc01_applies_killswitch_and_scope`, `test_tc01_applies_never_raises` | PASS |
| TC-02 | unit | Маппинг exit-кода `0→SUCCESS`, иначе/None→`FAILED` (контракт `self_deploy.map_exit_code_to_status`) | AC-3 | `test_tc02_map_exit_code` | PASS |
| TC-03 | unit | Рендер `15-staging-log.md`: `staging_status:` UPPERCASE + 52c-схема; INFRA-WAIVED в тело | AC-2 | `test_tc03_log_render_schema_and_infra_waived` | PASS |
| TC-04 | integration | Лог читается **неизменённым** `_parse_staging_status` для SUCCESS/FAILED | AC-2 | `test_tc04_gate_parser_unchanged` | PASS |
| TC-05 | integration | `launch_job` перехватывает до `_spawn`, нет `agent_runs`, `mark_job` ведёт строку | AC-1 | `test_tc05_launch_job_intercepts_before_spawn` | PASS |
| TC-06 | integration | Дискриминатор стадии: `deploy` (prod) и not-self репо НЕ перехватываются | AC-1 | `test_tc06_stage_discriminator_prod_not_intercepted`, `test_tc06_non_self_repo_not_intercepted` | PASS |
| TC-07 | integration | SUCCESS/FAILED → `advance_stage(finished_agent="deployer")` как у LLM | AC-4 | `test_tc07_advance_initiated_like_llm[0-SUCCESS]`, `[1-FAILED]` | PASS |
| TC-08 | integration | Kill-switch `=False` → прежний LLM-путь через `_spawn` (байт-в-байт) | AC-6 | `test_tc08_killswitch_falls_back_to_spawn` | PASS |
| TC-09 | unit | Анти-дрейф NFR-1: `STAGE_TRANSITIONS`/`QG_CHECKS`/`staging_status:`/схема БД неизменны | AC-5 | `test_tc09_pipeline_contract_unchanged` | PASS |
| TC-10 | integration | never-raise/fail-safe: ненулевой→FAILED+advance; таймаут→DEFER; бюджет исчерпан→FAILED; раннер не падает | AC-7 | `test_tc10_nonzero_exit_is_failed_and_advances`, `test_tc10_timeout_defers_without_advance`, `test_tc10_tool_error_budget_exhausted_fails_closed`, `test_tc10_run_gate_never_raises`, `test_tc10_launcher_contains_runner_fault` | PASS |
| TC-11 | unit | Таймаут `staging_runner_timeout_s`; малформ→дефолт+WARNING; передаётся в `proc_group` | AC-9 | `test_tc11_resolve_timeout_default_on_bad_value`, `test_tc11_timeout_passed_to_proc_group` | PASS |
| TC-12 | unit | Self-hosting safety: нет запрещённых литералов (рестарт 8500 / `up` / `--build` / force-push) | AC-8 | `test_tc12_command_has_no_dangerous_literals` | PASS |
| TC-13 | integration | Наблюдаемость: блок `staging_runner` в `/queue` + структурный лог-вердикт (различает код-фейл/tool-error) | AC-10 | `test_tc13_snapshot_shape`, `test_tc13_queue_endpoint_includes_block`, `test_tc13_structured_verdict_log_distinguishes_outcomes`, `test_tc13_snapshot_never_raises` | PASS |
| TC-14 | integration | Анти-дрейф LLM-карты: `llm-call-sites.md`(A6)/roadmap/policy обновлены, анти-дрейф зелёный | AC-11 | `test_llm_call_site_inventory.py` (9 тестов), `test_llm_determinization_docs.py` (3 теста) | PASS |

**Итог по плану: 14/14 TC выполнены и PASS.** Каждый AC (AC-1…AC-12) покрыт; AC-12 (полный регресс)
подтверждён прогоном всего `tests/`.

## Smoke API (read-only, prod 8500)
- `GET /health` → `{"status":"ok","service":"orchestrator"}` ✅
- `GET /status` → отвечает, активные задачи перечислены (включая ORCH-115 на `testing`) ✅
- `GET /queue` → отвечает; блок **`serial_gate`** присутствует (ORCH-088) ✅; блок **`auto_labels`**
  присутствует ✅. Полный набор ключей: `auto_labels, bug_fast_track, build_cache_prune,
  checkout_hygiene, counts, coverage, disk_monitor, fs_ownership, lessons, max_concurrency,
  merge_gate, merge_verify, poll_interval, post_deploy, reaper, recent, reconcile, resilience,
  serial_gate, stop, task_deps, transition_lease`.

> Примечание: read-only блок `staging_runner` (FR-7) на боевом 8500 ещё отсутствует — это ожидаемо,
> т.к. ORCH-115 не задеплоен в прод. Наличие блока в коде ветки подтверждено тестами TC-13
> (`test_tc13_queue_endpoint_includes_block`). Это **не** регресс смока: обязательный для смока
> блок `serial_gate` присутствует.

## Покрытие нового кода
`src/staging_runner.py` — **83%** (211 стэйтментов, 36 непокрытых). Непокрытые строки —
исключительно defensive `except`-ветви контракта never-raise (согласовано с `12-review.md`).

## Вывод pytest

Полный регресс:
```
........................................................................ [100%]
2105 passed, 1 warning in 93.61s (0:01:33)
```

Целевой сьют ORCH-115 + анти-дрейф LLM:
```
tests/test_orch115_staging_runner.py ......................... (24 passed)
tests/test_llm_call_site_inventory.py ......................... (9 passed)
tests/test_llm_determinization_docs.py ...................... (3 passed)
======================== 37 passed, 1 warning in 1.80s =========================
```

Единственное предупреждение — `PydanticDeprecatedSince20` (class-based `config`), не относится к
ORCH-115, присутствовало до изменения.

## Итог
**PASS** — полный регресс зелёный (2105 passed), целевой сьют (24 теста) и анти-дрейф LLM-карты
(12 тестов) зелёные, все 14 TC выполнены и сопоставлены с AC, smoke read-only OK (`serial_gate` и
`auto_labels` присутствуют в `/queue`). Машинный вердикт: `result: PASS` → задача переходит на
`deploy-staging`.
