Files
orchestrator/docs/work-items/ORCH-103/02-trz.md

233 lines
22 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-103
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-11
model_used: claude-opus-4-8
---
# 02 — ТЗ (TRZ): ORCH-103 — ORCH-10b Bundled-тираж: весь стек одним комплектом + bootstrap-скрипт
Work Item: **ORCH-103** · Repo: **orchestrator** · Стадия: analysis
> ТЗ фиксирует **что** должно измениться и **где** (артефакты/контракты/границы). **Как**
> (расположение bundle-каталога, состав сервисов Plane-стека, язык/режимы bootstrap, механизм
> сетевой связности) — решает архитектор в `06-adr/`. Архитектурные решения здесь не принимаются.
---
## 1. Сводка изменения
Добавить в репо **Bundled-комплект тиража (Type B эпика ORCH-10)**: (1) отдельный
**bundle-compose** всего стека (орк + watchdog + Gitea + Plane-стек ~14 контейнеров),
(2) **bootstrap-скрипт**, доводящий свежеподнятый стек до рабочего конвейера одним запуском
(с явными manual-step чекпоинтами там, где Plane CE API не позволяет автоматизацию),
(3) **генерацию новых секретов** на инсталляцию (reuse `gen_secrets.py` + bundle-внутренние
креды), (4) инструкцию **`docs/deployment/BUNDLED_SETUP.md`** с требованиями к хосту,
(5) **структурные анти-дрейф тесты**. Всё — вне рантайма и вне конвейера: `src/**`, корневой
`docker-compose.yml`, `Dockerfile`, `STAGE_TRANSITIONS`/`QG_CHECKS`/схема БД — байт-в-байт
(паттерн ORCH-009/ORCH-102). Kill-switch не требуется: активация — только явный запуск
оператором на целевом хосте.
---
## 2. Задействованные модули / пути
| Путь | Действие | Назначение |
|------|----------|------------|
| `deploy/bundled/docker-compose.yml` *(рабочая гипотеза; финальное расположение/имя — ADR; далее «bundle-compose»)* | **создать** | Compose-комплект всего стека (FR-1) |
| `deploy/bundled/.env.bundled.example` *(имя — ADR; далее «bundle-конфиг-канон»)* | **создать** | Канон 100% переменных bundle (порты/версии/плейсхолдеры кред), паттерн `.env.watchdog.example` |
| `scripts/bootstrap_bundle.py` *(имя/язык — ADR)* | **создать** | Bootstrap-скрипт (FR-2) |
| `docs/deployment/BUNDLED_SETUP.md` | **создать** | Golden source инструкции Bundled-тиража (FR-4) |
| `docs/operations/REPLICATION.md` | **изменить (точечно)** | §1: строка Type B → ✅ ORCH-103 + ссылка на BUNDLED_SETUP.md (FR-6) |
| `tests/test_bundle_compose.py` | **создать** | Структура bundle-compose + изоляция корневого compose (FR-5) |
| `tests/test_bundled_setup_doc.py` | **создать** | Канон дока, env-ключи, FORBIDDEN/секрет-эвристика, кросс-рефы (FR-5) |
| `tests/test_bootstrap_script.py` | **создать** | Структурные/unit-ассерты bootstrap (FR-5) |
| `CHANGELOG.md` | **изменить** | Запись `feat: ORCH-103` |
| `.gitignore` | **изменить (при необходимости)** | Сгенерированные на хосте конфиги bundle не коммитятся (NFR-3) |
| **НЕ трогать:** `src/**`, корневой `docker-compose.yml`, `Dockerfile`, `.gitea/workflows/**`, `.env.example` (кроме явно обоснованного в ADR аддитива), `onboarding/**`, промпты `.openclaw/agents/**` | — | NFR-1; анти-дрейф `test_lite_setup_doc.py` (TC-04: ровно 3 сервиса, нет `plane*`/`gitea*`) и `test_no_host_hardcodes.py` остаются зелёными |
---
## 3. Функциональные требования
### FR-1 — Bundle-compose всего стека (BR-1)
- **Отдельный файл**, корневой `docker-compose.yml` не изменяется (жёсткое ограничение:
анти-дрейф TC-04 `tests/test_lite_setup_doc.py` проверяет точное множество сервисов корневого
compose и запрещает подстроки `plane`/`gitea` в именах сервисов/образов/контейнеров).
- **Состав стека:** `orchestrator` (образ собирается из существующего корневого `Dockerfile`
без его правки), `orchestrator-watchdog` (существующий `watchdog/Dockerfile`), Gitea
(+ её хранилище), полный Plane CE-стек (~14 контейнеров: web/admin/space/api/worker/beat/
live/migrator + postgres/redis/mq/minio/proxy — точный состав и версии пиннит архитектор по
upstream-référence). Staging-контур орка (8501) — НЕ в дефолтном `up` (вне скоупа заказчика;
включать ли за профилем — ADR).
- **Пиннинг версий** всех сторонних образов (тег или digest; не `latest`) — NFR-6.
- **Тома:** только именованные/каталожные тома bundle (узнаваемый префикс); чистый первый старт;
пересечений с томами/путями нашего прод-контура нет.
- **Сеть и достижимость (двунаправленно):** (a) Plane→орк и Gitea→орк webhooks доставляются;
(b) орк→Plane API и орк→Gitea API доступны; (c) git push/fetch агентов в Gitea работает.
Механизм (bridge-сеть + публикация портов, `extra_hosts: host-gateway`, host-network — что
выбрать) — ADR; ТЗ фиксирует только инвариант достижимости, проверяемый smoke (FR-6).
- **Порты:** карта портов по умолчанию задокументирована (BUNDLED_SETUP «Требования к хосту»);
порты конфигурируемы через bundle-конфиг; конфликт порта → отказ preflight bootstrap (FR-2),
не молчаливый сбой. Дефолт порта орка — существующий 8500 (`ORCH_DEPLOY_PROD_TARGET_PORT`).
- **Конфиг-канон:** все параметры bundle (порты/версии/пути/плейсхолдеры кред) — в
bundle-конфиг-каноне; key-set синхронизируется структурным тестом (паттерн key-sync
`.env.watchdog.example`, D5 ORCH-102). Ключи орка НЕ дублируются — `.env` орка собирается
bootstrap'ом из существующего канона `.env.example`.
### FR-2 — Bootstrap-скрипт: один запуск до рабочего состояния (BR-2, BR-6, BR-7)
Последовательность (нумерация — норматив поведения; механика шагов — ADR):
1. **Preflight (fail-fast, до любых мутаций):** docker+compose присутствуют; свободные
RAM/диск ≥ задокументированных минимумов; целевые порты свободны; тома bundle отсутствуют
(чистый хост) — иначе явный отказ с подсказкой (BR-7); наличие Claude CLI/кред — warning
(не блокер: конвейер без LLM не поедет, но стек поднимется).
2. **Секреты (FR-3):** генерация полного набора НОВЫХ секретов инсталляции.
3. **Up:** подъём bundle-compose; ожидание готовности каждого сервиса (healthcheck/готовность
БД/завершение миграций Plane и Gitea) с таймаутами и внятной диагностикой.
4. **Init Gitea:** административная учётка + API-токен (через официальные механизмы Gitea —
CLI/env/API; конкретика — ADR); branch protection НЕ настраивается (норматив D10 ORCH-009).
5. **Init Plane:** instance-setup/workspace/API-токен. Всё, что недоступно в CE по API, —
**интерактивный manual-step чекпоинт**: скрипт печатает точную инструкцию (URL/что нажать/
что ввести), ждёт подтверждения, **проверяет результат** (например, валидность введённого
API-токена запросом) и только тогда продолжает (fail-safe; молчаливый пропуск запрещён).
6. **Онбординг sandbox-проекта:** вызов `scripts/onboard_project.py apply` + `verify`
(22 статуса из `plane_sync._PLANE_NAME_TO_KEY`, лейблы `autoApprove`/`autoDeploy`/`Bug`,
Gitea-репо, per-repo webhook под глобальным секретом). Собственная реализация этих шагов
в bootstrap **запрещена** (BR-6, нулевой дрейф канона).
7. **Git-доступ агентов:** обеспечить push/fetch созданного репо из контейнера орка
(ssh-ключ + регистрация в Gitea ИЛИ токен-remote — механизм ADR); клон репо в repos-каталог
орка (`ORCH_HOST_REPOS_DIR`).
8. **Конфиг орка:** собрать `.env` (на базе `.env.example`: URL'ы Plane/Gitea bundle-инсталляции,
токены, webhook-секреты, `ORCH_PROJECTS_JSON` из вывода onboard) и `.env.watchdog`
(из `.env.watchdog.example`); файлы остаются только на целевом хосте.
9. **Health + итог:** `GET /health`, `GET /queue`, `GET /metrics` зелёные; финальная сводка
PASS/FAIL по всем шагам + следующая команда оператора (smoke FR-6).
Требования к скрипту:
- **Идемпотентность:** повторный запуск на уже-инициализированном bundle безопасен
(ensure/skip-семантика, как `onboard_project.py apply`); никаких delete-операций.
- **Exit-коды:** `0` — успех; `2` — остановка на manual-step/незавершённое предусловие;
`1` — ошибка (паттерн `onboard_project.py`).
- **Логи без секретов** (NFR-3): значения кред не печатаются (только имена ключей/пути файлов).
- **Никогда не адресует наш прод:** в скрипте нет боевых хостов/путей (FORBIDDEN-скан),
работает только с локальным docker целевого хоста.
- Желателен режим `plan` (печать шагов без мутаций, паттерн ORCH-009) — финально ADR.
### FR-3 — Инициализация секретов: новые на каждую инсталляцию (BR-4)
- **Webhook-секреты орка** — строго через существующий `scripts/gen_secrets.py`
(не реализовывать заново).
- **Bundle-внутренние креды** (генерирует bootstrap, криптослучайно, stdlib `secrets`):
пароли postgres/redis*/mq/minio Plane-стека, секрет-ключи Plane, админ-пароль и API-токен
Gitea. В репо — только плейсхолдеры в bundle-конфиг-каноне; **ни одного дефолтного пароля**.
- **Внешние секреты заказчика** (не генерятся, чек-лист в доке): Anthropic/Claude CLI доступ,
Telegram-токены (опционально), `ORCH_PLANE_API_TOKEN` (если выдаётся вручную на manual-step).
- Сгенерированные файлы: только на целевом хосте, права `600`, в `.gitignore`; повторный
запуск НЕ перетирает существующие секреты без явного флага (паттерн `--force` gen_secrets).
### FR-4 — `docs/deployment/BUNDLED_SETUP.md` (BR-5)
- **Канон LITE_SETUP** (ORCH-102): нормативные разделы в порядке маршрута оператора; каждый
исполняемый шаг = fenced-команда + явная «Проверка:» с PASS/FAIL; хост-специфика — только
плейсхолдеры; запрещены FORBIDDEN-литералы и реальные секреты (структурный тест).
- **Обязательные разделы** (минимум; точные заголовки — автор дока, проверяемость — тест):
(1) рамка Bundled (что входит/что НЕ входит: Claude CLI, Telegram, HTTPS; границы vs Lite);
(2) **требования к хосту** — RAM/диск/CPU/порты, явно «Plane ≈ 14 контейнеров», финальные
цифры — по замеру на тестовом развёртывании; (3) предусловия (docker/compose/sudo);
(4) получение кода; (5) секреты; (6) запуск bundle-compose; (7) bootstrap (включая перечень
manual-step чекпоинтов Plane); (8) LLM/Claude CLI (ссылкой на канон LITE_SETUP §7);
(9) Telegram (ссылкой на LITE_SETUP §8); (10) онбординг следующих проектов
(ссылкой на ONBOARDING.md); (11) smoke (шаги REPLICATION §4); (12) stateless-проверка;
(13) остановка/полный сброс инсталляции; (14) траблшутинг (минимум: webhook не доходит,
не хватает RAM/OOM, порт занят, claude не найден, Plane-миграции не завершились).
- **Канон не форкается:** общие с Lite шаги — ссылками (LITE_SETUP §5§8, ONBOARDING §1,
REPLICATION §2§4), не копипастой; fail-closed имена `Confirm Deploy`/`STOP` и «22 статуса» —
согласованы с `plane_sync._PLANE_NAME_TO_KEY` (число — сверкой импорта в тесте, не литералом).
### FR-5 — Структурные анти-дрейф тесты (BR-9)
Все тесты — без docker/сети/LLM/subprocess-мутаций (CI-безопасные; паттерн
`test_lite_setup_doc.py`):
- **bundle-compose:** файл существует, валидный YAML; обязательные сервисы присутствуют
(`orchestrator`, `orchestrator-watchdog`, Gitea, Plane-стек — по списку из ADR); все
сторонние образы пиннованы (нет `:latest`/безтегового образа); корневой
`docker-compose.yml` НЕ изменён (множество сервисов == текущему эталону);
- **док:** BUNDLED_SETUP.md существует, несёт обязательные разделы (включая «Требования к
хосту»), каждый env-ключ из дока существует в канонах (`.env.example` bundle-конфиг-канон),
кросс-ссылки на LITE_SETUP/ONBOARDING/REPLICATION присутствуют;
- **гигиена:** FORBIDDEN-литералы (импорт списка из `test_no_host_hardcodes.py`) отсутствуют
в bundle-compose/доке/bootstrap; секрет-эвристика (hex ≥32 / alnum ≥40, паттерн D8 ORCH-102)
по новым файлам;
- **bootstrap:** скрипт существует; структурно ссылается на `gen_secrets`/`onboard_project`
(не дублирует канон); не содержит delete-операций уровня `docker volume rm`/`rm -rf` вне
явного отдельного «сброс»-режима; чистые функции (preflight-решение, сборка плана шагов,
рендер `.env`) покрыты unit-тестами;
- **кросс-рефы:** REPLICATION.md §1 несёт отметку Type B → BUNDLED_SETUP.md; CHANGELOG
содержит `ORCH-103`.
### FR-6 — Smoke и наблюдаемость результата (BR-3)
- Smoke Bundled = шаги REPLICATION §4 (06) поверх bundle-инсталляции, зафиксированные в
BUNDLED_SETUP §smoke: config-резолв → `/health``/queue`+`/metrics` → onboard verify →
тестовая задача (Plane issue → «To Analyse» → job в очереди) → **минимальный сигнал:
артефакты `0104` в ветке** → опционально полный цикл до `done`.
- Прохождение фиксируется оператором по PASS/FAIL каждого шага; это ручная приёмка AC-2
(e2e в CI не гоняется — нет docker/LLM).
---
## 4. Изменения API
**Нет.** Эндпоинты орка не добавляются/не меняются; bundle использует существующие
`/health`, `/queue`, `/metrics`, вебхуки `/webhook/plane`, `/webhook/gitea`.
## 5. Изменения схемы БД
**Нет** (схема БД орка не тронута). БД Plane/Gitea внутри bundle — их собственные, на чистых
томах инсталляции; к схеме орка отношения не имеют.
## 6. Требования к новым/изменённым QG checks
**Нет.** Реестр `QG_CHECKS`/`check_*`/`STAGE_TRANSITIONS` — байт-в-байт. Bundled-тираж — это
артефакты дистрибуции, а не гейты конвейера.
---
## 7. Совместимость / регресс
- **Kill-switch не требуется** (паттерн ORCH-009): артефакты вне рантайма; в нашем контуре
ничего их не исполняет; активация — явный запуск оператором на целевом хосте.
- **Нулевая регрессия:** корневой compose/`Dockerfile`/`src/**` не изменены ⇒ наш прод,
staging-контур и enduro-trails не затронуты по построению; существующие анти-дрейф тесты
(`test_lite_setup_doc.py`, `test_no_host_hardcodes.py`, канон-тесты ORCH-009) остаются
зелёными без правки их ассертов.
- **Обратимость:** удаление bundle-каталога/скрипта/дока возвращает репо в текущее состояние;
на целевом хосте полный сброс = задокументированная процедура (FR-4 §13).
- **Эскалация:** если при реализации выяснится необходимость править `src/**`/корневой compose
(например, недостающая параметризация, не закрытая ORCH-101) — это выход за рамки ТЗ:
остановиться и вернуть задачу с обоснованием (CLAUDE.md правило 4), не «дотачивать молча».
---
## 8. Артефакты pipeline (создать/обновить в ТОМ ЖЕ PR)
- `docs/work-items/ORCH-103/06-adr/ADR-001-<slug>.md` — решения архитектора (см. §9 OQ);
при сквозном значении — зеркало в `docs/architecture/adr/adr-NNNN-<slug>.md`.
- `docs/architecture/README.md` — раздел «Bundled-тираж (ORCH-103)» рядом с 10-common/Lite.
- `CLAUDE.md` — краткий абзац Type B (паттерн абзацев ORCH-101/102).
- `docs/operations/REPLICATION.md` §1 — отметка Type B (FR-6).
- `CHANGELOG.md``feat: ORCH-103 …`.
- При выявлении инфра-предусловий целевого хоста — `07-infra-requirements.md` (архитектор).
---
## 9. Открытые вопросы для архитектора (не блокируют анализ)
- **OQ-1** Расположение/имя bundle-каталога и compose-файла (`deploy/bundled/` vs `bundle/`;
один compose vs include-композиция); судьба staging-контура орка в bundle (исключить vs
профиль).
- **OQ-2** Точный состав/версии Plane CE-стека (по upstream selfhost-référence) и Gitea;
стратегия пиннинга (тег vs digest).
- **OQ-3** Перечень физически автоматизируемых шагов инициализации Plane CE (instance-setup/
workspace/API-токен): что через API/CLI/seed, что — manual-step чекпоинт.
- **OQ-4** Язык и режимы bootstrap (python stdlib vs bash; `plan`/`apply` vs линейный визард);
способ ожидания готовности (healthchecks vs poll).
- **OQ-5** Механизм сетевой связности орк (host network?) ⟷ bundle bridge-сеть: публикация
портов, `host-gateway`, либо весь bundle в host-network — и согласование URL вебхуков.
- **OQ-6** Механизм git-доступа агентов к bundle-Gitea (ssh-ключ vs http-токен) и наполнение
repos-каталога.
- **OQ-7** Делать ли отдельный явный «сброс»-режим (teardown) частью скрипта или только
документированной процедурой в BUNDLED_SETUP §13.