---
work_item: ORCH-115
stage: architecture
author_agent: architect
status: proposed
created_at: 2026-06-16
model_used: claude-opus-4-8
---

# 07 — Инфра-требования: ORCH-115 — детерминированный staging-раннер

Work Item: **ORCH-115** · Repo: **orchestrator** · Стадия: architecture

> When-applicable. Топология **не меняется** (новых контейнеров/портов/томов/compose-правок
> нет). Файл фиксирует **предусловия**, на которые раннер теперь опирается **программно**
> (раньше эти же шаги исполнял LLM-deployer), чтобы предусловие было аудитопригодно (BR-7/
> AC-8/AC-9).

## I-1. Топология / окружения
**Без изменений топологии.** Раннер исполняется в прод-контейнере `orchestrator` (8500), в
worker-треде, как `_run_deploy_finalizer_job`. Предусловия (существующие, не вводятся
ORCH-115):
- staging-контейнер `orchestrator-staging` (8501) поднят и доступен на хосте (Допущение А1);
- прод-контейнер имеет возможность `docker exec` в `orchestrator-staging` (та же возможность
  использовал LLM-deployer — `.openclaw/agents/deployer.md` шаг 1; уже в проде);
- `scripts/staging_check.py` доступен внутри `orchestrator-staging` по bind-mount
  (`/repos/orchestrator/scripts/…`, паттерн B6/ORCH-048) — источник истины набора проверок и
  exit-кода (Допущение А2), ORCH-115 его не меняет.

Недоступность любого из предусловий обрабатывается **детерминированно** (раннер D5: bounded
defer → fail-closed `FAILED` + alert на исчерпании) — никогда тихий advance / ложный green.

## I-2. Переменные окружения / секреты
**Новые env-ключи (config, дефолты = боевое; добавить в `.env.example`):**
- `ORCH_STAGING_RUNNER_ENABLED` (`staging_runner_enabled`, дефолт `True`) — kill-switch;
  `false` → прежний LLM-deployer-путь байт-в-байт.
- `ORCH_STAGING_RUNNER_REPOS` (`staging_runner_repos`, дефолт `""`) — CSV скоупа; пусто →
  self-hosting only (`orchestrator`).
- `ORCH_STAGING_RUNNER_TIMEOUT_S` (`staging_runner_timeout_s`, дефолт `600`) — таймаут
  subprocess'а; малформ/непозитив → дефолт + WARNING.
- `ORCH_STAGING_RUNNER_INFRA_MAX_RETRIES` (`staging_runner_infra_max_retries`, дефолт `2`) и
  `ORCH_STAGING_RUNNER_INFRA_RETRY_DELAY_S` (`staging_runner_infra_retry_delay_s`, дефолт `30`)
  — бюджет defer на tool-error (D5).

**Секретов не вводит.** Команда строится из существующих host-параметров (`repos_dir`/
`staging_port`/`SELF_HOSTING_REPO`/сервис-литерал `orchestrator-staging`) — без новых
host-хардкодов (анти-дрейф `tests/test_no_host_hardcodes.py`).

## I-3. Деплой / рестарт
**Self-hosting инвариант соблюдён.** Раннер на `deploy-staging` **никогда** не рестартит
прод-контейнер 8500, не выполняет `docker compose up -d orchestrator`/`--build`, не пушит
force в `main`, не правит `.env`/`.env.staging`/`docker-compose.yml` (BR-7/AC-8; TC-12 —
запрет литералов в argv). Прод-выкат самого ORCH-115 идёт штатно через staging-гейт (8501)
→ `Confirm Deploy` (ORCH-059). Изменение **docs/prompts/код+config**, активируется на
следующем worktree от `main`; включение в проде — флагом (по умолчанию `True`, обратимо).

## I-4. CI/CD
**Без изменений `.gitea/workflows/`.** Новый `tests/test_orch115_staging_runner.py` исполняется
существующим `pytest tests/ -q` (мокирует subprocess/docker-exec и `advance_stage`; живой
Claude CLI / docker / сеть не требуются). Staging-smoke (`scripts/staging_check.py` на 8501)
— штатный гейт, не меняется.
