--- work_item: ORCH-103 stage: analysis author_agent: analyst status: ready-for-review created_at: 2026-06-11 model_used: claude-opus-4-8 --- # 01 — BRD: ORCH-103 — ORCH-10b Bundled-тираж: весь стек одним комплектом + bootstrap-скрипт Work Item: **ORCH-103** · Repo: **orchestrator** (self-hosting) · Стадия: analysis Заказчик: Слава · Эпик: **ORCH-10** (домен D5 «Масштаб», `docs/epics/self-evolution.md`) · Тип: **B — Bundled** --- ## 1. Бизнес-контекст и проблема ### 1.1. Цель эпика ORCH-10 Тираж платформы — РАЗДАЧА текущей функциональности нескольким заказчикам **на тест**. Решения Владельца 10.06 (приняты как требования): ДВА типа тиража, ОБА **stateless** (наши задачи/данные/секреты НЕ переносим — чистый старт): - **Тип A (Lite, ORCH-102 ✅)** — переносится ТОЛЬКО орк+watchdog; Plane/Gitea/LLM/Telegram заказчик донастраивает сам по инструкции `docs/deployment/LITE_SETUP.md`. - **Тип B (Bundled, эта задача)** — **весь стек одним комплектом** (орк + watchdog + Gitea + Plane + рантайм-обвязка агентов) — «под ключ». ### 1.2. Проблема, которую закрывает ORCH-103 Lite предполагает, что у заказчика **уже есть** (или он сам поднимет) свои Plane и Gitea. Для заказчика без собственной инфраструктуры это барьер: Plane CE self-hosted — это ~14 контейнеров со своей БД/брокером/хранилищем, Gitea — отдельная установка, и поверх всего — первичная инициализация (админы, токены, workspace, 22 статуса, лейблы, вебхуки в обе стороны, git-доступ агентов). Сегодня репо не содержит ни compose-описания этого стека, ни автоматизации его доводки: разворачивание «с нуля до работающего конвейера» = многочасовая ручная работа по сторонним докам с рисками дефолтных паролей и дрейфа от канона платформы. ORCH-103 должен дать: **один compose-комплект** всего стека + **bootstrap-скрипт**, доводящий свежеподнятый стек до рабочего состояния одной командой/визардом, + **новые секреты** на каждую инсталляцию + **инструкцию `docs/deployment/BUNDLED_SETUP.md`** с требованиями к хосту. ### 1.3. Установленные факты (проверено по репо — не изобретать) - **Корневой `docker-compose.yml` защищён анти-дрейфом:** ровно 3 сервиса (`orchestrator`, `orchestrator-watchdog`, `orchestrator-staging` за `profiles: ["staging"]`); `tests/test_lite_setup_doc.py` (TC-04) проверяет точное множество сервисов и **запрещает** появление в нём имён/образов с подстроками `plane`/`gitea` → bundle-компоуз обязан быть **отдельным файлом**, корневой compose не форкается и не расширяется. - **Кирпичи уже в `main` (переиспользовать, не дублировать):** - `scripts/gen_secrets.py` (ORCH-101) — криптослучайные webhook-секреты (`ORCH_PLANE_WEBHOOK_SECRET`/`ORCH_GITEA_WEBHOOK_SECRET`), печать по умолчанию, `--write` отказывает при существующем `.env`, `--force` — перезапись; exit 0/2. - `scripts/onboard_project.py` (ORCH-009) — `plan` (GET-only) / `apply` (идемпотентный ensure, без delete) / `verify`: Plane-проект + **22 статуса** (read-only импорт `plane_sync._PLANE_NAME_TO_KEY`, fail-closed имена `Confirm Deploy`/`STOP`) + лейблы `autoApprove`/`autoDeploy`/`Bug`; Gitea-репо + per-repo webhook (`push`/`pull_request`/`status`, ОДИН глобальный `ORCH_GITEA_WEBHOOK_SECRET`); недоступное в Plane CE API → `manual-step` (fail-safe); exit 0/2/1. - `docs/operations/REPLICATION.md` (ORCH-101) — карта env (§2), чек-лист секретов (§3), **smoke §4** (шаги 0–6 с PASS/FAIL: config-резолв → `/health` → `/queue`+`/metrics` → onboard plan/apply/verify → тестовая задача → артефакты `01–04` → опц. до `done`); §1 — таблица границ, где Type B помечен «отдельная задача». - `docs/deployment/LITE_SETUP.md` (ORCH-102) — канон тиражной инструкции: 13 нормативных разделов, каждый шаг = fenced-команда + явная «Проверка:» PASS/FAIL, хост-специфика только плейсхолдерами; канон не форкается — общие шаги ссылками. - `.env.example` — канон 100% ключей орка; `.env.watchdog.example` — канон watchdog (key-set-sync тестом, D5 ORCH-102). - **Хост-параметризация завершена (ORCH-101):** платформа разворачивается без правки кода — только env (`${VAR:-default}`-интерполяция compose, `ARG APP_*` Dockerfile); анти-регресс `tests/test_no_host_hardcodes.py` (FORBIDDEN-литералы: IP/`/home/slin`/`mva154`/`duckdns`). - **Claude CLI НЕ запечён в образ орка:** монтируется с хоста (`ORCH_HOST_CLAUDE_CODE_DIR`/`ORCH_HOST_NODE_BIN`/`ORCH_HOST_CLAUDE_DIR`/`ORCH_HOST_CLAUDE_JSON`). «Агенты» в комплекте = рантайм-обвязка запуска; **инсталляция Claude CLI и LLM-ключ — внешнее предусловие хоста заказчика** (как Lite §7), bundle их не содержит и не генерирует. - **Нормативы тиражной Gitea:** branch protection на `main` НЕ включать (D10 ORCH-009 / INV-4 — мерж только через Gitea PR-merge API); pre-receive не вводится. - **Plane CE self-hosted ≈ 14 контейнеров** (web/admin/space/api/worker/beat/live/migrator + postgres/redis/mq/minio/proxy) — ресурсоёмко; часть первичной инициализации в CE недоступна по API → честные ручные чекпоинты (паттерн `manual-step` ORCH-009). --- ## 2. Объём (scope) ### 2.1. В объёме - **Bundle-compose** — отдельный compose-комплект всего стека: орк + watchdog + Gitea + Plane-стек (~14 контейнеров); пиннинг версий; чистые именованные тома; согласованная сетевая достижимость (вебхуки в обе стороны). - **Bootstrap-скрипт** — один запуск (команда/визард): поднять всё → дождаться готовности/миграций → инициализация Gitea (админ/токен) → инициализация Plane (instance/workspace/API-токен; CE-ограничения → явные manual-step чекпоинты) → онбординг sandbox-проекта (22 статуса/3 лейбла/репо/вебхуки — через `onboard_project.py`) → git-доступ агентов → сборка `.env`/`.env.watchdog` орка → health → smoke-подсказка. - **Инициализация секретов** — генерация НОВЫХ на каждую инсталляцию (reuse `gen_secrets.py` + bundle-внутренние креды: пароли БД/брокера/хранилища Plane, админ Gitea); дефолтных паролей в репо нет. - **`docs/deployment/BUNDLED_SETUP.md`** — инструкция запуска bundle по канону LITE_SETUP, включая **требования к хосту (RAM/диск/CPU/порты)**. - **Структурные анти-дрейф тесты** (без docker/сети/LLM в CI) + полный зелёный pytest + CHANGELOG. - Отметка Type B в `docs/operations/REPLICATION.md` §1 (границы трёх задач эпика). ### 2.2. Вне объёма (явно, не делать) - Изменения рантайма: `src/**`, корневой `docker-compose.yml`, `Dockerfile`, `.gitea/workflows/`, `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД — байт-в-байт. - Перенос наших задач/данных/секретов (stateless — решение Владельца 10.06). - Автоматическая установка Claude CLI / выдача LLM-ключей / создание Telegram-ботов — внешние предусловия заказчика (документируются, не автоматизируются). - HTTPS/домены/публичный reverse-proxy заказчика — за рамками bundle (документируется как ручной шаг при необходимости). - Процедура обновления (upgrade) развёрнутого bundle; миграция Lite→Bundled; кластерные/ multi-host топологии; мультитенантность (D5.6) и горизонтальный воркер-пул (D5.4). - Какая-либо активация bundle на НАШЕМ боевом хосте. --- ## 3. Заинтересованные стороны - **Владелец (Слава)** — раздаёт платформу заказчикам на тест; принимает результат. - **Оператор заказчика** — целевой читатель BUNDLED_SETUP.md: чистый Linux-хост, docker+compose, без знания внутренностей платформы. - **Self-hosting прод** (`orchestrator`, общий для всех проектов) — не должен быть затронут: задача — артефакты репо (compose/скрипт/доки/тесты), активируемые только явным запуском на ЦЕЛЕВОМ хосте. --- ## 4. Бизнес-требования (BR) | ID | Требование | Связь | |----|------------|-------| | BR-1 | Единый bundle-compose (отдельный файл) поднимает ВЕСЬ стек одной командой: орк, watchdog, Gitea, Plane-стек. Корневой `docker-compose.yml` не форкается и не меняется. | AC-1, AC-6, FR-1 | | BR-2 | Bootstrap-скрипт ОДНИМ запуском (команда/визард) доводит свежеподнятый стек до рабочего состояния: готовность/миграции → init Gitea → init Plane → онбординг sandbox-проекта → git-доступ агентов → конфиг орка → health. Шаги, физически недоступные через Plane CE API, оформляются явными интерактивными manual-step чекпоинтами (fail-safe, паттерн ORCH-009) — без молчаливых пропусков. | AC-1, FR-2 | | BR-3 | После bootstrap smoke проходит: тестовый проект создан, тестовая задача доезжает минимум до артефактов `01–04` в ветке (минимальный сигнал REPLICATION §4 шаг 5); расширенно — до `done`. Вебхуки работают в ОБЕ стороны (Plane→орк, Gitea→орк, орк→Plane/Gitea API). | AC-2, FR-2/FR-6 | | BR-4 | Stateless: каждая инсталляция стартует с чистых томов/БД (Plane, Gitea, орк) и НОВЫХ секретов (`gen_secrets.py` + bundle-внутренние креды). Боевые данные/секреты не используются ни на одном шаге; в репо нет ни одного реального секрета/дефолтного пароля. | AC-3, FR-3 | | BR-5 | `docs/deployment/BUNDLED_SETUP.md` написан по канону LITE_SETUP (fenced-команды + «Проверка:» PASS/FAIL, плейсхолдеры вместо хост-специфики, канон не форкается — общие шаги ссылками на LITE_SETUP/ONBOARDING/REPLICATION) и фиксирует требования к хосту: RAM/диск/CPU/занимаемые порты (Plane ~14 контейнеров — ресурсоёмко). | AC-4, FR-4 | | BR-6 | Переиспользование кирпичей без дублирования: секреты — `gen_secrets.py`; статусы/лейблы/репо/вебхуки — `onboard_project.py` (22 статуса — из `plane_sync._PLANE_NAME_TO_KEY`, нулевой дрейф); smoke — шаги REPLICATION §4. Bootstrap не реализует собственную копию этих канонов. | FR-2/FR-3, AC-7 | | BR-7 | Идемпотентность/fail-safe: повторный запуск bootstrap безопасен (ensure/skip, без delete-операций); запуск на «грязном» хосте (существующие тома/занятые порты/нехватка ресурсов) → явный отказ preflight с понятной подсказкой, а не молчаливое переиспользование чужого состояния. | FR-2, AC-8 | | BR-8 | Наш прод не затрагивается: вся задача — вне рантайма и вне конвейера; kill-switch не требуется (активация — только явный запуск человеком на целевом хосте, паттерн ORCH-009). | NFR-1/NFR-2, AC-6 | | BR-9 | Анти-дрейф: структурные тесты держат bundle-канон (compose-структура, док-канон, env-ключи, FORBIDDEN-литералы, секрет-эвристика, кросс-ссылки); существующие `test_lite_setup_doc.py`/`test_no_host_hardcodes.py` остаются зелёными; полный `pytest tests/ -q` зелёный; CHANGELOG обновлён. | AC-5, AC-6, AC-7, FR-5 | --- ## 5. Нефункциональные требования (NFR) | ID | Требование | |----|------------| | NFR-1 | **Рантайм/конвейер байт-в-байт:** `src/**`, корневой `docker-compose.yml`, `Dockerfile`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи, схема БД орка — не тронуты. Задача — docs+scripts+compose-bundle+tests. | | NFR-2 | **Self-hosting безопасность:** ни один артефакт задачи не рестартит/не деплоит/не конфигурирует наш прод-контейнер; bundle-артефакты в нашем контуре инертны (никто их не исполняет). | | NFR-3 | **Секрет-гигиена:** в репо не попадают реальные секреты, высокоэнтропийные литералы и хост-литералы (FORBIDDEN-скан `test_no_host_hardcodes.py` распространяется на новые артефакты); bootstrap не печатает секреты в лог; сгенерированные файлы конфигов — только на целевом хосте, в `.gitignore`. | | NFR-4 | **Переносимость:** bundle не зависит от нашей инфраструктуры; вся хост-специфика — переменные/плейсхолдеры; целевая платформа — одиночный Linux x86_64 хост с docker+compose. | | NFR-5 | **Норматив сопровождения** (зеркало NFR-5 ORCH-102): изменение шагов тиража в будущих задачах → обновление `BUNDLED_SETUP.md` в том же PR. | | NFR-6 | **Воспроизводимость:** версии образов Gitea/Plane-стека зафиксированы (пиннинг тегов/digest, не `latest`); состав bundle детерминирован. | | NFR-7 | **Без новых тяжёлых зависимостей:** bootstrap — в духе существующих скриптов (stdlib-инструментарий `gen_secrets.py`/`onboard_project.py`); точный стек (bash/python) — решение архитектора. | --- ## 6. Допущения и ограничения - Целевой хост: чистый одиночный Linux x86_64 с установленными docker + docker compose; оператор имеет sudo. Прочие ОС — вне целевой платформы (best-effort). - Ресурсы: Plane-стек ресурсоёмок; ориентир для проверки — **не менее 4 vCPU / 8 GB RAM / 40 GB диска** (финальные минимумы УТОЧНЯЮТСЯ при реализации замером на тестовом развёртывании и фиксируются в BUNDLED_SETUP.md — см. AC-4; цифры выше — гипотеза, не факт). - Внешние предусловия заказчика (bundle не поставляет): инсталляция/аутентификация Claude CLI + LLM-доступ Anthropic; Telegram-боты (трекер + watchdog) — опциональны, их отсутствие деградирует только нотификации (never-raise), не конвейер. - Часть инициализации Plane CE недоступна по API (instance-setup/workspace/API-токен) — допускаются документированные интерактивные шаги внутри визарда; «одной командой» означает «один запуск bootstrap с явными чекпоинтами», а не «ноль действий человека». - Версии upstream-образов (Plane CE/Gitea) фиксируются на момент реализации; их обновление — отдельные будущие задачи (NFR-6). --- ## 7. Критерии успеха (резюме; детали — 03-acceptance-criteria.md) Пять AC из постановки Владельца (сохранены 1:1 как AC-1…AC-5) + производные проверяемые: - AC-1 единый bundle-compose поднимает ВЕСЬ стек; bootstrap доводит до рабочего состояния одной командой/визардом. - AC-2 после bootstrap smoke проходит (тестовый проект + задача доезжает). - AC-3 stateless (чистые Plane/Gitea/БД, новые секреты). - AC-4 BUNDLED_SETUP.md + требования к хосту (RAM/диск) задокументированы. - AC-5 pytest зелёный; CHANGELOG. - AC-6 корневой compose/рантайм не тронуты (анти-дрейф зелёный); AC-7 нулевой дрейф канонов (22 статуса/лейблы/секреты — через существующие кирпичи); AC-8 идемпотентность/fail-safe bootstrap; AC-9 секрет-гигиена новых артефактов. --- ## 8. Риски (детали — 10-tech-risks.md, заполняет архитектор) - **R-1 Ресурсоёмкость Plane:** ~14 контейнеров → OOM/медленный старт на слабом хосте; смягчение — preflight-проверка ресурсов + честные требования в доке (AC-4). - **R-2 Дыры Plane CE API:** первичная инициализация частично UI-only → ручные чекпоинты; риск — UX «одной команды» размывается; смягчение — явные manual-step с проверкой результата (паттерн ORCH-009), минимизация числа ручных шагов. - **R-3 Дрейф upstream-образов:** «плавающие» теги ломают воспроизводимость → пиннинг (NFR-6). - **R-4 Сетевая достижимость вебхуков:** орк (host network) ⟷ Plane/Gitea (bridge-сеть bundle) — двунаправленные URL должны быть согласованы bootstrap'ом; ошибка = «задача не появилась» (труднодиагностируемо); смягчение — smoke проверяет оба направления. - **R-5 Соблазн форкнуть корневой compose** (анти-дрейф TC-04 `test_lite_setup_doc.py` упадёт) → bundle строго отдельным файлом. - **R-6 Утечка секретов в логи/репо** при генерации bundle-кред → секрет-эвристика в тестах, запрет печати секретов (NFR-3).