15 KiB
work_item, stage, author_agent, status, created_at, model_used
| work_item | stage | author_agent | status | created_at | model_used |
|---|---|---|---|---|---|
| ORCH-123 | analysis | analyst | ready-for-review | 2026-06-16 | claude-opus-4-8 |
02 — ТЗ (TRZ): ORCH-123 — staging-runner execution strategy must not depend on Docker CLI inside the app container
Work Item: ORCH-123 · Repo: orchestrator · Стадия: analysis
ТЗ описывает требования и ограничения к реализации, выведенные из BRD и фактического кода. Архитектурное решение (какую стратегию исполнения выбрать: host-side ssh / Docker SDK поверх сокета / docker CLI в образе / выделенный hook-режим, + security-review) — задача архитектора (
06-adr/), т.к. задача эскалирована в full-cycle (01-brd.md→escalate: full-cycle).
1. Сводка изменения
Восстановить работоспособную стратегию исполнения staging-сюиты для self-hosting orchestrator на
стадии deploy-staging, не завися от docker CLI, отсутствующего внутри прод-контейнера
(Dockerfile:11 ставит openssh-client git curl ca-certificates, не docker; docker.sock
смонтирован — docker-compose.yml:40 — но клиента нет). Сегодня staging_runner.build_staging_command
(src/staging_runner.py:154) формирует ["docker","exec","orchestrator-staging",…] и запускает её
изнутри прод-контейнера через proc_group → Popen падает FileNotFoundError → ветка tool-error
→ инфра-DEFER×2 → fail-closed FAILED → откат deploy-staging → development. Требуется: (а) исполнять
сюиту так, чтобы она реально запускалась в проде (паттерн host-side, уже применённый прод-деплоем
ORCH-036 / --build-staging); (б) различать постоянный environment/tool-error от настоящего
код-фейла и не делать вводящего в заблуждение код-фейл-отката; (в) prod-like preflight + регресс;
(г) документировать границу исполнения.
2. Задействованные модули / пути
| Путь | Действие | Примечание |
|---|---|---|
src/staging_runner.py |
изменить | build_staging_command/run_staging_suite — точка, где сюита запускается «изнутри контейнера» (корень дефекта, FR-1); классификация tool-error vs environment-дефект в run_staging_gate/_handle_tool_error (FR-2) |
src/self_deploy.py |
возможно переиспользовать | build_deploy_command/initiate_deploy — рабочий host-side ssh+setsid механизм (ORCH-036); кандидат на общий ssh-хелпер исполнения host-side команды (решает архитектор) |
scripts/orchestrator-deploy-hook.sh |
возможно изменить | --build-staging уже делает host-side docker exec "$STAGING_CONTAINER" python3 staging_check.py (строки 197/261) — прецедент/возможная точка выделенного staging-режима |
Dockerfile |
возможно изменить | строка 11 — если выбран вариант «docker CLI в образе» (тогда + security-обоснование) |
docker-compose.yml |
возможно изменить | строка 40 — docker.sock уже смонтирован; если выбран socket/SDK-вариант, зафиксировать права (:ro где возможно) |
src/proc_group.py |
возможно изменить | run_in_process_group уже корректно деградирует spawn-error в ProcResult(returncode=None) — кандидат на preflight «исполняемое существует» (FR-4) |
src/config.py |
возможно изменить | существующие staging_runner_*; при необходимости — флаг выбора/режима стратегии (FR-5), дефолт = боевое |
docs/operations/INFRA.md |
изменить | граница исполнения staging-сюиты относительно прод-контейнера (FR-6 / BR-5) |
docs/architecture/README.md |
изменить | описать стратегию исполнения staging-runner (FR-6 / BR-5) |
CHANGELOG.md, CLAUDE.md |
изменить | docs = golden source (CLAUDE.md §2); раздел ORCH-115 дополнить фиксом исполнения |
tests/test_orch115_staging_runner.py / tests/test_orch123_staging_runner_exec.py |
создать/расширить | регресс «docker CLI отсутствует» + классификация + preflight (04-test-plan.yaml) |
3. Функциональные требования
FR-1 — Работоспособная стратегия исполнения staging-сюиты в проде (BR-1)
- На стадии
deploy-stagingдля self-hostingorchestratorstaging-сюита (staging_check.pyвнутриorchestrator-staging) должна реально исполняться в боевом окружении, не завися от наличия бинаряdockerвнутри прод-контейнераorchestrator. - Стратегия исполнения — выбор архитектора (ADR), из перечня BRD §2: host-side через
существующий ssh+setsid механизм (ORCH-036,
deploy_ssh_host=127.0.0.1, ssh-ключ смонтирован,openssh-clientв образе) либо Docker SDK/docker.sock(уже смонтирован, + security-review) либо docker CLI в образе либо выделенный режим хука. ТЗ не прескриптивно — фиксирует лишь требуемый инвариант «сюита исполняется». - Команда/контракт сюиты (
python3 staging_check.py --base-url http://localhost:<staging_port> --mode stub, host-specifics из config — ORCH-101) сохраняются; меняется инициатор/канал запуска, не сама сюита.
FR-2 — Environment/tool-error ≠ код-фейл (BR-2, BR-3)
- Невозможность исполнить сюиту по причине окружения (нет исполняемого
docker/SDK недоступен/ стратегия неработоспособна) не должна завершаться откатомdeploy-staging → developmentкак кодовой ошибкой и не должна инкрементировать developer-retry. Текущий терминальный путь_handle_tool_error→write_staging_log("FAILED") + _advance(= откат) для постоянного environment-дефекта вводит в заблуждение (см. BRD §1) и должен быть заменён на отличимый инфра/environment-исход (хольд наdeploy-staging+ алерт оператору, по образцуmerge_gateinfra-tolerance ORCH-110: задача остаётся на стадии, без developer-retry). - Анти-over-tolerance (BR-3): если сюита реально исполнилась (получен exit-код) и упала
(exit≠0), исход — прежний откат
deploy-staging → development+ developer-retry (контрактstaging_runnerD5 для «сюита исполнилась» сохраняется байт-в-байт). - Различение «сюита исполнилась / постоянный environment-дефект / транзиентная инфра» —
детерминированная классификация (по образцу
merge_gate.classify_retest_failure, ORCH-110 D2); никаких догадок — постоянный environment-дефект (spawn-error «исполняемое не найдено») трактуется как НЕ-транзиентный и НЕ как код-фейл.
FR-3 — Анти-бессмысленный-ретрай (BR-2)
- При постоянном environment-дефекте бессмысленно крутить инфра-DEFER ×N (каждая попытка падает идентично, жжёт время/слот) и затем ложно откатывать. Допустимо: немедленный отличимый инфра-хольд+алерт (без отката, без developer-retry) или preflight, не дающий задаче войти в ложный путь. Конкретику решает архитектор; инвариант — не оканчиваться код-фейл-откатом.
FR-4 — Prod-like preflight (BR-4)
- Должен существовать механизм, ловящий «стратегия исполнения неработоспособна (нет исполняемого/
канал недоступен)» до раската — preflight на старте сервиса и/или в
scripts/staging_check.py/ smoke (scripts/staging_check.pyBlock …) / вshould_intercept/applies. Условие, проявившееся в инциденте (нет бинаряdockerтам, где runner его зовёт), должно детектироваться до того, как реальная задача ложно откатится. - Реализационно preflight никак не должен трогать гейты/стадии; never-raise; область — self-hosting.
FR-5 — Условность / kill-switch (BR-1, NFR-4, NFR-6)
- Поведение под существующим
staging_runner_enabled(выключен → прежний LLM-деплойер через_spawnбайт-в-байт) +staging_runner_repos(область). При необходимости нового флага выбора/режима стратегии — envORCH_*, дефолт = боевое (паттерн ORCH-101); откат = выставить флаг(и) → поведение до ORCH-123.applies(repo)(локально, без сети) проверяется первым.
FR-6 — Документирование границы исполнения (BR-5)
docs/operations/INFRA.md+docs/architecture/README.md: явно зафиксировать, что docker-операции для self-hosting исполняются host-side (а не из app-контейнера, где нет docker CLI), какие исполняемые/сокеты доступны прод-контейнеру (openssh-client/git/curl;docker.sockсмонтирован, CLI — нет), и как именно staging-runner запускает сюиту после фикса.
4. Изменения API
Нет обязательных. Существующий read-only блок staging_runner в GET /queue (ORCH-115)
дополняется различием environment/tool-error vs код-фейл и (опц.) статусом preflight; новых
управляющих эндпоинтов не требуется (на усмотрение архитектора — опц. read-only preflight-поле).
5. Изменения схемы БД
Нет. Restart-safe состояние (счётчик инфра-ретраев) уже ведётся маркером в task_content
(_INFRA_RETRY_MARKER, ORCH-115) — без миграции. Новой таблицы/колонки не требуется.
6. Требования к новым/изменённым QG checks
Нет. Это не Quality Gate и не стадия — это стратегия исполнения продюсера артефакта
15-staging-log.md. STAGE_TRANSITIONS / реестр QG_CHECKS / имена и семантика check_*
(check_staging_status/_parse_staging_status) / machine-verdict ключи (staging_status:/
deploy_status:/…) / схема БД — байт-в-байт не тронуты (NFR-1; зеркало инварианта ORCH-115 NFR-1).
7. Совместимость / регресс
- Обратная совместимость:
staging_runner_enabled=False→ стадиюdeploy-stagingснова ведёт LLM-deployerчерез_spawnбайт-в-байт; для прочих репоapplies==False→ no-op (нулевая регрессия enduro). - Контракт артефакта:
15-staging-log.md(staging_status:+ 52c-схема,author_agent: staging-runner/model_used: n/a) сохраняется; вердикт по-прежнему читается ТОЛЬКО из frontmatter. - Self-hosting инварианты (NFR-2): не рестартить прод 8500, не
docker compose up orchestrator/--buildпрода, не force-push, не писать вmain, не править.env— сохраняются (ORCH-115 BR-7). - Security (NFR-3): любой socket/CLI-в-контейнере вариант проходит security-review в ADR; host-side ssh-вариант переиспользует доверенный ORCH-036 механизм без расширения привилегий.
- Бюджеты/инварианты: тайм-аут сюиты не растёт сверх
staging_runner_timeout_s(держит сквозной reaper-инвариант ORCH-065/109/110); proc_group tree-kill (ORCH-110) сохраняется. - Артефакты pipeline: обычные docs work item (
01..04этой задачи;06-adr/на стадии architecture после эскалации;15-staging-log.mdпри прогоне). Новых pipeline-артефактов задача не вводит. - Трассировка (CLAUDE.md §9 / ORCH-078): правки маркированных блоков — ORCH-115 (staging-runner,
прямой объект), ORCH-036 (self_deploy ssh), ORCH-110 (proc_group/infra-tolerance), ORCH-058
(
--build-staging) — сверять с их06-adr/перед изменением; инварианты не ломать.