Files
orchestrator/docs/work-items/ORCH-104/02-trz.md
claude-bot 94a3f399f2
All checks were successful
CI / test (push) Successful in 58s
analyst(ET): auto-commit from analyst run_id=638
2026-06-11 20:19:18 +03:00

272 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
work_item: ORCH-104
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-11
model_used: claude-opus-4-8
---
# 02 — ТЗ (TRZ): ORCH-104 — Установочный скрипт Lite-тиража (интерактивный installer)
Work Item: **ORCH-104** · Repo: **orchestrator** · Стадия: analysis
> ТЗ описывает **что** должно измениться и **где** (модули/контракты/артефакты). **Как**
> (имя/режимы скрипта, эвристики discovery, степень автоматизации отдельных шагов) — решает
> архитектор в `06-adr/`. Тип изменения — **scripts + docs + tests** (паттерн ORCH-009/103):
> рантайм `src/**` байт-в-байт.
---
## 1. Сводка изменения
Ввести **единый операторский установочный скрипт Lite-тиража**: один файл в `scripts/`,
который интерактивно проводит внешнего оператора по маршруту `docs/deployment/LITE_SETUP.md`
§2§12 — сканирует предусловия хоста и предлагает доустановить недостающее, обнаруживает
инсталляции Plane/Gitea (при нескольких — даёт выбрать), запрашивает обязательные ключи в
момент установки с немедленной верификацией, автодетектит хост-параметры, собирает
`.env`/`.env.watchdog` от канонов, поднимает Lite-контур, регистрирует проект заказчика
кирпичом `onboard_project.py` и выдаёт итоговый вердикт PASS/MANUAL/FAIL с exit-кодами
`0/2/1`. Паттерн — `bootstrap_bundle.py` (ORCH-103): step-движок check→ensure, stdlib-only,
no-delete, manual-checkpoint с верификацией, идемпотентный повтор. Канон LITE_SETUP.md не
форкается — скрипт становится в нём рекомендованным быстрым путём, ручной маршрут сохраняется.
---
## 2. Задействованные модули / пути
| Путь | Действие | Роль в задаче |
|------|----------|---------------|
| `scripts/setup_lite.py` *(имя-кандидат; финал — архитектор)* | **создать** | единый установочный CLI: step-движок, скан, discovery, интерактивный сбор, сборка конфигов, запуск, отчёт |
| `scripts/gen_secrets.py` | переиспользовать, **не менять** | кирпич выпуска webhook-секретов (субпроцесс — паттерн AC-7 ORCH-103: канон-знания только субпроцессами кирпичей) |
| `scripts/onboard_project.py` | переиспользовать, **не менять** | кирпич регистрации проекта: Plane-проект + 22 статуса + лейблы, Gitea-репо + webhook, merged-`ORCH_PROJECTS_JSON` |
| `docs/deployment/LITE_SETUP.md` | **обновить** | скрипт = рекомендованный быстрый путь; ручной маршрут остаётся каноном-fallback; размещение не ломает пиннинг «13 разделов в порядке» ЛИБО тест обновляется синхронно |
| `tests/test_setup_lite_script.py` *(имя-кандидат)* | **создать** | анти-дрейф + unit чистых функций (по образцу `tests/test_bootstrap_script.py`) |
| `tests/test_lite_setup_doc.py` | обновить **при необходимости** | если меняется пиннингуемая структура LITE_SETUP.md (разделы/кирпичи) |
| `CHANGELOG.md` | обновить | запись `feat:` |
| `docs/overview/` | обновить **при необходимости** | если витрина описывает маршрут Lite-тиража (таблица соответствия — в индексе витрины, правило агентов №2/ORCH-011) |
| `src/**`, `docker-compose.yml`, `Dockerfile`, `.env.example`, `.env.watchdog.example` | **НЕ менять** | каноны-источники: скрипт их только читает (шаблоны env, состав сервисов) |
---
## 3. Функциональные требования
### FR-1 — Единая точка входа, режимы, идемпотентность (BR-1, BR-5)
- Один файл; запуск `python3 scripts/setup_lite.py …` из корня чекаута репо `orchestrator`
на голом python3 (до venv и до `docker compose up`).
- Обязательны как минимум: **read-only режим диагностики** (ноль мутаций: скан предусловий +
discovery + план шагов — аналог `plan` ORCH-103) и **установочный интерактивный режим**
(аналог `apply`); желателен `verify` (read-only пост-проверка). Дефолтный режим и имена —
решение архитектора (OQ-1) с учётом паттерна D5 ORCH-009/103 («plan — дефолт») и
бизнес-цели «одна команда».
- Step-движок **check→ensure**: каждый шаг сперва проверяет «уже сделано?» и при PASS
пропускается → повторный запуск идемпотентен; «resume» после manual-step = просто повторный
запуск (паттерн `bootstrap_bundle.run_apply`).
- **Exit-коды (контракт):** `0` — все шаги PASS; `2` — остановка на manual-step /
незавершённое предусловие; `1` — ошибка.
- Каждая мутация хоста — с **явного согласия** пользователя (per-action consent); отказ от
согласия → честный MANUAL-шаг с печатью эквивалентной команды, не молчаливый пропуск.
### FR-2 — Скан предусловий с офером установки (BR-2; LITE_SETUP §2, §7)
- Проверяемый перечень (каждый пункт — отдельный вердикт `OK | MISSING | WARN | MANUAL`):
1. ОС/арх: `uname -sm` = Linux x86_64 (иное → WARN «вне контура Lite»);
2. `docker --version`, `docker compose version` (v2), `git --version`, `python3 --version`,
`node --version`;
3. дистрибутив claude-code (`npm root -g` → каталог `@anthropic-ai/claude-code`) и
аутентификация CLI (читаемость `~/.claude/.credentials.json` uid'ом из п.5);
4. группа docker (`getent group docker` → gid для `ORCH_DOCKER_GID`);
5. uid/gid пользователя-владельца и каталога репозиториев (`ORCH_HOST_REPOS_DIR`,
инвариант ORCH-040: владелец = `ORCH_RUN_UID:ORCH_RUN_GID`);
6. каталог ssh-ключей (`ORCH_HOST_SSH_DIR`): существование/ключи;
7. свободность портов (прод/staging, дефолты 8500/8501).
- Для каждого `MISSING`: определить пакетный менеджер хоста (например apt/dnf/yum/zypper —
точный набор фиксирует архитектор) → предложить **конкретную команду установки** → выполнить
её ТОЛЬКО с явного согласия; для node+claude-code — офер `npm install -g
@anthropic-ai/claude-code`; для ssh-ключей — офер `ssh-keygen` (+ печать pubkey как
manual-step «добавить в Gitea», §2.4/§6.2).
- Неопределимый дистрибутив/менеджер, отказ пользователя, sudo-недоступность → честный
**MANUAL** с готовыми командами и ссылкой на § LITE_SETUP; молчаливый пропуск запрещён.
- Интерактивный OAuth-логин claude CLI скрипт **не выполняет** — только верифицирует
результат (§7.2) и выдаёт manual-step.
### FR-3 — Discovery инсталляций Plane/Gitea (BR-4)
- Источник — **локальный Docker**: перечисление контейнеров, группировка в «инсталляции» по
метке compose-проекта (`com.docker.compose.project`), опознание по именам образов
(Plane: `makeplane/*`-семейство; Gitea: `gitea/*`) и published-портам; точные
эвристики/паттерны — ADR. Из кандидата выводятся **предлагаемые** URL
(`ORCH_PLANE_API_URL`/`ORCH_PLANE_WEB_URL`; `ORCH_GITEA_URL`/`ORCH_GITEA_PUBLIC_URL`).
- Поведение по числу найденных: **0** → ручной ввод URL + честная подсказка «Lite не
устанавливает Plane/Gitea; нет инфраструктуры — см. Bundled (BUNDLED_SETUP.md)»; **1**
префилл по умолчанию (с подтверждением); **≥2** → нумерованный список (проект, образы,
порты) + выбор. Пункт **«ввести вручную»** доступен всегда.
- **Best-effort, never-block:** docker недоступен / ошибка перечисления / не-docker
инсталляция (native/k8s) → ручной ввод, не FAIL.
- Discovery заполняет только кандидаты URL; **токены всегда вводит пользователь** (FR-4);
выбранный кандидат всё равно проходит верификацию FR-4.
### FR-4 — Интерактивный сбор обязательных ключей с немедленной верификацией (BR-3)
- Покрывается карта обязательных ключей нового хоста — **§4.2 LITE_SETUP** (группы: Plane,
Gitea, webhook-секреты, Telegram, `ORCH_PROJECTS_JSON`, хост-параметры, порты).
- Секретные значения вводятся **скрыто** (`getpass`-класс ввода) и **никогда не печатаются**
(ни в stdout, ни в лог; только имена ключей) — паттерн NFR-3 ORCH-103.
- Немедленная верификация каждого введённого значения фактическим вызовом:
- Plane: `GET $ORCH_PLANE_API_URL/api/v1/workspaces/<slug>/projects/` c `X-API-Key` → 200;
- Gitea: `GET $ORCH_GITEA_URL/api/v1/user` c токеном → 200 (+ владелец → `ORCH_GITEA_OWNER`);
- Telegram: `getMe``"ok":true`; helper определения chat-id через `getUpdates`;
- публичный URL оркестратора (для webhook'ов) — синтаксическая валидация + предупреждение,
что достижимость со стороны Plane/Gitea проверится на smoke.
- Неуспех верификации → re-prompt с диагнозом (ограниченное число попыток — паттерн
`manual_checkpoint(max_tries=3)`), затем честный MANUAL/остановка exit 2 — не бесконечный
цикл и не молчаливое принятие.
- **non-TTY** (нет интерактива): честный отказ с подсказкой ЛИБО неинтерактивная альтернатива
(флаги/answers-file — механизм решает архитектор, OQ-2); зависание недопустимо.
### FR-5 — Автодетект хост-параметров и когерентность портов (BR-2, BR-6)
- Автоматически определяются и НЕ спрашиваются у пользователя (только подтверждение):
`ORCH_RUN_UID`/`ORCH_RUN_GID` (uid/gid владельца `ORCH_HOST_REPOS_DIR` / текущего
пользователя), `ORCH_DOCKER_GID` (`getent group docker`), `ORCH_HOST_NODE_BIN`
(`which node`), `ORCH_HOST_CLAUDE_CODE_DIR` (`npm root -g`), `ORCH_AGENT_HOME_DIR` /
`ORCH_HOST_CLAUDE_DIR` / `ORCH_HOST_CLAUDE_JSON` (HOME пользователя из §2.2),
`ORCH_DEPLOY_HOST_REPO_PATH` (корень чекаута).
- Порты: busy-check (`ss`/socket) прод- и staging-портов; занят → предложить альтернативу.
Смена прод-порта → **синхронно** согласовать тройку `ORCH_DEPLOY_PROD_TARGET_PORT`
`WATCHDOG_METRICS_URL``ORCH_POST_DEPLOY_BASE_URL` (§2.5/§4.2). `ORCH_STAGING_PORT` ==
прод-порт → **отказ fail-closed** (инвариант ORCH-058, усилен ORCH-101).
### FR-6 — Сборка `.env` / `.env.watchdog` (BR-5; LITE_SETUP §4)
- `.env` собирается **от канона `.env.example`** (принцип ORCH-101: дефолт = боевое значение;
записываются только собранные отличия нового хоста). `.env.watchdog` — от
`.env.watchdog.example` (ключи `WATCHDOG_TG_BOT_TOKEN`/`WATCHDOG_TG_CHAT_ID` кладутся
**только туда** — ловушка файла-носителя §4.3).
- Webhook-секреты — **кирпичом `gen_secrets.py`** (свежий выпуск; боевые секреты не
используются — stateless §12 / REPLICATION §3).
- **Существующий `.env`/`.env.watchdog` → отказ** (exit 2, внятное сообщение); перезапись —
только явный force-флаг (паттерн `gen_secrets --force` / `--force-secrets` ORCH-103).
Подсказки-дефолты промптов — из `.env.example`/автодетекта, **никогда** из боевых значений.
- После сборки — резолв-проверка `docker compose config` (PASS/FAIL, §4 «Проверка»).
### FR-7 — Подключения и машинная охрана нормативов (BR-3, BR-6)
- **Plane (§5):** наличие workspace/доступность API верифицируются (FR-4); статусы/лейблы
вручную НЕ создаются (только кирпич onboarding, §5.3). **Webhook (§5.4, каверза Plane CE):**
Path A (UI) = manual-checkpoint с инструкцией и верификацией; Path Б (SQL в Postgres Plane)
= только с **явного согласия** + подтверждённый пользователем контейнер БД Plane +
пост-верификация (`SELECT url, is_active FROM webhooks`); выбор степени автоматизации — ADR
(OQ-3). Молчаливый пропуск запрещён.
- **Gitea (§6):** токен верифицирован (`/api/v1/user`); **branch protection на `main`:**
непустой `branch_protections`**FAIL шага с лечением** (норматив §6.4 / ADR D10 ORCH-009 /
INV-4); скрипт правила **сам не удаляет** (no-delete) — только инструкция. Per-repo webhook
и репо создаёт кирпич onboarding (FR-9), не сам скрипт.
- **Telegram (§8):** два независимых бота; **идентичные токены орка и watchdog → отказ шага**
(C-1 ORCH-100 «ЗАПРЕЩЕНО» — машинная проверка, не примечание).
- **LLM (§7):** верификация дистрибутива/нод-бинаря/читаемости кредов uid'ом контейнера;
наличие `ORCH_AGENT_MODEL_DEFAULT`/`ORCH_AGENT_EFFORT_DEFAULT` в собранном `.env` (§7.3).
### FR-8 — Запуск Lite-контура и health (BR-6; LITE_SETUP §9, §12)
- С согласия: `docker compose up -d --build`; проверка состава: запущены **ровно**
`orchestrator` + `orchestrator-watchdog`, `orchestrator-staging` НЕ поднят (строго за
`profiles: [staging]`).
- Health-чек контрактов: `/health` → 200 `"status":"ok"`; `/queue` → штатный JSON;
`/metrics``"schema_version": 1` (порт — фактический из конфига).
- Stateless-проверка чистоты (§12): счётчики jobs нулевые, ни одной задачи чужих проектов;
нарушение → FAIL с лечением «пересобрать `data/` с нуля».
### FR-9 — Регистрация проекта заказчика кирпичом onboarding (BR-6, BR-7; LITE_SETUP §10)
- Скрипт собирает параметры проекта (имя/описание/repo/prefix/stack/test-cmd/порты/
webhook-url из публичного URL оркестратора) и строит аргументы вызова
`onboard_project.py` **детерминированной чистой функцией** (тестируемо без сети).
- Последовательность: `plan` → показать пользователю → согласие → `apply``verify`
(субпроцессы; exit 2 кирпича = остались ручные шаги → транслировать как MANUAL).
Степень автоматизации vs «печать готовой команды» — ADR (OQ-6; прецедент драйва —
`bootstrap_bundle.step_onboard`).
- `ORCH_PROJECTS_JSON` из отчёта `apply` вписывается в `.env` (с согласия); затем управляемый
рестарт **только собственного свежеподнятого** контура по процедуре §10: проверка тихого
окна (`/queue` без running-job) → `docker compose up -d --force-recreate orchestrator`
пост-проверка `/health`+`/queue`.
### FR-10 — Итоговый отчёт (BR-1, BR-6)
- Финальная сводная таблица всех шагов: PASS/FAIL/MANUAL; для каждого MANUAL — что сделать и
ссылка на § LITE_SETUP; для FAIL — диагноз и лечение (зеркало §13 траблшутинга).
- Smoke первой задачи (§11: issue → «To Analyse» → артефакты `0104`) выдаётся как
завершающая manual-инструкция (вердикт «тираж PASS» — за оператором).
### FR-11 — Документация: канон не форкается (BR-7)
- `docs/deployment/LITE_SETUP.md`: скрипт вводится как **рекомендованный быстрый путь**
(врезка/подраздел в начале маршрута); ручной маршрут §2§13 сохраняется как канон и
fallback для MANUAL-шагов. Размещение либо не ломает пиннинг
`test_doc_exists_with_all_13_sections_in_order`, либо тест обновляется в том же PR.
- Норматив сопровождения (NFR-5 ORCH-102) расширяется симметрично: «меняешь шаги тиража →
обнови LITE_SETUP.md **и установочный скрипт** в том же PR».
---
## 4. Изменения API
**Нет.** Эндпоинты оркестратора не добавляются и не меняются; скрипт — потребитель
существующих read-only контрактов (`/health`, `/queue`, `/metrics`) и внешних API
(Plane/Gitea/Telegram).
## 5. Изменения схемы БД
**Нет.** БД оркестратора не затрагивается (создаётся пустой при первом старте — штатно);
БД Plane заказчика — только опциональная webhook-вставка Path Б §5.4 (FR-7, с согласия).
## 6. Требования к новым/изменённым QG checks
**Нет.** Скрипт — операторский инструмент вне рантайма и вне конвейера;
`STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict ключи — байт-в-байт.
## 7. Совместимость / регресс
- **Kill-switch не нужен:** активация — только явный запуск CLI человеком (паттерн
ORCH-009/102/103); рантайм не несёт ни одной новой кодовой ветки.
- Полный существующий регресс `pytest tests/ -q` остаётся зелёным; `test_lite_setup_doc.py`
зелёный (с синхронным обновлением при правке структуры дока).
- Обратимость: задача добавляет файлы `scripts/` + `tests/` + правку дока; откат = revert PR,
поведение платформы не меняется в обе стороны.
- Скрипт не вносит хост-литералов в `src/**` (вне скана `test_no_host_hardcodes.py` по
определению, т.к. `src/**` не трогается).
## 8. Конфигурация
Новых ключей `Settings`/`.env.example` **не вводится**. Скрипт читает каноны
`.env.example`/`.env.watchdog.example` как шаблоны и пишет целевые `.env`/`.env.watchdog`
(FR-6). Платформенные константы (`SELF_HOSTING_REPO="orchestrator"`, имена сервисов, layout
контейнера) не параметризуются (норматив REPLICATION §1).
## 9. Наблюдаемость
- Структурный stdout-лог прогона (шаг → вердикт → диагноз) + итоговая таблица (FR-10).
- Exit-код = машинный итог прогона (`0/2/1`) — пригоден для обвязки/CI заказчика.
- Опциональный файл-отчёт прогона — на усмотрение архитектора (ADR).
## 10. Артефакты pipeline (создать/обновить в ТОМ ЖЕ PR)
- `docs/work-items/ORCH-104/06-adr/ADR-001-<slug>.md` — решения: имя/режимы скрипта,
эвристики discovery, политика оферов установки, автоматизация webhook Path Б и onboarding,
механизм non-TTY (архитектор).
- `docs/deployment/LITE_SETUP.md` — быстрый путь (FR-11).
- `tests/test_setup_lite_script.py` (+ правка `tests/test_lite_setup_doc.py` при
необходимости).
- `CHANGELOG.md` — запись `feat:`; витрина `docs/overview/` — если затронуто описание тиража.
## 11. Инварианты (не нарушать)
- `src/**`, корневой `docker-compose.yml`, `Dockerfile`, `STAGE_TRANSITIONS`, `QG_CHECKS`,
`check_*`, machine-verdict ключи, схема БД — **байт-в-байт**.
- **stdlib-only**; модули платформы не импортируются; канон-знания — только субпроцессами
кирпичей (`gen_secrets.py`, `onboard_project.py`).
- **No-delete:** ни одной удаляющей операции (файлы, контейнеры, ветки, правила) — лечение
всегда инструкцией.
- **Никогда** не push/force-push/иные операции в `main` (INV-4); не рестартить чужие/боевые
контейнеры; мутации — только с явного согласия.
- Секреты: свежие, скрытый ввод, не печатаются; существующие `.env*` молча не перетираются.
- Stateless: данные/задачи/секреты исходного хоста не переносятся ни одним шагом.
## 12. Открытые вопросы для архитектора (не блокируют анализ)
- **OQ-1:** имя скрипта и набор/дефолт режимов: строгий паттерн D5 (`plan` — дефолт,
мутации только в `apply`) vs «запуск без аргументов = wizard» (бизнес-цель «одна команда»).
Возможный компромисс: wizard-дефолт, где фаза скана всегда read-only, а мутации — за
per-action consent.
- **OQ-2:** механизм неинтерактивного прогона (флаги / answers-file / env-переменные) и
точное поведение в non-TTY.
- **OQ-3:** webhook Plane: автоматизировать ли Path Б (SQL) или строго manual-checkpoint;
критерий выбора/подтверждения контейнера Postgres Plane.
- **OQ-4:** политика оферов установки: исполнять команды пакетного менеджера из скрипта
(с согласия) vs только печатать (безопаснее); набор поддерживаемых менеджеров.
- **OQ-5:** размещение быстрого пути в LITE_SETUP.md (врезка в §1 vs новый раздел с правкой
пиннинга «13 разделов») и судьба нумерации.
- **OQ-6:** степень драйва onboarding: субпроцесс plan→apply→verify изнутри скрипта
(прецедент `bootstrap_bundle.step_onboard`) vs печать готовой команды.