Files
orchestrator/docs/work-items/ORCH-048/02-trz.md
stream 7a6c7a0151
All checks were successful
CI / test (push) Successful in 13s
CI / test (pull_request) Successful in 13s
docs(ORCH-048): owner decision — pin variant (v), reject (a) HTTP-endpoint (chicken-egg)
2026-06-06 06:56:09 +00:00

13 KiB
Raw Blame History

02 — Техническое задание (ТЗ / TRZ)

Work Item: ORCH-048 Title: staging B6 check reads registry from host worktree, not staging container Stage: analysis Author: analyst Date: 2026-06-06

Это ТЗ фиксирует требования и инварианты. Выбор одного из трёх архитектурных вариантов (§4) — за архитектором (ADR). Анализ варианты НЕ выбирает.


1. Задействованные модули

Путь Роль Характер изменений
scripts/staging_check.py Suite живых staging-проверок; блок B6 (~строки 263284) Изменяется — переписать механику получения реестра в B6
tests/ (новый файл, напр. tests/test_staging_check_b6.py) Unit-тест корректности B6 Создаётся
docs/operations/STAGING_CHECK.md Док запуска suite Обновляется (описание B6 + способ запуска)
docs/architecture/README.md / CHANGELOG.md Golden source Обновляется при необходимости

НЕ изменять (жёсткий инвариант scope)

  • src/projects.py — реестр работает корректно.
  • .env, .env.staging, .env.example — конфиг верен.
  • Прод-логику оркестратора (src/main.py прод-роуты, src/webhooks/*, src/stage_engine.py, src/qg/*) — кроме случая варианта (а), если архитектор решит добавить read-only эндпоинт (см. §4а, отдельно обоснованный риск).
  • Блоки A1A3, B4, B5 и блок C E2E в staging_check.py.

2. Текущее поведение (то, что чиним)

Блок B6 (scripts/staging_check.py):

sys.path.insert(0, "/repos/orchestrator")          # хост-worktree path
import importlib
if "src.projects" in sys.modules:
    importlib.reload(sys.modules["src.projects"])   # перечитывает env ТЕКУЩЕГО процесса
from src.projects import known_plane_project_ids
known = known_plane_project_ids()

Проблема: реестр строится из ORCH_PROJECTS_JSON process-env того процесса, в котором исполняется скрипт. При запуске деплоером с хоста (python3 scripts/staging_check.py --base-url http://localhost:8501) переменная не задана → _DEFAULT_PROJECTS (ET+ORCH) → ложный FAIL. B6 не отражает реестр работающего staging-инстанса.

3. Требуемое поведение (контракт B6)

ID Требование
TR-1 B6 определяет набор «известных staging-инстансу Plane project id» из источника, который гарантированно отражает окружение работающего staging-инстанса (порт 8501 / контейнер orchestrator-staging), а не из локального импорта в process-env скрипта.
TR-2 B6 PASS ⟺ SANDBOX_PROJECT_ID ∈ known И PROD_ET_PROJECT_ID ∉ known И PROD_ORCH_PROJECT_ID ∉ known. Идентификаторы — те же константы, что уже в скрипте.
TR-3 B6 сохраняет формат вывода Results.add(label, passed, detail) с человекочитаемым detail (sandbox=…, prod-ET=…, prod-ORCH=…).
TR-4 При недоступности источника реестра B6 даёт детерминированный FAIL с понятным detail (не падает с необработанным исключением, не даёт ложный PASS).
TR-5 Скрипт остаётся на stdlib (без сторонних зависимостей), если выбранный вариант это допускает.
TR-6 Удаляется зависимость B6 от хардкод-пути /repos/orchestrator для построения реестра (host-path хак), несовместимого с целью проверки.

4. Варианты реализации — РЕШЕНИЕ ВЛАДЕЛЬЦА (обязательно)

РЕШЕНИЕ ПРИНЯТО ВЛАДЕЛЬЦЕМ ПРОЕКТА (Слава, 06.06): выбран ВАРИАНТ (в). Архитектор НЕ выбирает заново — он фиксирует вариант (в) в ADR с обоснованием ниже.

Почему (в), а НЕ (а) и НЕ (б)

  • (а) HTTP-эндпоинт GET /projects — ОТКЛОНЁН. Порождает «курицу-яйцо»: B6 ходит на эндпоинт работающего staging-инстанса, а эндпоинт запечён в Docker-образ → на первом прогоне его в живом инстансе ещё нет (404) → ложный FAIL → откат. Требует ручного bootstrap-деплоя. Это ровно тот класс поломки автономности, который мы устраняем. (Подтверждено на проде 06.06: GET /projects на 8501 → 404 → deploy-staging FAILED.)
  • (б) docker exec subprocess — ОТКЛОНЁН. Хрупкое экранирование (см. docs/history/LESSONS_2026-06-05.md), зависимость от docker-CLI и имени контейнера.
  • (в) запуск suite ВНУТРИ staging-контейнера + чтение собственного process-env — ВЫБРАН. B6 не зависит от того, что отдаёт инстанс по HTTP; staging_check.py берётся из mount (свежий код сразу, без ребилда образа); реестр читается из env самого orchestrator-staging. Курицы-яйца нет ни на первом прогоне, ни в будущем. Автономность не ломается.

Что обязан зафиксировать архитектор в ADR (вариант в)

  1. Убрать из B6 host-path хак sys.path.insert(0, "/repos/orchestrator") и importlib.reload(src.projects).
  2. Канонизировать запуск suite ВНУТРИ контейнера: docker exec orchestrator-staging python3 <путь к staging_check.py> --base-url http://localhost:8501 (или эквивалент, где cwd/PYTHONPATH и env — staging-контейнера). Код импортируется из кода контейнера, env уже staging.
  3. Синхронно обновить .openclaw/agents/deployer.md (способ запуска suite через docker exec, НЕ с хоста) и docs/operations/STAGING_CHECK.md — иначе host-запуск воспроизведёт баг.
  4. Логику вердикта B6 вынести в чистую функцию _evaluate_b6(known: set[str]) -> tuple[bool, str] (TR-2/§9) для unit-теста на оба исхода (AC-2).
  5. НЕ добавлять HTTP-эндпоинт /projects и НЕ трогать прод-src/main.py. НЕ трогать src/projects.py, .env*, прочие чеки A/B4/B5/C.

Нюанс топологии (учесть)

Dockerfile НЕ копирует scripts/ в образ → staging_check.py доступен в контейнере только через mount /repos/orchestrator/scripts/.... Архитектор должен указать в ADR корректный путь запуска внутри контейнера, учитывая этот mount (а не /app/scripts).


4-original. Варианты реализации (исходный анализ — справочно)

4. Варианты реализации (выбор — архитектор, в ADR)

Бизнес-запрос предлагает три варианта. Анализ перечисляет их с известными плюсами/минусами; решение и обоснование — в 06-adr/.

(а) HTTP-эндпоинт staging-инстанса

B6 запрашивает реестр у работающего staging-инстанса по HTTP (как делают A/B4/B5/C).

  • Сейчас подходящего эндпоинта НЕТ. /health, /status, /queue реестр проектов не отдают (src/main.py).
  • Потребуется добавить read-only эндпоинт (напр. GET /projects, отдающий known_plane_project_ids() или список репо/prefix). Это касается прод-main.py → выходит за «не трогать прод-логику», но изменение read-only и низкорисковое — архитектор взвешивает.
  • Плюс: B6 гарантированно читает реестр именно того процесса, что обслуживает webhooks. Единый HTTP-стиль с остальными чеками.

(б) Subprocess в окружении staging-контейнера

B6 выполняет docker exec orchestrator-staging python3 -c "from src.projects import known_plane_project_ids; ..." и парсит stdout.

  • Плюс: не трогает прод-main.py; читает env контейнера напрямую.
  • Минус: требует доступности docker-CLI и имени контейнера из среды запуска suite; усложняет запуск «изнутри контейнера»; есть нюансы экранирования (см. docs/history/LESSONS_2026-06-05.md).

(в) Запуск suite внутри контейнера + чтение собственного process-env

Канонизировать запуск staging_check.py ВНУТРИ orchestrator-staging (docker exec orchestrator-staging python3 …), убрать sys.path.insert(0, "/repos/orchestrator"), импортировать src.projects из кода контейнера (его cwd/PYTHONPATH), env уже staging.

  • Плюс: минимально инвазивно, не трогает прод-логику и src.projects; согласуется с «рекомендуемым способом запуска» в STAGING_CHECK.md §Способы запуска.1.
  • Условие: деплоер должен запускать suite через docker exec (а не с хоста). Нужно синхронно обновить .openclaw/agents/deployer.md и STAGING_CHECK.md, иначе host-запуск воспроизведёт баг.
  • Нюанс: внутри контейнера код лежит в /app (Dockerfile COPY), а /repos/orchestrator — отдельный mount; импорт должен резолвиться из кода, чьим env реально живёт инстанс.

5. Изменения API

  • Варианты (б) и (в): нет изменений API.
  • Вариант (а): новый read-only эндпоинт (напр. GET /projects) — точная схема ответа определяется архитектором. Если выбран — задокументировать в docs/architecture/README.md (таблица API) и CHANGELOG.md.

6. Изменения схемы БД

Нет.

7. Требования к новым QG checks

Нет новых QG. Поведение check_staging_status (ADR-0003) не меняется — меняется только достоверность одного из чеков suite, чей агрегат пишется в 15-staging-log.md.

8. Артефакты pipeline, создаваемые/обновляемые

  • Код: scripts/staging_check.py (B6), новый тест в tests/.
  • Док: docs/operations/STAGING_CHECK.md; при выборе варианта (а) — docs/architecture/README.md (API) и CHANGELOG.md; при выборе (в) — .openclaw/agents/deployer.md (способ запуска) и STAGING_CHECK.md.
  • ADR: docs/work-items/ORCH-048/06-adr/ADR-001-*.md — обоснование выбранного варианта.

9. Тестируемость

  • Логика «PASS/FAIL по набору known id» B6 должна быть выделена в чистую, юнит-тестируемую функцию (напр. _evaluate_b6(known: set[str]) -> tuple[bool, str]), чтобы тест проверял оба исхода без поднятия staging-инстанса/docker. План — 04-test-plan.yaml.

10. Definition of Done

  • BR-1…BR-5 (01-brd) выполнены.
  • staging-прогон → B6 PASS; pytest tests/ -q зелёный.
  • Док и (при необходимости) ADR обновлены в том же PR.