---
work_item: ORCH-104
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-12
model_used: claude-opus-4-8
---

# 02 — ТЗ (TRZ): ORCH-104 — Установочный скрипт для Lite

Work Item: **ORCH-104** · Repo: **orchestrator** · Стадия: analysis

> ТЗ описывает **конкретные требования к реализации**, выведенные из BRD и фактического кода.
> Архитектурное обоснование (структура скрипта, точные эвристики детекта, общий код с
> `bootstrap_bundle.py`, финальное имя файла) — задача архитектора (`06-adr/`). Открытые вопросы —
> §12.

## 1. Сводка изменения
Добавляется **один интерактивный установщик** `scripts/install_lite.py`, автоматизирующий ручной
маршрут `docs/deployment/LITE_SETUP.md` §2–§11 для Lite-тиража (Type A). Скрипт сканирует хост,
детектит/предлагает доустановить зависимости, обнаруживает существующие Plane/Gitea (выбор при
нескольких), интерактивно собирает и **живо верифицирует** токены/URL, выпускает секреты кирпичом
`gen_secrets.py`, собирает `.env`/`.env.watchdog` из канон-`.example`, поднимает `orchestrator` +
`orchestrator-watchdog`, регистрирует проект кирпичом `onboard_project.py` и проверяет health.
Изменение **аддитивно** и **вне рантайма**: `src/**`/`STAGE_TRANSITIONS`/`QG_CHECKS`/схема БД — не
трогаются; kill-switch не нужен (активация — только явный запуск). Каноны не форкаются.

## 2. Задействованные модули / пути

| Путь | Действие |
|------|----------|
| `scripts/install_lite.py` | **создать** — интерактивный установщик Lite (entry-point; имя — OQ-1) |
| `scripts/gen_secrets.py` | **переиспользовать** (subprocess-кирпич), без изменений |
| `scripts/onboard_project.py` | **переиспользовать** (subprocess-кирпич, `apply`/`verify`), без изменений |
| `.env.example`, `.env.watchdog.example` | **переиспользовать** как канон-источник рендера, без изменений |
| `docker-compose.yml` | **переиспользовать** (`docker compose up -d --build`), без изменений |
| `scripts/bootstrap_bundle.py` | **эталон-паттерн** (parse_env/render_env/preflight_verdict/manual_checkpoint/exit-коды) — не изменяется; общий код — OQ-4 |
| `docs/deployment/LITE_SETUP.md` | **обновить** — указатель на установщик как рекомендованный путь + синхронизация шагов |
| `tests/test_install_lite_script.py` | **создать** — unit (чистые функции) + структурные анти-дрейф тесты |
| `tests/test_lite_setup_doc.py` | **обновить** — ассерт ссылки на установщик; существующие ассерты зелёные |
| `CLAUDE.md`, `CHANGELOG.md`, `docs/architecture/README.md`, `docs/overview/` | **обновить** (docs golden-source, правило агентов №2) |

## 3. Функциональные требования

### FR-1 — Entry-point и режимы
Скрипт `scripts/install_lite.py`, запускаемый из корня чекаута: `argparse`, позиционный `mode ∈
{plan, apply, verify}` (дефолт `plan`). Exit-коды (контракт): **0** — успех; **2** — остановка на
manual-step / незавершённое предусловие / нет TTY; **1** — ошибка. `plan` — ноль мутаций (печать
плана + read-only preflight-диагностика). `apply` — полный прогон step-движком `check→ensure`
(повтор = каскад skip; «resume» = повторный запуск). `verify` — read-only пост-проверка
(health-контракты + `onboard_project.py verify`). Привязка: BR-1, BR-7.

### FR-2 — Скан предусловий хоста (preflight)
Read-only снимок хоста (по образцу `bootstrap_bundle.collect_facts`/`preflight_verdict`): наличие
`docker`, `docker compose` v2, `git`, `python3`, `node`, `claude` CLI + читаемость кред; свободность
портов (прод-порт `ORCH_DEPLOY_PROD_TARGET_PORT` дефолт 8500, при self-hosting-вилке staging 8501);
`uid`/`gid`/`docker-gid` и владелец каталога репозиториев; наличие ssh-каталога. Чистая функция-
вердикт возвращает `(blockers, warnings)`; человекочитаемый список «есть/нет». Привязка: BR-2.

### FR-3 — Управляемая установка зависимостей (D-1)
Для каждого блокера-зависимости: детект пакетного менеджера (`apt`/`dnf` по наличию бинаря /
`/etc/os-release`) → **точная команда** установки (чистая функция «дистрибутив+пакет → команда»);
печать команды; для безопасных — предложение выполнить с согласия (`y/N`, `input()`); отказ/нет
TTY/неизвестный дистрибутив → печать инструкции и `exit 2` (никакой молчаливой root-мутации).
Привязка: BR-3, AC-3.

### FR-4 — Детект существующих Plane/Gitea + выбор (D-2)
Best-effort обнаружение (never-raise, NFR-3): кандидаты из `docker ps` (имена/образы, похожие на
Plane: `plane-*`/`makeplane`/`proxy`; Gitea: `gitea/gitea`/`gitea-*`) и из слушающих портов
(типовые Plane 80/8080/443, Gitea 3000). По кандидату — проба живости (Plane: `GET /api/instances/`;
Gitea: `GET /api/v1/version`). Чистая функция формирует ранжированный список кандидатов. Поведение:
0 кандидатов → запрос ручного URL; ≥2 → нумерованный список + выбор (`input()` индекс), вне
диапазона → ручной ввод; 1 → предложить с подтверждением. Выбор наполняет `ORCH_PLANE_*` /
`ORCH_GITEA_*`. Привязка: BR-5, AC-4.

### FR-5 — Интерактивный сбор данных + живая верификация
Honest-checkpoint контракт (как `bootstrap_bundle.manual_checkpoint`): для каждого требуемого
секрета/параметра — печать откуда взять (ссылка на LITE_SETUP §5–§8), скрытый ввод секрета
(`getpass`), **верификация ДО записи**: Plane — `GET /api/v1/workspaces/<slug>/projects/` с
`X-API-Key`; Gitea — `GET /api/v1/user` с `Authorization: token`; Telegram — `GET /bot<token>/getMe`.
Провал → повтор (до N) или `exit 2` с подсказкой, значение **не пишется**. Авто-детект и
пред-заполнение всего детектируемого (uid/gid/docker-gid/порты/пути/node/claude/выбранные URL) —
оператор только подтверждает. Привязка: BR-4, AC-5.

### FR-6 — Выпуск webhook-секретов кирпичом `gen_secrets.py`
`ORCH_PLANE_WEBHOOK_SECRET` / `ORCH_GITEA_WEBHOOK_SECRET` выпускаются **строго** субпроцессом
`gen_secrets.py` (никакого собственного `secrets.token_hex` в установщике — анти-форк, AC-7); если
уже присутствуют в `.env` и валидны — пропуск (не перетирать без `--force`). Привязка: BR-6, NFR-2.

### FR-7 — Сборка `.env` / `.env.watchdog`
Идемпотентный рендер из канона (`render_env`-паттерн): существующий файл — обновить ключи-
override, отсутствующий — отрендерить из `.env.example` / `.env.watchdog.example`; комментарии
канона сохранены; неизвестные ключи — управляемым блоком в конец; запись правами **600**; значения
секретов в stdout/лог **не попадают**; молчаливой перезаписи нет. Watchdog-ключи (`WATCHDOG_TG_*`)
кладутся **только** в `.env.watchdog` (файл-носитель, LITE_SETUP §4.3). Привязка: BR-6, NFR-2.

### FR-8 — Подъём стека + готовность
`docker compose up -d --build` ровно `orchestrator` + `orchestrator-watchdog` (staging НЕ
поднимается — за профилем). Ожидание готовности поллингом `GET /health` (таймаут). Перед записью
`ORCH_PROJECTS_JSON` стек уже жив. Привязка: BR-1.

### FR-9 — Регистрация проекта кирпичом `onboard_project.py`
Сбор параметров проекта (имя/repo/prefix/стек/тест-команда/порты/webhook-URL — флаги или интерактивно),
вызов `onboard_project.py apply` затем `verify` субпроцессом; парс merged-`ORCH_PROJECTS_JSON` из
отчёта и запись в `.env`; ручные пункты отчёта (manual-step) пробрасываются оператору. **Никакого
собственного создания статусов/лейблов/репо** (анти-форк, 22 статуса — только онбординг-кирпич).
Привязка: BR-6, AC-7.

### FR-10 — Health-верификация + сводка
После `apply` (и в `verify`): `GET /health` → 200, `GET /queue` / `GET /metrics` → валидный JSON.
Итоговая сводка по шагам (`ok`/`skipped`/`manual-step`) + общий вердикт; любой FAIL → `exit 1` с
диагностикой (хвост `docker logs` / снапшот). Привязка: BR-7, AC-11.

### FR-11 — Синхронизация документации
`LITE_SETUP.md` дополняется указателем «рекомендованный путь — `install_lite.py`; ручной маршрut
ниже как фолбэк/референс». Обновляются `CLAUDE.md` (раздел тиража), `docs/architecture/README.md`
(Type A), `docs/overview/` (если затронута витрина), `CHANGELOG.md`. Привязка: BR-9, AC-12.

## 4. Изменения API
**Нет.** Установщик — вне процесса орка; обращается только к существующим read-only эндпоинтам
(`/health`, `/queue`, `/metrics`) как HTTP-клиент и к собственным Plane/Gitea/Telegram заказчика.
Новых/изменённых эндпоинтов оркестратора не вводится.

## 5. Изменения схемы БД
**Нет.** Установщик не касается БД оркестратора (её создаёт сам орк пустой при первом старте,
stateless-инвариант LITE_SETUP §12).

## 6. Требования к новым/изменённым QG checks
**Нет.** `QG_CHECKS` / `check_*` / `STAGE_TRANSITIONS` / machine-verdict ключи — байт-в-байт не
трогаются (INV-1). Установщик не участвует в решении ни одного гейта.

## 7. Конфигурация
Новых **рантайм**-ключей `config.py` / kill-switch — **нет** (NFR-1; активация = явный запуск).
Установщик читает/пишет только `.env` / `.env.watchdog` (канон ключей — `.env.example` /
`.env.watchdog.example`, ORCH-101). CLI-флаги установщика (имена — OQ-7): режим + параметры проекта
для `onboard_project.py` (`--repo`/`--prefix`/`--stack`/…), возможный `--force` (перевыпуск
секретов), возможный `--non-interactive`/значения из env для CI.

## 8. Наблюдаемость
- Прогресс-лог по шагам (`ok`/`skipped`/`manual-step`/`error`) — **без значений секретов** (только
  имена ключей/пути файлов, NFR-2).
- Итоговая сводка PASS/FAIL + код выхода `0/2/1`.
- `manual_checkpoint` печатает точную инструкцию и верифицирует результат (молчаливый пропуск
  запрещён); без TTY → `exit 2` с той же инструкцией.

## 9. Артефакты pipeline (создаются/обновляются)
- `scripts/install_lite.py` (новый исполняемый артефакт).
- `tests/test_install_lite_script.py` (новый), `tests/test_lite_setup_doc.py` (обновление).
- `docs/work-items/ORCH-104/06-adr/ADR-001-<slug>.md` (архитектор) + опц. сквозной
  `docs/architecture/adr/adr-NNNN-*.md`.
- `docs/deployment/LITE_SETUP.md`, `CLAUDE.md`, `docs/architecture/README.md`, `docs/overview/`,
  `CHANGELOG.md` — обновления (BR-9).

## 10. Совместимость / регресс
Аддитивно: новый файл-скрипт + новый тест + правки docs. Существующие кирпичи (`gen_secrets.py`,
`onboard_project.py`) и compose — байт-в-байт. Полный регресс `pytest tests/ -q` остаётся зелёным.
Обратимость — тривиальная (удаление нового файла/теста). Область раската — только хосты заказчиков
Lite; **наш прод не затронут** (установщик исполняется на чужом хосте, говорит только с локальным
хостом и инфраструктурой заказчика).

## 11. Инварианты (не нарушать)
- **INV-1** — `src/**` / `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict ключи /
  схема БД — байт-в-байт.
- **INV-2** — Каноны не форкаются: секреты — `gen_secrets.py`; статусы/лейблы/репо/webhook —
  `onboard_project.py`; env — из `.env.example`/`.env.watchdog.example`; стек — из `docker-compose.yml`.
- **INV-3** — Нет delete-операций (никаких `docker … rm`, `rm -rf`, удаления веток, force-push).
- **INV-4** — Секреты не печатаются; `.env`/`.env.watchdog` — права 600; без молчаливой перезаписи.
- **INV-5** — Никогда не трогает наш прод / `main` / force-push; говорит только с локальным хостом и
  собственными Plane/Gitea/Telegram заказчика.
- **INV-6** — Платформенные конвенции: репо `orchestrator`; имена compose-сервисов/профиля —
  константы; staging за профилем; `ORCH_STAGING_PORT` ≠ прод-порт (guard ORCH-058) — установщик
  уважает, не форкает.
- **INV-7** — stdlib-only (NFR-6).

## 12. Открытые вопросы для архитектора (OQ — не блокируют анализ)
- **OQ-1** — Финальное имя/путь: `scripts/install_lite.py` (понятно конечному оператору) vs
  `scripts/bootstrap_lite.py` (симметрия с `bootstrap_bundle.py`). Рекомендация анализа —
  `install_lite.py`.
- **OQ-2** — Точные эвристики детекта Plane/Gitea (паттерны имён/образов контейнеров, набор
  портов/URL-проб, ранжирование уверенности).
- **OQ-3** — Какие зависимости считать «безопасными для авто-выполнения с согласия» (напр.
  `pip install -r requirements.txt` в venv — да; `apt install docker` под sudo — только consent;
  claude CLI через npm); владелец distro-команд-карты.
- **OQ-4** — Общий код с `bootstrap_bundle.py` (вынести `parse_env`/`render_env`/`manual_checkpoint`
  в общий stdlib-модуль) vs самодостаточный один файл (ради «1 установочный файл» и stdlib-only).
  Trade-off DRY ↔ простота/одно-файловость.
- **OQ-5** — Драйвить ли путь Б Plane-webhook (raw-SQL, LITE_SETUP §5.4) автоматически (как
  `bootstrap_bundle.step_plane_webhook`) или всегда оставлять верифицируемым manual-step.
- **OQ-6** — Подтвердить: интерактивный логин claude CLI остаётся manual-step с верификацией
  (`claude --version` + читаемость кред), не автоматизируется.
- **OQ-7** — Набор CLI-флагов/env для не-интерактивного (CI) прогона: какие входы принимают
  флаги/env vs только prompt.
