Files

200 lines
22 KiB
Markdown
Raw Permalink 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-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** (шаги 06 с PASS/FAIL: config-резолв → `/health``/queue`+`/metrics`
onboard plan/apply/verify → тестовая задача → артефакты `0104` → опц. до `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 проходит: тестовый проект создан, тестовая задача доезжает минимум до артефактов `0104` в ветке (минимальный сигнал 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).