--- work_item: ORCH-104 stage: analysis author_agent: analyst status: ready-for-review created_at: 2026-06-12 model_used: claude-opus-4-8 --- # 01 — BRD (бизнес-требования): ORCH-104 — Установочный скрипт для Lite Work Item: **ORCH-104** · Repo: **orchestrator** (self-hosting) · Стадия: analysis Тип: FEATURE — UX/онбординг тиража (Type A эпика ORCH-10), поверх ORCH-102 (LITE_SETUP.md) > ⚠️ **Объём заморожен (2026-06-12).** Один интерактивный установщик, автоматизирующий > ручной маршрут `docs/deployment/LITE_SETUP.md`. Это **scripts + docs + tests**-изменение: > рантайм/конвейер (`src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, схема БД) — **не трогаются** > (см. §2 «Вне объёма», NFR-1). Установщик НЕ форкает каноны: секреты — кирпичом > `gen_secrets.py`, онбординг — кирпичом `onboard_project.py`, env — из `.env.example`. --- ## 1. Бизнес-контекст и проблема ### 1.1. Цель Максимально упростить установку оркестратора в Lite-режиме на чужой хост: свести тринадцатишаговую ручную инструкцию к **одному запускаемому файлу**, который сам сканирует систему, подсказывает чего не хватает, запрашивает у оператора только действительно неизвестные данные (токены/URL) и доводит инсталляцию до работающего конвейера. ### 1.2. Корневая боль (установленный факт) `docs/deployment/LITE_SETUP.md` (ORCH-102) — золотой источник Lite-тиража, но это **ручной runbook из 13 разделов**. Оператор вручную: проверяет предусловия хоста (§2), клонирует код (§3), копирует `.env.example`, гоняет `gen_secrets.py`, **заполняет ~20 ключей `.env`** по четырём группам (Plane/Gitea/Telegram/хост-порты, §4), настраивает webhook Plane (иногда **прямым SQL в Postgres**, §5.4 путь Б), выпускает токен и webhook Gitea (§6), ставит claude CLI (§7), заводит **два** Telegram-бота (§8), поднимает compose (§9), регистрирует проект `onboard_project.py` (§10), гоняет smoke (§11). Это долго, легко ошибиться (опечатка в секрете → 401 HMAC; неверный uid → worktree не пишется; занятый порт; пропущенный fail-closed статус `Confirm Deploy`/`STOP`), и ошибка часто всплывает поздно — на `docker compose up`, а не в момент ввода. ### 1.3. Почему именно установщик (а не «ещё инструкция») Ручной маршрут уже задокументирован и стабилен (ORCH-102). Ценность ORCH-104 — **автоматизация happy-path и ранняя валидация**: авто-детект всего детектируемого (uid/gid/docker-gid, свободные порты, node/claude, **существующие инсталляции Plane/Gitea**), живая проверка каждого введённого секрета ДО записи в `.env`, идемпотентный безопасный повтор. LITE_SETUP.md остаётся справочником и фолбэком для траблшутинга — установщик его не заменяет, а исполняет. ### 1.4. Установленные факты (переиспользуемые кирпичи — НЕ изобретать) - **`scripts/bootstrap_bundle.py` (ORCH-103)** — ближайший прецедент: step-движок `check→ensure`, режимы `plan`/`apply`/`verify`, exit-коды `0/2/1`, честные `manual_checkpoint` с `input()`/`getpass()`, stdlib-only, секреты не печатаются, **delete-операций нет вообще**, каноны переиспользуются субпроцессами. Установщик Lite — его «connect-only»-сородич: bundle *поднимает* Plane/Gitea, Lite *подключается* к уже существующим. - **`scripts/gen_secrets.py` (ORCH-101)** — выпуск webhook-секретов (`secrets.token_hex(32)`), отказ перезаписи без `--force`. Единственный легитимный источник секретов. - **`scripts/onboard_project.py` (ORCH-009)** — регистрация проекта (22 статуса с точными именами, лейблы `autoApprove`/`autoDeploy`/`Bug`, репо+webhook), `plan`/`apply`/`verify`, идемпотентно, exit `0/2/1`. - **`.env.example` / `.env.watchdog.example`** — канон 100% ключей старта (дефолт каждого ключа = боевому значению, ORCH-101); установщик рендерит `.env` из них, не выдумывая ключи. - **`docker-compose.yml`** — сам по себе является Lite-подмножеством (дефолтный `up -d` поднимает ровно `orchestrator` + `orchestrator-watchdog`; `orchestrator-staging` за профилем `staging`). ### 1.5. Решения владельца (Owner decisions) Предложены Владельцу как рекомендованные дефолты 2026-06-12; приняты для старта анализа, пересматриваемы на review. | ID | Решение | Дата | |----|---------|------| | D-1 | **Установка зависимостей = детект + управляемая установка.** Установщик сканирует, показывает чего не хватает, печатает **точную команду** под обнаруженный дистрибутив и предлагает выполнить безопасные с явного согласия (`y/N`). Системные пакеты под root — только с подтверждением, **никогда молча**. (Совпадает с self-hosting-этосом и каноном `bootstrap_bundle.py`.) | 2026-06-12 | | D-2 | **Plane/Gitea = только подключение (Lite = Type A).** Установщик **детектит существующие** инсталляции; при нескольких — показывает нумерованный список и даёт выбрать; ручной ввод URL — всегда фолбэк. Если их нет вовсе → инструктирует поставить самостоятельно либо указывает на Bundled-тираж (ORCH-103). Установщик их **не поднимает**. | 2026-06-12 | | D-3 | **Режимы = интерактивный мастер + `plan`/`apply`/`verify`.** Канон `bootstrap_bundle.py`: `plan` (дефолт, ноль мутаций) / `apply` / `verify`; exit `0/2/1`; без TTY → fail-closed exit 2 с инструкцией; идемпотентный повтор. Скрипт пригоден и для повторного/CI-прогона. | 2026-06-12 | --- ## 2. Объём (scope) ### В объёме - **FR-1** — Единый entry-point `scripts/install_lite.py` с режимами `plan`/`apply`/`verify`. - **FR-2** — Скан-предусловий хоста (детект docker/compose/git/python3/node/claude CLI/портов/ uid/gid/docker-gid/каталогов) с понятным списком «чего не хватает». - **FR-3** — Управляемая установка недостающих зависимостей (детект дистрибутива → точная команда → выполнение безопасных с согласия; D-1). - **FR-4** — Детект существующих инсталляций Plane/Gitea на хосте + выбор при нескольких + ручной фолбэк (D-2). - **FR-5** — Интерактивный сбор данных оператора (Plane/Gitea/Telegram токены/URL) с **живой верификацией каждого ДО записи** и скрытым вводом секретов. - **FR-6** — Выпуск webhook-секретов строго кирпичом `gen_secrets.py`. - **FR-7** — Сборка `.env` / `.env.watchdog` из канона `.env.example` / `.env.watchdog.example` (идемпотентный рендер, права 600, без молчаливой перезаписи). - **FR-8** — Подъём `orchestrator` + `orchestrator-watchdog` (`docker compose up`) + ожидание готовности. - **FR-9** — Регистрация проекта строго кирпичом `onboard_project.py apply`/`verify` + запись `ORCH_PROJECTS_JSON`. - **FR-10** — Health-верификация (`/health` / `/queue` / `/metrics`) + итоговая сводка PASS/FAIL. - **FR-11** — Синхронизация документации (указатель LITE_SETUP.md на установщик; CLAUDE/README/ overview/CHANGELOG). ### Вне объёма - ❌ **Любые изменения рантайма/конвейера** — `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи, схема БД (NFR-1; установщик вне процесса орка и вне конвейера QG). - ❌ **Подъём самих Plane/Gitea** — это Bundled-тираж (ORCH-103); Lite только подключается (D-2). - ❌ **Полный безусловный авто-install системных пакетов под root без согласия** (D-1 отвергает). - ❌ **Teardown / удаление** — установщик не несёт delete-операций (NFR-4); снос — документированная процедура. - ❌ **Замена LITE_SETUP.md** — runbook остаётся золотым источником и фолбэком (дополняем, не выкидываем). - ❌ **Форк канонов** — секреты/онбординг/env/compose не реимплементируются (NFR-7). - ❌ **Автоматизация интерактивного логина claude CLI** — это поток Anthropic; остаётся верифицируемым manual-step (OQ-6). --- ## 3. Заинтересованные стороны - **Заказчик/инициатор:** Владелец (Слава) — цель «максимально упростить установку для пользователей». - **Прямой пользователь:** внешний оператор/заказчик платформы, разворачивающий Lite на своём хосте. - **Затрагиваемые:** сопровождающие LITE_SETUP.md (норматив синхронизации, BR-9); агенты пайплайна (reviewer — проверка doc-sync; tester — прогон новых тестов). - **Принимает результат:** reviewer (стадия review) + tester (стадия testing) по критериям §03. --- ## 4. Бизнес-требования (BR) | ID | Требование | Связь | |----|------------|-------| | **BR-1** | Один запускаемый файл проводит оператора от «код склонирован» до «работающий Lite-конвейер», автоматизируя LITE_SETUP.md §2–§11. | FR-1, AC-1 | | **BR-2** | Установщик сканирует хост и выдаёт чёткий список отсутствующих предусловий (что есть / чего не хватает). | FR-2, AC-2 | | **BR-3** | Для каждого недостающего предусловия — точная команда установки под обнаруженный дистрибутив + предложение выполнить безопасные с явного согласия (никогда молча, D-1). | FR-3, AC-3 | | **BR-4** | Данные, которые знает только оператор (токены/URL Plane, Gitea, Telegram), запрашиваются интерактивно в момент установки, **каждое — с живой проверкой ДО записи**; секреты вводятся скрыто и не логируются. | FR-5, AC-5, AC-6 | | **BR-5** | Установщик детектит существующие инсталляции Plane и Gitea; при нескольких — показывает список и даёт выбрать; ручной ввод URL — всегда доступный фолбэк (D-2). | FR-4, AC-4 | | **BR-6** | Каноны не форкаются: webhook-секреты — `gen_secrets.py`, регистрация проекта — `onboard_project.py`, env — из `.env.example`/`.env.watchdog.example`, стек — из `docker-compose.yml`. | FR-6, FR-7, FR-9, AC-7 | | **BR-7** | Идемпотентность и наблюдаемость: режимы `plan`(дефолт)/`apply`/`verify`; повтор пропускает завершённые шаги; exit `0/2/1`; без TTY → fail-closed exit 2 с инструкцией; финальная сводка PASS/FAIL. | FR-1, FR-10, AC-8, AC-11 | | **BR-8** | Self-hosting-безопасность: установщик — только scripts/docs/tests; никогда не правит `src/**`/конвейер/схему; исполняется на хосте заказчика; говорит только с локальным хостом и собственными Plane/Gitea/Telegram заказчика; delete-операций нет. | NFR-1, NFR-4, AC-9, AC-10 | | **BR-9** | Норматив сопровождения: установщик автоматизирует LITE_SETUP.md → оба держатся в синхроне (меняешь шаги установки → обнови LITE_SETUP.md в том же PR; держит анти-дрейф тест). | FR-11, AC-12 | --- ## 5. Нефункциональные требования (NFR) | ID | Требование | |----|------------| | **NFR-1** | **Рантайм байт-в-байт.** `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, machine-verdict ключи, схема БД — не трогаются. Kill-switch не нужен: активация = только явный запуск оператором (паттерн ORCH-009/102/103). | | **NFR-2** | **Гигиена секретов.** Значения секретов никогда не печатаются в stdout/логи; `.env`/`.env.watchdog` пишутся правами 600; существующие секреты не перетираются без явного согласия/`--force`. | | **NFR-3** | **Never-raise в детекте.** Сбой любой эвристики обнаружения/пробы деградирует на ручной ввод и не роняет установщик и не блокирует прогон (best-effort, fail-safe). | | **NFR-4** | **Нет delete-операций** нигде в скрипте (teardown — только документированная процедура; зеркало ORCH-103 D9). | | **NFR-5** | **Идемпотентный ensure.** Каждый шаг `check→ensure`; повтор безопасен; валидный существующий конфиг пропускается; дублей проекта/webhook не создаётся. | | **NFR-6** | **stdlib-only.** Никаких новых зависимостей платформы — работает на голом `python3` целевого хоста ДО первого `docker compose up` (как `gen_secrets.py`/`bootstrap_bundle.py`). Каноны-знания — только субпроцессами кирпичей. | | **NFR-7** | **Детерминированные анти-дрейф тесты.** В unit-тестах — без сети/docker/subprocess/LLM; чистые функции изолированы; HTTP/процессы — через инъекцию фейков. | | **NFR-8** | **Кросс-дистрибутив.** Детект и команды установки работают на распространённых Linux (Debian/Ubuntu `apt`, RHEL/Fedora `dnf`); неизвестный дистрибутив → деградация на «инструктировать». | --- ## 6. Допущения и ограничения - **Контур Lite** (LITE_SETUP §1–§2): Linux x86_64, у оператора есть root/sudo для установки системных пакетов (или он ставит их сам). Вне контура — вне гарантии. - **Plane и Gitea — собственные инсталляции заказчика** (Type A). Установщик к ним подключается, не управляет их жизненным циклом. - **Plane CE не даёт API первичной инициализации/иногда webhook** (LITE_SETUP §5.4): такие шаги остаются честными manual-step с верификацией результата (контракт `manual_checkpoint`). - **Интерактивный логин claude CLI** не автоматизируется (поток Anthropic) — manual-step (OQ-6). - **Платформенные конвенции (не менять):** репо обязан называться `orchestrator` (`SELF_HOSTING_REPO`); имена compose-сервисов/профиля — константы; `ORCH_STAGING_PORT` ≠ прод-порт (fail-closed guard ORCH-058). --- ## 7. Критерии успеха (резюме) Оператор на свежем хосте запускает один файл, отвечает на минимум вопросов (только то, что система не может определить сама), и получает поднятый Lite-контур с зарегистрированным проектом и зелёными `/health` `/queue` `/metrics`. Повторный запуск безопасен и пропускает сделанное. Рантайм не изменён. Детальные PASS/FAIL — в `03-acceptance-criteria.md`. --- ## 8. Риски (кратко; детали — 10-tech-risks.md, заполняет архитектор) - **R-1** — Эвристика детекта Plane/Gitea ложно-положительна/отрицательна (нестандартные имена контейнеров/порты) → митигируется ручным фолбэком (NFR-3) и живой верификацией URL (BR-4). - **R-2** — Авто-install системных пакетов небезопасен/дистрибутиво-зависим → митигируется D-1 (только с согласия, точная команда, неизвестный дистрибутив → инструктировать). - **R-3** — Дрейф установщик ↔ LITE_SETUP.md при будущих правках → митигируется BR-9 + анти-дрейф тестом. - **R-4** — Случайная утечка секрета в лог/перетирание `.env` → митигируется NFR-2 (маскирование, 600, без silent overwrite), покрыто AC-6. - **R-5** — Дублирование логики `bootstrap_bundle.py` (parse_env/render_env/manual_checkpoint) → архитектурный вопрос «общий модуль vs самодостаточный файл» (OQ-4), не блокирует анализ.