212 lines
23 KiB
Markdown
212 lines
23 KiB
Markdown
---
|
||
work_item: ORCH-102
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-10
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# 01 — BRD: ORCH-102 — ORCH-10a Lite-тираж: перенос орк+watchdog + полная инструкция донастройки окружения
|
||
|
||
Work Item: **ORCH-102** · Repo: **orchestrator** (self-hosting) · Стадия: analysis
|
||
Заказчик: Слава · Эпик: **ORCH-10** (домен D5 «Масштаб», `docs/epics/self-evolution.md`) · Тип: **A — Lite**
|
||
|
||
---
|
||
|
||
## 1. Бизнес-контекст и проблема
|
||
|
||
### 1.1. Цель эпика ORCH-10
|
||
Тираж платформы — РАЗДАЧА текущей функциональности нескольким заказчикам **на тест**.
|
||
Решения Владельца 10.06 (приняты как требования, см. §1.4): ДВА типа тиража, ОБА **stateless**
|
||
(наши задачи/данные/секреты НЕ переносим — чистый старт):
|
||
|
||
- **Тип A (Lite)** — переносим ТОЛЬКО орк+watchdog на новую инфру; окружение
|
||
(Plane / Gitea / LLM / Telegram) заказчик донастраивает сам **по чёткой инструкции**.
|
||
- **Тип B (Bundled)** — весь стек одним комплектом (отдельная задача эпика, вне ORCH-102).
|
||
|
||
### 1.2. Проблема, которую закрывает ORCH-102
|
||
Фундамент **10-common (ORCH-101) уже в `main`**: все хост-значения параметризованы env
|
||
(`docker compose config` без переменных = боевое поведение 1:1), секреты выпускаются заново
|
||
(`scripts/gen_secrets.py`), есть smoke-процедура с PASS/FAIL (`docs/operations/REPLICATION.md` §4)
|
||
и анти-регресс `tests/test_no_host_hardcodes.py`. **Технически** платформа разворачивается на
|
||
чужом хосте без правки кода.
|
||
|
||
**Операционно** — нет: знания размазаны по 4+ документам, каждый из которых писался для
|
||
оператора НАШЕГО хоста, а не для заказчика на чистой инфре:
|
||
|
||
| Документ | Что покрывает | Чего не хватает для Lite |
|
||
|----------|---------------|--------------------------|
|
||
| `docs/operations/REPLICATION.md` | карта env, секреты, smoke | явно НЕ описывает установку/подключение Plane/Gitea (анти-скоуп Р-5 ORCH-101) |
|
||
| `docs/operations/ONBOARDING.md` | онбординг проекта (статусы/лейблы/репо/kit/реестр) | предполагает уже работающий оркестратор и наш хост |
|
||
| `docs/operations/SETUP_WEBHOOKS.md` | формат вебхуков Plane/Gitea | примеры с боевыми URL (`mva154`), не generic |
|
||
| `docs/operations/INFRA.md` | топология/рестарты нашего хоста | не инструкция «с нуля» |
|
||
|
||
Заказчик сегодня **не может развернуть Lite без доп-вопросов** — отсутствует единый сквозной
|
||
маршрут «голый хост → работающий конвейер». Главный продукт ORCH-102 — **ИНСТРУКЦИЯ**
|
||
`docs/deployment/LITE_SETUP.md` (golden source в репо), закрывающая этот разрыв.
|
||
|
||
### 1.3. Установленные факты (проверено по репо, не изобретать)
|
||
- **ORCH-101 смержен** (`git log`: merge #122) — ветка задачи уже содержит фундамент: env-карта
|
||
§2 REPLICATION.md, `gen_secrets.py`, `.env.example` = канон 100% ключей старта (включая блок
|
||
`WATCHDOG_*`), smoke §4, тесты `test_no_host_hardcodes/test_infra_parametrization/test_secrets_gen/test_replication_smoke`.
|
||
- **`docker-compose.yml` УЖЕ является compose-подмножеством Lite:** ровно три сервиса —
|
||
`orchestrator`, `orchestrator-watchdog`, `orchestrator-staging` (последний строго за
|
||
`profiles: [staging]`); сервисов Plane/Gitea в compose НЕТ. Дефолтный `docker compose up -d`
|
||
поднимает ровно орк+watchdog. AC-2 достижим без форка compose — нужны фиксация в доке и
|
||
анти-дрейф тест.
|
||
- **Plane CE не отдаёт webhook через публичный API** — на нашем хосте webhook создан напрямую в
|
||
PostgreSQL / через UI (`SETUP_WEBHOOKS.md`). Инструкция Lite обязана дать заказчику оба пути
|
||
(UI и DB) для ЕГО инсталляции Plane.
|
||
- **Точная модель статусов**: 22 канонических имени с группами (источник —
|
||
`plane_sync._PLANE_NAME_TO_KEY`; таблица — `ONBOARDING.md` §1; создаёт
|
||
`scripts/onboard_project.py apply`). Код-критичные fail-closed: `Confirm Deploy`, `STOP`
|
||
(группа `cancelled`); в терминальных группах — только Done/Cancelled/STOP.
|
||
- **Branch protection на `main` нормативно ЗАПРЕЩЁН** (ORCH-009 ADR D10: required-approvals /
|
||
status-checks ломают PR-merge API merge-актора → ложные HOLD). **Pre-receive хуков в платформе
|
||
НЕТ** — защита держится конвенцией + скоупом токенов. Формулировка бизнес-запроса
|
||
«pre-receive хуки» конфликтует с этим нормативом → вопрос архитектору (ТЗ §3.8 А-1);
|
||
рекомендация: раздел Gitea фиксирует канон (репо+токен+webhook+«protection НЕ включать»).
|
||
- **Гэп watchdog-конфига:** compose читает `.env.watchdog` (`required: false`), но
|
||
`.env.watchdog.example` в репо НЕТ (есть только `.env.example`/`.env.staging.example`);
|
||
ключи `WATCHDOG_*` задокументированы внутри `.env.example`. Инструкции нужен однозначный
|
||
рецепт настройки watchdog-бота (форма — вопрос архитектору А-4).
|
||
- **Платформенные конвенции тиража** (REPLICATION.md §1, нормативно): репо платформы обязан
|
||
называться `orchestrator` (`SELF_HOSTING_REPO`); имена сервисов/профиля — константы;
|
||
контейнерный layout (`/app/data`, `/repos`, `/opt/claude-code`) не параметризуется.
|
||
- **Прецедент приёмки smoke**: ORCH-101 AC-3 — воспроизводимость подтверждается прогоном на
|
||
текущей инфре (staging-песочница `ORCH_STAGING_PORT`=8501 + sandbox-проект), без нового железа.
|
||
|
||
### 1.4. Решения Владельца (10.06) — приняты как требования
|
||
| # | Решение |
|
||
|---|---------|
|
||
| D-1 | Тиражей ДВА типа: A (Lite) и B (Bundled); ORCH-102 реализует ТОЛЬКО A. |
|
||
| D-2 | Оба типа **stateless**: наши задачи/данные/секреты не переносятся; на целевой инфре чистый старт. |
|
||
| D-3 | Lite = перенос ТОЛЬКО орк+watchdog; окружение (Plane/Gitea/LLM/Telegram) заказчик донастраивает по инструкции. |
|
||
| D-4 | Главный продукт задачи = **инструкция** `docs/deployment/LITE_SETUP.md` — golden source в репо. |
|
||
| D-5 | Зависимость: ORCH-102 ← **10-common (ORCH-101)** — выполнена (смержен), блокеров нет. |
|
||
|
||
---
|
||
|
||
## 2. Объём (scope)
|
||
|
||
### 2.1. В объёме
|
||
- **Инструкция `docs/deployment/LITE_SETUP.md`** — полная пошаговая (каждый шаг = команда +
|
||
проверка), покрывающая сквозной маршрут: предусловия хоста (зависимости, uid/gid) → перенос
|
||
кода орк+watchdog → конфиг (`.env` с нуля + секреты) → подключение Plane (workspace/проект,
|
||
точная модель статусов, API-токен, webhook+HMAC) → подключение Gitea (репо, токен, webhook,
|
||
норматив защиты `main`) → LLM-доступ (claude CLI / ключи моделей) → Telegram (бот трекера +
|
||
watchdog-бот + chat-id) → запуск compose-подмножества → регистрация проекта
|
||
(`ORCH_PROJECTS_JSON`, `src/projects.py`) → health-чек → smoke (из 10-common) → траблшутинг.
|
||
- **Фиксация compose-подмножества** (AC-2): документировано и защищено структурным тестом, что
|
||
дефолтный запуск = ровно орк+watchdog, без Plane/Gitea-контейнеров.
|
||
- **Stateless-нормативы** в инструкции (AC-3): чистая БД, новые секреты, явный запрет переноса
|
||
наших задач/данных/секретов.
|
||
- **Smoke на чистом окружении** (AC-4): воспроизводимая процедура/чек-лист (переиспользование
|
||
REPLICATION.md §4) + зафиксированный приёмочный прогон.
|
||
- **Анти-дрейф тесты** структуры/полноты инструкции и compose-подмножества; полный pytest
|
||
зелёный; `CHANGELOG.md`; перекрёстные ссылки (REPLICATION.md §1 границы, README — по объёму).
|
||
|
||
### 2.2. Вне объёма (явно, не делать)
|
||
- **Тип B (Bundled)** — весь стек одним комплектом: отдельная задача эпика.
|
||
- **Установка самих Plane / Gitea / Telegram / LLM-аккаунтов** — заказчик ставит по официальной
|
||
документации вендоров; ORCH-102 покрывает только ПОДКЛЮЧЕНИЕ к оркестратору (анти-скоуп-крип,
|
||
зеркало Р-5 ORCH-101).
|
||
- **Изменения рантайма/конвейера**: ожидаемый объём — docs+tests; `src/**` не трогается;
|
||
`STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict ключи / схема БД — байт-в-байт.
|
||
- **Перенос данных**: ни БД, ни задач, ни worktree, ни секретов (D-2).
|
||
- **Новая автоматизация** поверх существующих CLI (`gen_secrets.py`, `onboard_project.py`):
|
||
новые скрипты не вводятся без решения архитектора.
|
||
- **Коммерческая механика раздачи** (доступ заказчика к коду, лицензии, поддержка) —
|
||
операторский/владельческий уровень; в инструкции — параметризованный источник кода.
|
||
- **Введение pre-receive хуков / branch protection** — запрещено действующим нормативом
|
||
ORCH-009 ADR D10 (см. §1.3); пересмотр только явным ADR архитектора.
|
||
|
||
---
|
||
|
||
## 3. Заинтересованные стороны
|
||
- **Владелец (Слава)** — раздаёт платформу заказчикам на тест; принимает инструкцию как продукт.
|
||
- **Заказчик-тестер (новый оператор)** — целевой читатель LITE_SETUP.md: разворачивает Lite на
|
||
своей инфре без доп-вопросов; технически грамотен (linux/docker), платформу видит впервые.
|
||
- **Оператор текущего прода** — прогоняет приёмочный smoke на staging-песочнице; его прод
|
||
(общий для enduro-trails) не должен быть затронут.
|
||
- **Будущая задача 10b (Bundled)** — переиспользует разделы Lite-инструкции; границы фиксируются
|
||
в REPLICATION.md §1.
|
||
|
||
---
|
||
|
||
## 4. Бизнес-требования (BR)
|
||
|
||
| ID | Требование | Связь |
|
||
|----|------------|-------|
|
||
| BR-1 | Существует `docs/deployment/LITE_SETUP.md` — **полная пошаговая** инструкция Lite-тиража: по ней человек, не видевший платформу, разворачивает орк+watchdog и донастраивает окружение **без доп-вопросов**; **каждый шаг несёт команду и проверку** (ожидаемый результат / PASS-FAIL). | AC-1, FR-1, D-4 |
|
||
| BR-2 | Инструкция покрывает ВСЕ системы донастройки: Plane (workspace/проект, точная модель статусов — 22 имени с группами, API-токен, webhook+HMAC с учётом ограничения Plane CE), Gitea (репо, токен с нужными scope, per-repo webhook, норматив «branch protection `main` НЕ включать»), LLM (claude CLI: дистрибутив/node/аутентификация/`ORCH_CLAUDE_BIN`/модели), Telegram (бот трекера + ОТДЕЛЬНЫЙ watchdog-бот + получение chat-id), регистрацию проекта (`ORCH_PROJECTS_JSON` через `onboard_project.py`), health-чек, smoke. | AC-1, FR-4 |
|
||
| BR-3 | Разворачивается **compose-подмножество только орк+watchdog**: дефолтный `docker compose up -d` поднимает ровно `orchestrator`+`orchestrator-watchdog`; Plane/Gitea-контейнеров в compose нет; staging-сервис — строго за профилем. Свойство зафиксировано в доке и защищено структурным тестом. | AC-2, FR-2 |
|
||
| BR-4 | **Stateless**: инструкция предписывает чистую БД (создаётся пустой при первом старте), выпуск НОВОГО комплекта секретов (`gen_secrets.py` + чек-лист внешних токенов), и нигде не предписывает перенос наших задач/данных/секретов; в самой доке — только плейсхолдеры, ни одного реального секрета/боевого токена. | AC-3, FR-3 |
|
||
| BR-5 | **Smoke на чистом окружении** существует как воспроизводимая процедура/чек-лист с PASS/FAIL (переиспользование REPLICATION.md §4, без форка); приёмочный прогон выполнен на чистом контуре (минимум — staging-песочница + sandbox-проект, прецедент ORCH-101 AC-3) и зафиксирован в артефактах задачи. | AC-4, FR-5 |
|
||
| BR-6 | **Канон не форкается**: канонические таблицы (модель статусов, карта env, формат вебхуков) инструкция даёт ссылкой на golden source (`ONBOARDING.md`/`REPLICATION.md`/`SETUP_WEBHOOKS.md`) либо с анти-дрейф тестом при неизбежном дублировании; копируемые команды инструкции — generic (плейсхолдеры вместо боевых URL/путей). | AC-1/AC-6, FR-4, NFR-4 |
|
||
| BR-7 | Полный `pytest tests/ -q` зелёный; запись в `CHANGELOG.md`; перекрёстные доки обновлены (REPLICATION.md §1 «границы» — строка Type A → ссылка/статус; README/CLAUDE.md — по фактическому объёму, правило агентов №2/№6). | AC-5, FR-6/FR-7 |
|
||
| BR-8 | Полнота/структура инструкции защищена **структурным pytest** (анти-дрейф, по образцу `tests/test_replication_smoke.py`): исчезновение обязательного раздела/кирпича/env-ключа из дока или дрейф compose-подмножества ломает CI. | AC-6, FR-6 |
|
||
|
||
---
|
||
|
||
## 5. Нефункциональные требования (NFR)
|
||
|
||
| ID | Требование |
|
||
|----|------------|
|
||
| NFR-1 | **Self-hosting безопасность:** задача docs+tests; прод-контейнер `orchestrator` не перезапускается; прод-выкат — только штатным конвейером (staging 8501 → ручной Confirm Deploy). |
|
||
| NFR-2 | **Нулевая регрессия:** поведение рантайма не меняется (ожидаемо ноль изменений `src/**`); `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД — байт-в-байт; существующие тесты (включая `test_no_host_hardcodes`, `test_replication_smoke`) остаются зелёными. |
|
||
| NFR-3 | **Секрет-гигиена:** ни в инструкции, ни в тестах — ни одного реального секрета/токена/боевого webhook-секрета; только плейсхолдеры и ссылки на `gen_secrets.py`; security-гейт (ORCH-022) зелёный. |
|
||
| NFR-4 | **Единый источник истины:** инструкция — маршрутизатор поверх канонов, не их копия; неизбежные дубли защищены анти-дрейф тестом (сверка с кодом/каноном импортом, не строкой). |
|
||
| NFR-5 | **Поддерживаемость golden source:** LITE_SETUP.md версионируется в репо и поддерживается агентами при каждой доработке, меняющей шаги тиража (правило агентов №2 — дока в том же PR). |
|
||
| NFR-6 | **Копируемость команд:** каждый код-блок инструкции выполняется на чистом хосте дословно после подстановки явно перечисленных плейсхолдеров (`<...>`); никаких неявных «подразумевается, что…». |
|
||
|
||
---
|
||
|
||
## 6. Допущения и ограничения
|
||
- **Поддерживаемый контур** (фиксируется в предусловиях инструкции): Linux x86_64, Docker Engine +
|
||
Compose v2, git, python3; пользователь с правами docker; диск/память по минимальным требованиям
|
||
(значения уточнит архитектор/инструкция). Иные ОС/архитектуры — вне гарантии Lite.
|
||
- **Заказчик сам ставит** Plane CE, Gitea, заводит Telegram-ботов и LLM-доступ (Claude
|
||
CLI-аутентификация / ключи) — по официальным докам вендоров; наша инструкция начинается с
|
||
«системы установлены и доступны по сети».
|
||
- **Имя репо платформы — `orchestrator`** (норматив REPLICATION.md §1 / `SELF_HOSTING_REPO`);
|
||
инструкция не предлагает его менять.
|
||
- **Источник кода** для заказчика (clone-URL/архив) — решение Владельца; в инструкции —
|
||
параметризованный шаг (А-6 в ТЗ).
|
||
- «Без доп-вопросов» (AC-1) операционализируется проверяемо: (а) каждый шаг несёт
|
||
команду+проверку, (б) приёмочный smoke-прогон по инструкции на чистом контуре зафиксирован,
|
||
(в) траблшутинг покрывает типовые отказы первичной настройки.
|
||
- Терминология бизнес-запроса «pre-receive хуки» трактуется по факту платформы (§1.3):
|
||
канонический механизм защиты — конвенция + скоуп токенов + запрет branch protection;
|
||
окончательная формулировка раздела Gitea — за архитектором (А-1).
|
||
|
||
---
|
||
|
||
## 7. Критерии успеха (резюме; детали — 03-acceptance-criteria.md)
|
||
- AC-1: `docs/deployment/LITE_SETUP.md` — полная пошаговая, человек разворачивает без
|
||
доп-вопросов (каждый шаг — команда/проверка).
|
||
- AC-2: compose-подмножество только орк+watchdog (без Plane/Gitea-контейнеров).
|
||
- AC-3: stateless — чистая БД, ни одной нашей задачи/секрета.
|
||
- AC-4: smoke на чистом окружении проходит (минимум — воспроизводимая процедура/чек-лист).
|
||
- AC-5: pytest зелёный; CHANGELOG.
|
||
- AC-6 (детализация): анти-дрейф тесты структуры дока/compose; канон не форкается.
|
||
- AC-7 (детализация): self-hosting безопасность, инварианты конвейера не тронуты.
|
||
|
||
---
|
||
|
||
## 8. Риски (детали — 10-tech-risks.md, заполняет архитектор)
|
||
- R-1 — **Дрейф инструкции**: платформа развивается, шаги устаревают → структурные тесты (BR-8)
|
||
+ правило golden source (NFR-5).
|
||
- R-2 — **Форк канона**: скопированная таблица статусов/env разъедется с кодом → ссылки/анти-дрейф
|
||
(BR-6, NFR-4).
|
||
- R-3 — **Непроверяемость «без доп-вопросов»** → операционализация через §6 (команда+проверка,
|
||
smoke-прогон, траблшутинг).
|
||
- R-4 — **Гетерогенность хостов заказчиков** (rootless docker, иной uid, нет node) → явный
|
||
поддерживаемый контур + предусловия с проверками (`getent group docker`, владение
|
||
`ORCH_HOST_REPOS_DIR`).
|
||
- R-5 — **Конфликт «pre-receive» с нормативом ADR D10** → вопрос А-1 архитектору; до решения —
|
||
канон платформы.
|
||
- R-6 — **Утечка секрета через примеры дока** → NFR-3, security-гейт, тест на отсутствие
|
||
секретоподобных значений.
|