# LITE_SETUP — Lite-тираж: оркестратор + watchdog на вашей инфраструктуре (ORCH-102) > **Golden source Lite-тиража (Type A эпика ORCH-10).** Сквозной маршрут > «голый хост → работающий конвейер» для внешнего оператора/заказчика. Каждый шаг — > исполняемая команда + явная проверка результата (**Проверка:** / PASS / FAIL). > Хост-специфика в командах — только плейсхолдеры `<...>` и `$ENV_VAR`. > Тираж **stateless**: данные/задачи/секреты исходного (боевого) хоста **НЕ переносятся** > ни на одном шаге — всё создаётся заново (§12). > **Быстрый путь — `scripts/setup_lite.py`** (§1.1): интерактивный installer проводит по > §2–§12 за один прогон; ручной маршрут ниже остаётся каноном и fallback'ом. --- ## 1. Рамка Lite **Что разворачиваем:** два контейнера платформы — `orchestrator` (конвейер, порт `ORCH_DEPLOY_PROD_TARGET_PORT`, дефолт 8500) и `orchestrator-watchdog` (независимый sidecar-мониторинг). Третий сервис `orchestrator-staging` существует в том же compose-файле, но строго за профилем `staging` и в базовом Lite-контуре не поднимается (§9). **Что заказчик ставит и администрирует сам** (вне этой инструкции — как продукты): - **Plane** (task-management) — своя инсталляция; здесь только её *подключение* (§5); - **Gitea** (git-хостинг) — своя инсталляция; здесь только её *подключение* (§6); - **Telegram-боты** (нотификации) — свои боты (§8); - **LLM-доступ** (claude CLI + node) — свой дистрибутив и аутентификация (§7). **Границы слоёв тиража** (10-common vs Lite vs Bundled) — `docs/operations/REPLICATION.md` §1. Этот док собирает кирпичи 10-common (карта env, секреты, smoke) в один маршрут и не форкает их. **Платформенные конвенции (не менять):** - репо платформы обязан называться **`orchestrator`** (узел безопасности `SELF_HOSTING_REPO`); - имена compose-сервисов/профиля (`orchestrator`, `orchestrator-watchdog`, `orchestrator-staging`, профиль `staging`) — константы платформы; - контейнерные пути (`/app/data`, `/repos`, `/opt/claude-code`) — layout контейнера, не хост-значения; не параметризуются. ### 1.1. Быстрый путь: `setup_lite.py` (рекомендуется) Вместо ручного прохода §2–§12 запустите **интерактивный installer** — он сканирует предусловия хоста и предлагает доустановить недостающее, обнаруживает ваши инсталляции Plane/Gitea (при нескольких — даёт выбрать), запрашивает обязательные ключи **в момент установки с немедленной верификацией**, автодетектит хост-параметры, собирает `.env`/`.env.watchdog` от канонов (свежие webhook-секреты — кирпичом `gen_secrets.py`), поднимает ровно орк+watchdog и регистрирует ваш проект строго кирпичом `onboard_project.py`. ```bash cd <путь-чекаута> # корень репо orchestrator python3 scripts/setup_lite.py # apply (дефолт): интерактивная установка python3 scripts/setup_lite.py plan # read-only диагностика (ноль мутаций) python3 scripts/setup_lite.py verify # read-only пост-проверка контура ``` **Контракт:** дефолт-режим `apply` — установка «одной командой»; безопасность дефолта структурна — фаза 0 любого `apply` ≡ `plan` (read-only скан), каждая мутация хоста — с **явного согласия** (per-action consent с печатью точной команды), существующий чужой `.env`/`.env.watchdog` **не перетирается** без `--force` (guard managed-маркера), в non-TTY без `--yes` — честный выход без зависания. Exit-коды: `0` — все шаги PASS; `2` — остановка на ручном шаге (повторный запуск продолжит с него — resume); `1` — ошибка. Секреты вводятся скрыто и **никогда не печатаются**; delete-операций скрипт не выполняет (лечение — всегда инструкция). Любой ручной шаг ссылается на соответствующий § ниже — ручной маршрут §2–§13 остаётся полным каноном и fallback'ом для MANUAL-шагов. **Проверка:** `python3 scripts/setup_lite.py plan` завершается без блокеров (exit 0) — PASS; есть блокеры (exit 2) — устраните по выводу и повторите. --- ## 2. Предусловия хоста Поддерживаемый контур: **Linux x86_64, Docker Engine + Compose v2, git, python3, node** + дистрибутив claude-code на хосте. Вне контура — вне гарантии Lite. Каждое предусловие — команда проверки; все проверки PASS → можно переходить к §3. **2.1. ОС и базовые зависимости.** ```bash uname -sm # Linux x86_64 docker --version # Docker Engine docker compose version # Compose v2 git --version python3 --version # 3.x (для scripts/*.py) node --version # путь к бинарю станет ORCH_HOST_NODE_BIN ``` **Проверка:** все команды отвечают версиями без ошибок — PASS; любая отсутствует — FAIL (доставить пакет средствами вашего дистрибутива). **2.2. Пользователь-владелец и uid/gid (инвариант ORCH-040).** Контейнеры бегут под `ORCH_RUN_UID:ORCH_RUN_GID` — это обязан быть uid:gid владельца каталога репозиториев `ORCH_HOST_REPOS_DIR`, иначе git-артефакты конвейера не запишутся. ```bash id -u ; id -g # значения для ORCH_RUN_UID / ORCH_RUN_GID mkdir -p <путь-каталога-репозиториев> # станет ORCH_HOST_REPOS_DIR stat -c '%u:%g' <путь-каталога-репозиториев> # обязан совпасть с ORCH_RUN_UID:ORCH_RUN_GID ``` **Проверка:** uid:gid владельца каталога = будущие `ORCH_RUN_UID`/`ORCH_RUN_GID` — PASS. **2.3. Группа docker (доступ к docker.sock).** ```bash getent group docker # третье поле — gid, станет ORCH_DOCKER_GID ``` **Проверка:** строка вида `docker:x::...` есть — PASS; группы нет — FAIL (установите Docker корректно / создайте группу). **2.4. Каталог ssh-ключей деплой-хука** (понадобится для git-push артефактов агентов и деплой-хуков; монтируется в `$HOME/.ssh` акторов). ```bash mkdir -p <путь-ssh-каталога> # станет ORCH_HOST_SSH_DIR ssh-keygen -t ed25519 -f <путь-ssh-каталога>/id_ed25519 -N "" -C "orchestrator@" ls -l <путь-ssh-каталога> # ключи читаемы пользователем из 2.2 ``` **Проверка:** каталог существует, ключи на месте, владелец — пользователь из 2.2 — PASS. Публичный ключ добавьте в Gitea (Settings → SSH Keys) на шаге §6. **2.5. Свободные порты** (дефолты платформы: 8500 — прод, 8501 — staging). ```bash ss -ltn | grep -E ':(8500|8501)\b' || echo "ports free" ``` **Проверка:** вывод `ports free` — PASS. Порты заняты → выберите другие и на шаге §4 синхронно задайте `ORCH_DEPLOY_PROD_TARGET_PORT` ⇄ `WATCHDOG_METRICS_URL` ⇄ `ORCH_POST_DEPLOY_BASE_URL` (и `ORCH_STAGING_PORT` ≠ прод-порт — guard ORCH-058 fail-closed). --- ## 3. Перенос кода Переносится **только код** — чекаут репо `orchestrator`. **НИКАКИХ** данных, БД или `.env` с исходного хоста (норматив §12). Watchdog отдельно не переносится: его код — каталог `watchdog/` того же репо, образ собирается локально compose'ом. ```bash git clone <путь-чекаута> # путь станет ORCH_DEPLOY_HOST_REPO_PATH cd <путь-чекаута> ``` Конкретный канал дистрибуции (`` — зеркало/архив/доступ к Gitea поставщика) согласуйте с поставщиком платформы; опционально — `--branch <тег-среза>`. **Проверка:** ```bash git -C <путь-чекаута> log --oneline -1 # коммит виден ls <путь-чекаута>/docker-compose.yml <путь-чекаута>/watchdog/Dockerfile \ <путь-чекаута>/.env.example <путь-чекаута>/.env.watchdog.example ``` Все файлы на месте — PASS. --- ## 4. Конфигурация `.env` собирается **с нуля от канона `.env.example`** (100% ключей старта; полная карта переменных и их семантика — `docs/operations/REPLICATION.md` §2). Дефолт каждого ключа = значению исходного хоста, поэтому задаёте только то, что отличается у вас. **4.1. Создать `.env` и выпустить webhook-секреты.** ```bash cd <путь-чекаута> cp .env.example .env python3 scripts/gen_secrets.py # печатает свежие ORCH_PLANE_WEBHOOK_SECRET / ORCH_GITEA_WEBHOOK_SECRET ``` Вставьте оба напечатанных значения в `.env`. Секреты выпускаются **только заново** — боевые не копируются (§12). **4.2. Обязательные ключи нового хоста** (заполняются в `.env` по ходу §5–§8): | Группа | Ключи | Откуда | |--------|-------|--------| | Plane | `ORCH_PLANE_API_URL`, `ORCH_PLANE_WEB_URL`, `ORCH_PLANE_WORKSPACE_SLUG`, `ORCH_PLANE_API_TOKEN` | §5 | | Gitea | `ORCH_GITEA_URL`, `ORCH_GITEA_PUBLIC_URL`, `ORCH_GITEA_OWNER`, `ORCH_GITEA_TOKEN` | §6 | | Webhook-секреты | `ORCH_PLANE_WEBHOOK_SECRET`, `ORCH_GITEA_WEBHOOK_SECRET` | 4.1 (`gen_secrets.py`) | | Telegram | `ORCH_TELEGRAM_BOT_TOKEN`, `ORCH_TELEGRAM_CHAT_ID` | §8 | | Реестр проектов | `ORCH_PROJECTS_JSON` — **обязателен**: встроенный fallback несёт Plane-UUID исходного хоста | §10 | | Хост-параметры | `ORCH_AGENT_HOME_DIR`, `ORCH_HOST_REPOS_DIR`, `ORCH_HOST_CLAUDE_DIR`, `ORCH_HOST_CLAUDE_JSON`, `ORCH_HOST_SSH_DIR`, `ORCH_HOST_CLAUDE_CODE_DIR`, `ORCH_HOST_NODE_BIN`, `ORCH_RUN_UID`, `ORCH_RUN_GID`, `ORCH_DOCKER_GID`, `ORCH_DEPLOY_HOST_REPO_PATH`, `ORCH_AGENT_GIT_NAME`, `ORCH_GIT_EMAIL_DOMAIN` | значения из §2–§3 | | Порты | `ORCH_DEPLOY_PROD_TARGET_PORT` ⇄ `WATCHDOG_METRICS_URL` ⇄ `ORCH_POST_DEPLOY_BASE_URL`; `ORCH_STAGING_PORT` ≠ прод-порт | §2.5 | **4.3. Конфиг sidecar-watchdog — отдельный файл-носитель.** Sidecar-контейнер читает **ТОЛЬКО `.env.watchdog`**; ключ `WATCHDOG_ENABLED` (и любой другой `WATCHDOG_*`), положенный в `.env`, для sidecar **инертен**. ```bash cp .env.watchdog.example .env.watchdog # заполнить два ключа: WATCHDOG_TG_BOT_TOKEN / WATCHDOG_TG_CHAT_ID (бота создадим в §8) ``` **Проверка (резолв всей конфигурации):** ```bash docker compose config >/dev/null && echo "compose config: PASS" ``` `PASS` без ошибок интерполяции — конфигурация согласована; ошибка — FAIL (ищите незакрытую кавычку/невалидный JSON в `ORCH_PROJECTS_JSON`). --- ## 5. Подключение Plane Инсталляция Plane — ваша; платформа подключается к ней API-токеном и webhook'ом. **5.1. Workspace и проект.** Создайте workspace (его slug → `ORCH_PLANE_WEB_URL` / `ORCH_PLANE_WORKSPACE_SLUG`) и проект под вашу разработку — через UI Plane. ```bash # базовая доступность API из хоста оркестратора: curl -fsS "$ORCH_PLANE_API_URL/api/v1/workspaces//projects/" \ -H "X-API-Key: " | head -c 200 ``` **Проверка:** HTTP 200 и JSON со списком проектов — PASS; 401/403 — токен (5.2) ещё не выпущен или не имеет прав. **5.2. API-токен.** Plane UI → Workspace Settings → API tokens → выпустить токен → `ORCH_PLANE_API_TOKEN` в `.env`. Токен должен иметь право создавать проекты/статусы (нужно для `onboard_project.py apply`, §10). **5.3. Модель статусов — НЕ вручную.** Конвейеру нужны **22 канонических статуса** с точными именами и группами; их создаёт `python3 scripts/onboard_project.py apply` (§10), полная таблица — `docs/operations/ONBOARDING.md` §1 (golden source; здесь не дублируется). Два имени фиксируем явно, потому что они **fail-closed** (без них ветка просто не активируется, без ошибки): **`Confirm Deploy`** (человеческий гейт прод-деплоя) и **`STOP`** (отмена задачи; обязан быть в группе `cancelled`). ```bash # после §10 — проверить, что статусы созданы: curl -fsS "$ORCH_PLANE_API_URL/api/v1/workspaces//projects//states/" \ -H "X-API-Key: $ORCH_PLANE_API_TOKEN" | python3 -m json.tool | grep -c '"name"' ``` **Проверка:** счётчик имён = 22 (или больше, если в проекте остались дефолтные статусы Plane) и среди них `Confirm Deploy` и `STOP` — PASS. **5.4. Webhook + HMAC.** Приёмник — `POST https:///webhook/plane`; подпись — заголовок `X-Plane-Signature` (HMAC-SHA256, hex digest); секрет — значение `ORCH_PLANE_WEBHOOK_SECRET` из 4.1. События: Issue, Issue Comment. **Каверза Plane CE:** webhook **не экспонирован во внешнем `/api/v1`** — настраивается одним из двух путей. *Путь А — UI (если ваша сборка Plane его показывает):* Workspace Settings → Webhooks → Add Webhook → URL + Secret (значение `ORCH_PLANE_WEBHOOK_SECRET`) → события Issue, Issue Comment → Save. *Путь Б — прямой SQL в Postgres инсталляции Plane:* ```bash WORKSPACE_ID=$(docker exec -e PGPASSWORD= \ psql -U plane -d plane -t -A -c "SELECT id FROM workspaces WHERE slug=''") WEBHOOK_ID=$(cat /proc/sys/kernel/random/uuid) docker exec -e PGPASSWORD= psql -U plane -d plane -c " INSERT INTO webhooks (id, created_at, updated_at, deleted_at, workspace_id, url, is_active, secret_key, project, issue, module, cycle, issue_comment, is_internal, version) VALUES ('${WEBHOOK_ID}', NOW(), NOW(), NULL, '${WORKSPACE_ID}', 'https:///webhook/plane', true, '<значение ORCH_PLANE_WEBHOOK_SECRET>', true, true, false, false, true, false, 'v1'); " ``` **Проверка:** ```bash docker exec -e PGPASSWORD= psql -U plane -d plane -c \ "SELECT url, is_active FROM webhooks;" ``` Строка с вашим URL и `is_active = t` — PASS. Сквозная проверка доставки — §11 (smoke); generic-образец команд и формат подписи — `docs/operations/SETUP_WEBHOOKS.md`. --- ## 6. Подключение Gitea **6.1. Токен.** Gitea UI → Settings → Applications → Generate Token, scope: `repo`, `admin:repo_hook` → `ORCH_GITEA_TOKEN` в `.env`. ```bash curl -fsS -H "Authorization: token $ORCH_GITEA_TOKEN" "$ORCH_GITEA_URL/api/v1/user" | head -c 200 ``` **Проверка:** HTTP 200 с JSON вашего пользователя — PASS; владелец репозиториев (организация/пользователь) → `ORCH_GITEA_OWNER`, браузерный URL → `ORCH_GITEA_PUBLIC_URL`. **6.2. Репо проекта.** Создаёт `onboard_project.py apply` (§10) — или вручную (пустой репо + initial push). Чекаут обязан появиться в `$ORCH_HOST_REPOS_DIR/` (общий каталог репозиториев из §2.2). Публичный ключ из §2.4 добавьте в Gitea (Settings → SSH Keys), чтобы акторы могли пушить. ```bash git -C "$ORCH_HOST_REPOS_DIR" clone stat -c '%u:%g' "$ORCH_HOST_REPOS_DIR/" # владелец = ORCH_RUN_UID:ORCH_RUN_GID ``` **Проверка:** чекаут на месте, владелец совпадает — PASS. **6.3. Per-repo webhook.** Создаёт `onboard_project.py apply` (§10). Параметры (если вручную): URL `https:///webhook/gitea`, content type `json`, события **`push` / `pull_request` / `status`**, branch filter `*`, подпись — `X-Gitea-Signature` (HMAC-SHA256). Секрет — **ОДИН глобальный `ORCH_GITEA_WEBHOOK_SECRET` на ВСЕ репо** (приёмник валидирует только его; «свой секрет на репо» сломал бы HMAC остальных). ```bash curl -fsS -H "Authorization: token $ORCH_GITEA_TOKEN" \ "$ORCH_GITEA_URL/api/v1/repos///hooks" | python3 -m json.tool ``` **Проверка:** hook с вашим URL и тремя событиями существует, `active: true` — PASS. **6.4. Норматив защиты `main` (ВАЖНО).** **Branch protection на `main` НЕ включать** (никаких required-approvals / required-status-checks): merge-актор конвейера мержит PR строго через Gitea PR-merge API (INV-4), и protection-правила дают 405/409-класс отказов → ложные HOLD задач (ADR D10 ORCH-009). **pre-receive хуки платформа не вводит** и не проверяет — защита `main` держится конвенцией (агенты не пушат `main`) + скоупом токенов. ```bash curl -fsS -H "Authorization: token $ORCH_GITEA_TOKEN" \ "$ORCH_GITEA_URL/api/v1/repos///branch_protections" | python3 -m json.tool ``` **Проверка:** пустой список `[]` — PASS; есть правила на `main` — FAIL (удалите их, симптом «PR не мержится / HOLD» — §13.7). --- ## 7. LLM (claude CLI) Агенты конвейера — процессы claude CLI **внутри контейнера**, но дистрибутив, node и аутентификация живут **на хосте** и пробрасываются маунтами (источники маунтов = ключи `.env`). **7.1. Дистрибутив claude-code и node.** Установите claude-code (npm-дистрибутив Anthropic) и node на хост. Пути → `.env`: ```bash which node # → ORCH_HOST_NODE_BIN npm root -g # каталог глобальных модулей ls "/@anthropic-ai/claude-code" # → ORCH_HOST_CLAUDE_CODE_DIR ``` **Проверка:** каталог дистрибутива существует и непуст — PASS. Внутри контейнера бинарь доступен как `ORCH_CLAUDE_BIN` (дефолт менять не нужно). **7.2. Аутентификация CLI.** Выполните первичный интерактивный логин claude CLI **на хосте** под пользователем из §2.2 (по инструкции Anthropic к claude-code). Логин создаёт каталог `~/.claude` и файл `~/.claude.json` — их пути задайте в `ORCH_HOST_CLAUDE_DIR` / `ORCH_HOST_CLAUDE_JSON`. ```bash claude --version # CLI работает sudo -u "#" test -r <путь-~/.claude>/.credentials.json && echo "creds: PASS" ``` **Проверка:** версия печатается; `creds: PASS` — креды читаемы uid'ом контейнера (иначе — `chown -R :` каталога, симптом §13.3). **7.3. Модели агентов.** Резолв модели/эффорта — только из конфига (ORCH-41/74): дефолты канона уже в `.env.example` (`ORCH_AGENT_MODEL_DEFAULT`, `ORCH_AGENT_EFFORT_DEFAULT` и per-агент ключи рядом) — менять не обязательно. ```bash grep -E '^ORCH_AGENT_(MODEL|EFFORT)_DEFAULT=' .env ``` **Проверка:** оба ключа присутствуют и непусты — PASS. --- ## 8. Telegram Каналов **два и они независимы** (C-1 ORCH-100): бот live-трекера оркестратора и **отдельный** бот sidecar-watchdog. Токен орка для watchdog переиспользовать **ЗАПРЕЩЕНО** — упавший орк не сможет сообщить о себе своим же ботом. **8.1. Бот трекера.** BotFather → `/newbot` → токен → `ORCH_TELEGRAM_BOT_TOKEN` в `.env`. ```bash curl -fsS "https://api.telegram.org/bot<токен-трекера>/getMe" # напишите боту любое сообщение (или добавьте его в чат), затем: curl -fsS "https://api.telegram.org/bot<токен-трекера>/getUpdates" | python3 -m json.tool | grep -m1 '"id"' ``` **Проверка:** `getMe` → `"ok":true`; `id` чата из `getUpdates` → `ORCH_TELEGRAM_CHAT_ID` — PASS. **8.2. Watchdog-бот (отдельный).** BotFather → `/newbot` ещё раз → токен и chat-id → **`.env.watchdog`** (`WATCHDOG_TG_BOT_TOKEN` / `WATCHDOG_TG_CHAT_ID`). Помните о файле-носителе: эти ключи работают только в `.env.watchdog` (§4.3). ```bash curl -fsS "https://api.telegram.org/bot<токен-watchdog>/getMe" grep -E '^WATCHDOG_TG_(BOT_TOKEN|CHAT_ID)=.+' .env.watchdog ``` **Проверка:** `getMe` → `"ok":true`; оба ключа в `.env.watchdog` непусты — PASS. --- ## 9. Запуск **9.1. Базовый Lite-контур (дефолт): орк + watchdog.** ```bash cd <путь-чекаута> docker compose config --services # ровно: orchestrator, orchestrator-watchdog, orchestrator-staging docker compose up -d --build docker compose ps ``` **Проверка:** запущены **ровно два** контейнера — `orchestrator` и `orchestrator-watchdog`; `orchestrator-staging` НЕ поднялся (он строго за `profiles: [staging]`) — PASS. Поднялось что-то ещё/меньше — FAIL. **9.2. Health-чек контрактов.** ```bash curl -fsS http://127.0.0.1:8500/health curl -fsS http://127.0.0.1:8500/queue | python3 -m json.tool | head -20 curl -fsS http://127.0.0.1:8500/metrics | python3 -m json.tool | head -10 ``` **Проверка:** `/health` → HTTP 200, `"status":"ok"`; `/queue` → штатный JSON (счётчики очереди); `/metrics` → JSON со `"schema_version": 1` — PASS. (Порт замените, если меняли `ORCH_DEPLOY_PROD_TARGET_PORT`.) **9.3. Вилка staging (опционально).** Базовому контуру «гонять СВОИ проекты» staging **не нужен**. Он нужен ТОЛЬКО если вы регистрируете проект `orchestrator` (self-hosting развитие самой платформы у себя): стадия `deploy-staging` требует песочницу на `ORCH_STAGING_PORT` (изолированная БД `./data/staging`; guard ORCH-058: staging-порт ≠ прод-порт, fail-closed). ```bash cp .env.staging.example .env.staging # заполнить по аналогии с .env docker compose --profile staging up -d orchestrator-staging curl -fsS http://127.0.0.1:8501/health ``` **Проверка (только для этой вилки):** `/health` staging → 200 — PASS. --- ## 10. Регистрация проекта заказчика Onboarding-CLI создаёт Plane-проект с 22 статусами и лейблами (`autoApprove` / `autoDeploy` / `Bug`), Gitea-репо с webhook'ом, скелет репо (kit) и печатает merged-реестр. Полный runbook — `docs/operations/ONBOARDING.md`; Lite-последовательность: ```bash cd <путь-чекаута> python3 scripts/onboard_project.py plan \ --name "<имя проекта>" --description "<зачем проект>" \ --repo --prefix \ --stack "<стек>" --test-cmd "<команда тестов>" \ --prod-port <порт-прода-проекта> --staging-port <порт-staging-проекта> \ --webhook-url https:///webhook/gitea # план устроил → тот же вызов с apply; затем read-only контроль: python3 scripts/onboard_project.py verify <те же аргументы> ``` **Проверка:** `apply` завершился без ошибок (exit 0; `2` = остались 🖐 ручные шаги — выполните их по отчёту), `verify` зелёный — PASS. Дальше реестр и рестарт: ```bash # 1) строку ORCH_PROJECTS_JSON=[...] из отчёта apply вставить в .env (заменить целиком); # 2) дождаться тихого окна и управляемо перезапустить орк: curl -fsS http://127.0.0.1:8500/queue | python3 -m json.tool | head -20 # нет running-job docker compose up -d --force-recreate orchestrator # 3) убедиться, что инстанс жив и реестр подхвачен: curl -fsS http://127.0.0.1:8500/health curl -fsS http://127.0.0.1:8500/queue | python3 -m json.tool | head -20 ``` **Проверка:** `/health` → 200 после рестарта; в Plane создан проект со статусами (см. §5.3), в Gitea — репо с webhook (§6.3) — PASS. --- ## 11. Smoke: «конвейер доехал» Процедура — чек-лист `docs/operations/REPLICATION.md` §4 (шаги 0–5; шаг 6 «до `done`» — опционально), без форка; каждый шаг несёт явный PASS/FAIL. Lite-предусловия: §2–§10 этого дока выполнены, проект заказчика зарегистрирован (§10). Минимальный сигнал «конвейер доехал» (шаги 4–5 чек-листа): создайте issue в Plane-проекте и переведите в статус **To Analyse**, затем: ```bash # задача появилась и analyst-job в очереди: curl -fsS http://127.0.0.1:8500/queue | python3 -m json.tool | head -40 # по завершении стадии analysis — артефакты 01–04 в ветке задачи: git -C "$ORCH_HOST_REPOS_DIR/" fetch origin git -C "$ORCH_HOST_REPOS_DIR/" ls-tree --name-only origin/<ветка-задачи> "docs/work-items//" ``` **Проверка:** в `/queue` виден job задачи; `ls-tree` показывает `01-brd.md` … `04-test-plan.yaml` — PASS. **Итоговый вердикт:** все шаги чек-листа PASS ⇒ **тираж PASS**; любой шаг FAIL ⇒ тираж FAIL — соберите `docker logs orchestrator --tail 100` и снапшот `GET /queue`, разбор — §13. --- ## 12. Stateless-проверка **Нормативно: данные/задачи/секреты боевого (исходного) хоста НЕ переносятся** (зеркало `docs/operations/REPLICATION.md` §5). БД создаётся **пустой** при первом старте; `.env` / `.env.staging` / `.env.watchdog` собраны с нуля (§4); секреты — только свежевыпущенные (`gen_secrets.py` + чек-лист внешних токенов `docs/operations/REPLICATION.md` §3). Проверка чистоты развёрнутого инстанса (выполнить ДО первой своей задачи): ```bash ls -la <путь-чекаута>/data/ # БД появилась только после первого старта curl -fsS http://127.0.0.1:8500/queue | python3 -m json.tool # счётчики jobs нулевые ``` **Проверка:** в `/queue` нулевые счётчики и НИ ОДНОЙ задачи чужих проектов (никаких `ORCH-*`/`ET-*` исходного хоста) — PASS. Любая чужая задача/перенесённый файл БД — FAIL: инстанс собран не stateless, пересоберите `data/` с нуля. --- ## 13. Траблшутинг первичной настройки Формат: симптом → команда диагностики → лечение. **13.1. Webhook отвечает 401 / HMAC mismatch.** ```bash docker logs orchestrator --tail 50 2>&1 | grep -i "webhook\|signature\|401" ``` Лечение: секрет в `.env` (`ORCH_PLANE_WEBHOOK_SECRET` / `ORCH_GITEA_WEBHOOK_SECRET`) обязан **байт-в-байт** совпадать с секретом в настройке webhook'а (Plane §5.4 / Gitea §6.3); после правки `.env` — управляемый рестарт (§10). Формат подписи — `docs/operations/SETUP_WEBHOOKS.md`. **13.2. Задача в Plane создана, но в оркестраторе не появилась.** ```bash curl -fsS http://127.0.0.1:8500/queue | python3 -m json.tool | head -30 # есть ли job docker logs orchestrator --tail 50 2>&1 | grep -i "ignored\|unknown project" grep ORCH_PROJECTS_JSON .env # uuid вашего проекта в реестре? ``` Лечение: (а) проект отсутствует/с чужим UUID в `ORCH_PROJECTS_JSON` → поправить реестр (§10) + рестарт; (б) webhook не доставлен → Plane: `SELECT url, is_active FROM webhooks;` (§5.4), Gitea: Recent Deliveries в настройках hook'а; (в) подпись → §13.1. **13.3. claude CLI не найден / не аутентифицирован (агент падает на старте).** ```bash docker exec orchestrator /usr/bin/claude --version sudo -u "#" test -r <путь-~/.claude>/.credentials.json && echo "creds: PASS" ``` Лечение: маунты указывают на фактические пути хоста (`ORCH_HOST_CLAUDE_CODE_DIR`, `ORCH_HOST_NODE_BIN`, `ORCH_HOST_CLAUDE_DIR`, `ORCH_HOST_CLAUDE_JSON` в `.env`); креды читаемы uid'ом из §2.2 (`chown -R :`); при невалидной сессии — повторный логин на хосте (§7.2) + `docker compose up -d --force-recreate orchestrator`. **13.4. `docker.sock: permission denied` в логах орка/watchdog.** ```bash getent group docker # фактический gid grep ORCH_DOCKER_GID .env # gid в конфиге ``` Лечение: значения обязаны совпадать → выставить `ORCH_DOCKER_GID` = фактическому gid и `docker compose up -d --force-recreate`. **13.5. `Permission denied` при создании worktree (права `/repos`, ORCH-040/057).** ```bash stat -c '%u:%g' "$ORCH_HOST_REPOS_DIR" "$ORCH_HOST_REPOS_DIR/" grep -E '^ORCH_RUN_(UID|GID)=' .env ``` Лечение: владелец каталога репо обязан совпадать с `ORCH_RUN_UID:ORCH_RUN_GID` (§2.2) → `chown -R : "$ORCH_HOST_REPOS_DIR"` (включая legacy root-owned файлы) и пересоздать контейнер. **13.6. Telegram молчит (нет карточек/алертов).** ```bash curl -fsS "https://api.telegram.org/bot<токен-трекера>/getMe" curl -fsS "https://api.telegram.org/bot<токен-watchdog>/getMe" grep -E '^ORCH_TELEGRAM_(BOT_TOKEN|CHAT_ID)=.+' .env grep -E '^WATCHDOG_TG_(BOT_TOKEN|CHAT_ID)=.+' .env.watchdog ``` Лечение: оба бота отвечают `"ok":true`; chat-id корректен (бот добавлен в чат / получил сообщение); ключи watchdog-бота лежат именно в `.env.watchdog` (в `.env` они инертны, §4.3); пустой токен = режим «логи без отправки» (fail-safe, не ошибка). **13.7. PR задачи не мержится / задача в HOLD.** Первая проверка — **не включена ли branch protection на `main`** (§6.4): ```bash curl -fsS -H "Authorization: token $ORCH_GITEA_TOKEN" \ "$ORCH_GITEA_URL/api/v1/repos///branch_protections" | python3 -m json.tool ``` Лечение: непустой список правил на `main` → удалить (норматив §6.4); merge выполняет PR-merge API оркестратора, ручной merge не требуется. --- *Golden source Lite-тиража (ORCH-102, ADR-001). **Норматив сопровождения (NFR-5, расширен ORCH-104):** меняешь шаги тиража (env-ключи, compose-сервисы, маршрут онбординга, smoke) → обнови этот док **И установочный скрипт `scripts/setup_lite.py`** В ТОМ ЖЕ PR (правило агентов №2). Полноту и гигиену дока держит структурный анти-дрейф тест `tests/test_lite_setup_doc.py`; кирпичи-каноны: REPLICATION.md (карта env §2, секреты §3, smoke §4), ONBOARDING.md (статусы §1, онбординг), SETUP_WEBHOOKS.md (формат вебхуков), `.env.example` / `.env.watchdog.example` (канон ключей).*