196 lines
27 KiB
Markdown
196 lines
27 KiB
Markdown
# 2026-06-05
|
||
|
||
## Orchestrator — CI-гейт качества закрыт ✅ (продолжение self-hosting ORCH-7)
|
||
|
||
### Главный итог
|
||
**CI у orchestrator теперь честно зелёный.** Дефект изоляции тестов (тесты протекали друг в друга через синглтон `settings`) закрыт. Гейт качества для self-hosting работает по-настоящему.
|
||
|
||
### Что было сделано
|
||
- **PR #27** (ветка `fix/isolate-webhook-tests-from-plane`) — три коммита:
|
||
- `7bbab9c` — изоляция 3 webhook-тестов от живого Plane API (моки через ИСТОЧНИК `src.plane_sync.*`)
|
||
- `e856e09` — миграция `test_plane_webhook_generates_sequential_ids` под новый контракт (задача создаётся при переходе В In Progress, а не на `work_item.created`)
|
||
- `1baae81` — **autouse-фикстура в `tests/conftest.py`**, сбрасывает webhook-секрет (+ db_path) на синглтоне settings перед каждым тестом
|
||
- Проверено лично на проде: полный `pytest tests/` в чистом docker-окружении = **294 passed, 0 failed** (было 10 failed). CI run 547/548 = **success** (впервые).
|
||
- 401/HMAC/dedup тесты ЖИВЫ — фикстура их не сломала (они перекрывают её своим monkeypatch). Off-limits зона не тронута: правки только в `tests/conftest.py` и `tests/test_webhooks.py`, src/ чист.
|
||
|
||
### Ключевой урок — интерференция тестов через синглтон settings
|
||
- `Settings` (Pydantic, src/config.py) читает env ОДИН раз при создании объекта `settings`.
|
||
- `test_webhooks.py` ставит секрет жёстко `os.environ["..."]=""` на import-time; другие файлы — через `setdefault`; `test_webhook_dedup.py` ставит реальный `"s3cr3t"` через monkeypatch.
|
||
- В ПОЛНОМ прогоне `pytest tests/` секрет протекал между файлами → HMAC включался → webhook-тесты ловили `assert 401 == 200`. По отдельности файл зелёный, вместе — красный.
|
||
- **Решение-паттерн:** autouse-фикстура в conftest, сброс протекающего состояния синглтона через monkeypatch перед каждым тестом. НЕ менять сам механизм/защищённые тесты — только навести порядок с изоляцией. `db_path` тоже протекал (get_task_by_repo_branch возвращал stale) — Dev законно добавил и его сброс.
|
||
|
||
### Мерж ВЫПОЛНЕН ✅ (05.06, Слава дал «да»)
|
||
- **PR #27 → MERGED в main** (HTTP 200). main HEAD = `d0a3424` Merge PR #27. Все 3 коммита фиксов в истории main.
|
||
- **PR #26 → CLOSED без мержа** (поглощён #27).
|
||
- Нюанс: CI на самом main после merge-commit отдельным прогоном не появился (workflow триггерится на push/PR-ветки; merge-commit мог не дёрнуть). Код в main = ровно то, что прогонялось зелёным (294 passed). Гейт на будущих PR работает.
|
||
- **Пункт №1 self-hosting (CI-гейт) ЗАКРЫТ.** Осталось: удалить отработанные ветки fix/isolate, ci/add (косметика).
|
||
|
||
## Staging-среда для orchestrator (ORCH-30..35) — дизайн оформлен, задачи в Backlog
|
||
|
||
### Решения (гибрид C)
|
||
- Агенты на staging: ПО ДЕФОЛТУ заглушки (быстро/дёшево/детерминированно — гейт проверяет работоспособность ОРКа, не качество LLM) + режим `full-real` по флагу (настоящий Claude CLI через `claude-cli-proxy`).
|
||
- Plane/Gitea на staging — настоящие, но в песочнице (ORCH-SANDBOX проект + orchestrator-sandbox репо).
|
||
- `DEPLOY_REQUIRE_MANUAL_APPROVE=true` на старте — хук тормозит после зелёного staging, ждёт «go» Славы.
|
||
- **Деплоем рулит ВНЕШНИЙ хост-хук, не сам контейнер орка** (орк не может убить свой процесс на середине деплоя; rollback через PREV_IMG, образец `enduro-deploy-hook.sh`).
|
||
- Задачи только в Backlog — конвейер стартует ТОЛЬКО при переходе В In Progress (Feature 1). Backlog безопасен.
|
||
|
||
### Задачи (все Backlog, project ORCH id 8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a)
|
||
- **ORCH-31** id=5a68a13c-3f3b-4d9e-91f7-24b0794bed06 — staging-инфра: контейнер `orchestrator-staging` (порт 8501), изолированная БД через `ORCH_DB_PATH`/volume `./data/staging`, профиль compose `staging`
|
||
- **ORCH-32** id=3dadcf0d-f1b6-4302-8075-8d428ace01f6 — песочница: Plane `ORCH-SANDBOX` + Gitea `orchestrator-sandbox`, реестр через env `ORCH_PROJECTS_JSON` (код не трогать)
|
||
- **ORCH-33** id=a11a7c0f-a78a-4309-9aa5-1c43d4355d0f — тест-сьют (smoke + доступы + e2e), режим full-real
|
||
- **ORCH-34** id=47fe9e75-d7ff-4ecb-bb99-67af9b23ab67 — хост-деплой-хук `orchestrator-deploy-hook.sh` (build candidate→staging-гейт→promote→health 10×6с→auto-rollback), пересекается с ORCH-21
|
||
- **ORCH-35** id=4ead9be7-e1bf-4a28-8c76-88bda1c1fc2c — стадия `deploy-staging` перед `deploy-prod`
|
||
|
||
### Разведка инфры (факты для точных ТЗ)
|
||
- compose: один service `orchestrator`, `network_mode: host`, порт 8500 в команде uvicorn (`uvicorn src.main:app --host 0.0.0.0 --port 8500`). Staging → просто другой порт 8501 + профиль `staging`.
|
||
- `ORCH_DB_PATH` УЖЕ параметризован (config.py:43 дефолт `/app/data/orchestrator.db`) → изоляция БД через него + отдельный volume `./data/staging`.
|
||
- Реестр проектов через env `ORCH_PROJECTS_JSON` (JSON-массив) → sandbox добавляется в `.env.staging`, код менять не надо.
|
||
- В Plane sandbox-проекта ещё НЕТ (есть ag_proj, First, ET, ORCH). В Gitea sandbox-репо ещё НЕТ (enduro-trails, openclaw-vault, orchestrator, wiki). Заведу сама через API при выкате Этапа 2.
|
||
- ТЗ готово: `tasks/orchestrator/DEV_TASK_ORCH31_STAGING_INFRA.md`. Запускать Dev на ORCH-31 ТОЛЬКО когда репо свободно (не толкать двух Dev на один git одновременно).
|
||
|
||
## Грабли/правила (подтверждены этой сессией)
|
||
- Файлы памяти: durable → ТОЛЬКО `memory/YYYY-MM-DD.md` (append). Сегодня `2026-06-05.md`.
|
||
- Dev: код/тесты/конфиги → ТОЛЬКО в Gitea-репо orchestrator через PR. Push в main запрещён (pre-receive hook). Dev НЕ мержит — мержит ревьюер (Стрим/Слава).
|
||
- Инфра вне репо (`.env.staging` реальный, Plane/Gitea sandbox-сущности, хост-деплой-хук, поднятие контейнера) — делаю я через installer/API, НЕ Dev через PR. В репо только `.env.staging.example`.
|
||
- ⚠️ Dev: НЕ регистрировать раннеров, НЕ nohup. Раннер `mva154-runner-orch` уже есть.
|
||
- ⚠️ Off-limits без согласования: HMAC-механизм, 9 HMAC/401 тестов, src/config.py settings, check_reviewer_verdict, check_deploy_status, merge-gate gitea.py, PLANE_STATES, set_issue_done, launcher, queue, stages.py mapping, _parse_tests_verdict, check_tests_local (только DEPRECATED, не удалять).
|
||
- ⚠️ Грабля push: после push `git log origin/main..origin/<branch>` ДОЛЖЕН показать коммит ДО отчёта «PR готов».
|
||
- ⚠️ Plane API: дёргать через base64-stdin+docker cp в контейнер orchestrator. URL `http://localhost:8091` БЕЗ /api/v1 (суффикс добавляет код!), заголовок `X-API-Key`, токен `ORCH_PLANE_API_TOKEN`. Без /api/v1 Plane вернёт HTML(200) вместо JSON.
|
||
- Прогон тестов в чистом окружении (как CI): `docker run --rm -v /home/slin/repos/orchestrator:/code:ro -w /code -e PYTHONPATH=/code --entrypoint python3 $(docker inspect orchestrator --format '{{.Config.Image}}') -m pytest tests/ -q`
|
||
- Эндпоинт Actions: `GET /api/v1/repos/admin/orchestrator/actions/tasks`, токен `docker exec orchestrator printenv ORCH_GITEA_TOKEN`.
|
||
- Сервер: `slin@82.22.50.71` (sshpass, pw motoZ@yaz2010), репо `/home/slin/repos/orchestrator`, контейнер `orchestrator` порт 8500, Gitea https://git.mva154.duckdns.org.
|
||
- Модель Dev: `tokenator/claude-sonnet-4-6` (vibecode кредиты кончились; альт tokenator/claude-opus-4-8).
|
||
- ElevenLabs TTS квота кончилась → отвечать ТЕКСТОМ.
|
||
|
||
## Уборка раннеров (TODO, ждёт ОК Славы)
|
||
3 процесса act-runner: systemd `act-runner.service` (рабочий, mva154-runner), PID 3828601 (старый mva154-runner с 19.05), PID 4091018 (mva154-runner-orch через nohup — НЕ переживёт reboot). План: systemd-unit вместо nohup, прибить лишние. Принести Славе на ОК.
|
||
|
||
## Следующие шаги
|
||
1. [ждёт кивка] Мерж PR #27 в main, закрыть #26 → CI-гейт (пункт self-hosting) закрыт.
|
||
2. Запустить Dev на ORCH-31 (staging-инфра) когда репо свободно.
|
||
3. Этап 2 (ORCH-32): завести ORCH-SANDBOX в Plane + orchestrator-sandbox в Gitea при выкате.
|
||
4. Уборка раннеров (план Славе на ОК).
|
||
|
||
|
||
---
|
||
|
||
## Продолжение сессии (флаш #2)
|
||
|
||
### PR #27 СМЕРЖЕН в main ✅ / #26 закрыт
|
||
- **PR #27 merged** (HTTP 200), main HEAD = `d0a3424` "Merge PR #27". Все три коммита фиксов в истории main (изоляция Plane + seq-тест + изоляция секрета).
|
||
- **PR #26 закрыт без мержа** (поглощён #27). Подтверждено API: #27 state=closed merged=True; #26 state=closed merged=False.
|
||
- CI-гейт качества orchestrator закрыт по-настоящему → главный блокер self-hosting (ORCH-7) снят.
|
||
- Грабля по экранированию: при мерже через Gitea API двойной SSH-эскейп кавычек поехал → передавала скрипт через **base64** (echo b64 | base64 -d | bash). Рабочий приём для сложных команд через sshpass.
|
||
- ⚠️ Косметика-TODO: удалить отработанные ветки `fix/isolate-webhook-tests-from-plane` и `ci/add-gitea-workflow` (обе merged/closed).
|
||
|
||
### Этап 1 (ORCH-31) — staging-инфра ГОТОВА, PR #28 (ждёт мержа на момент флаша)
|
||
- Dev отработал, ветка `feature/ORCH-31-staging-infra`, **PR #28 open, mergeable**.
|
||
- 4 файла, прод-блок compose НЕ тронут (diff чистый: `@@ -25,3 +25,39 @@` — чистое добавление в конце, прод-строки 1-25 без изменений).
|
||
- Проверено на проде лично: обычный `docker compose config` показывает ТОЛЬКО `orchestrator`; staging виден ЛИШЬ с `--profile staging` → случайно не поднимется. Контейнера `orchestrator-staging` на проде нет (крутится только прод, Up 15h). БД изолирована через volume `./data/staging` (на хосте ещё не создан — создастся при первом запуске).
|
||
- ⚠️ Нюанс: `docker compose config --profile staging` без реального `.env.staging` не выводит детали порта 8501 — это норма, реальная валидация при выкате с настоящим `.env.staging` (Этап 2).
|
||
- **Развилка (ждёт ОК Славы):** мержить #28 сейчас (чистый инфра-код в main, ничего не запускается — staging «спящий чертёж») ИЛИ ждать. Я ЗА мерж сейчас (вариант 1) — main маленькими безопасными кусками.
|
||
- На хосте куча `orchestrator.db.bak-deploy*` — бэкапы прод-БД от прошлых деплоев 03-04.06, НЕ наша история, не трогать.
|
||
|
||
### Объяснила Славе что проверяют 294 теста (для контекста)
|
||
Группы тестов orchestrator (страховочная сетка перед самодеплоем): гейт качества (41), Telegram-трекер (28), resilience/переживание рестарта (26), usage+queue (23+19), движок этапов конвейера (22), запуск агентов через Claude CLI (18), webhooks Plane/Gitea + дедуп + подпись (16+9+8), маршрутизация проектов после инцидента 02.06 (16), git-worktree изоляция веток (9), мелочёвка (task.md, комменты, ротация логов, вердикты). Тесты НЕ вшиты в docker-образ — только в репо (правильно).
|
||
|
||
### Время
|
||
Сессия идёт глубокой ночью UTC (~04:40-04:50), у Славы утро ~07:40 UTC+3. Несколько раз предлагала паузу — Слава продолжает работать.
|
||
|
||
### Следующий шаг (на момент флаша)
|
||
Жду ОК Славы: мержить PR #28 → идти на Этап 2 (ORCH-32: песочница Plane ORCH-SANDBOX + Gitea orchestrator-sandbox + реальный `.env.staging` + поднятие staging-контейнера через installer).
|
||
|
||
---
|
||
|
||
## Продолжение (флаш #3) — STAGING-СТЕНД ПОДНЯТ 🚀
|
||
|
||
### PR #28 смержен → Этапы 1+2 выкачены, staging живой на проде
|
||
- **PR #28 merged** (main HEAD `3b68a29`). ⚠️ Грабля: при мерже через Gitea API заголовок `Authorization` сглючил → `token is required` (HTTP 401); фикс — `AUTH = "token " + TOK` отдельной переменной, не инлайнить. Со второго раза HTTP 200.
|
||
- **Этап 2 (ORCH-32) песочница создана:** Gitea-репо `admin/orchestrator-sandbox` (auto-init main) + Plane-проект "ORCH Sandbox" (identifier SANDBOX, **id 8c5a3025-4f9d-4190-b79f-fa06276bb27e**). Имя в Plane БЕЗ дефиса — Plane не пускает спецсимволы в name (ошибка "Project name cannot contain special characters").
|
||
- **Токены — вариант 1** (Слава подтвердил): общие с продом, изоляция по проекту/репо.
|
||
- **`.env.staging` собран** (скрипт из прод-.env + staging-оверрайды), бэкап прод-.env сделан (`.env.bak-before-staging-*`), в .gitignore (IGNORED ok), прод .env цел (23 строки).
|
||
|
||
### Изоляция staging (КЛЮЧЕВОЕ — проверено лично, всё зелёное)
|
||
- **Реестр `ORCH_PROJECTS_JSON` = ТОЛЬКО sandbox** → `known_plane_project_ids()` = {8c5a3025...}, боевые ORCH(8da6aa25)/ET(7a79f0a9) = False → события по ним фильтр ORCH-6 режет в `ignored`. Staging физически не реагирует на боевые задачи.
|
||
- **БД физически раздельная**: volume `./data/staging` → `data/staging/orchestrator.db` (32KB свежая). Прод-БД не трогает.
|
||
- **Telegram пустой** (Слава: вариант 1, staging молчит) — ORCH_TELEGRAM_CHAT_ID="" и BOT_TOKEN="". Не спамит боевой канал.
|
||
- **ORCH_STAGING=true** пометка.
|
||
- Подъём: `sg docker -c "docker compose --profile staging up -d --build orchestrator-staging"`.
|
||
|
||
### Проверки выката (все ✅)
|
||
- staging 8501 /health=ok, /queue=ok (queued/running/done/failed=0, preflight_ok, Claude Code 2.1.142).
|
||
- прод 8500 /health=ok, контейнер Up 16h БЕЗ рестарта (не дёрнулся).
|
||
- реестр: sandbox=True, боевой ORCH=False, боевой ET=False.
|
||
|
||
### Важные технические факты (для след. этапов)
|
||
- **Gitea-webhook прод-репо `orchestrator`** жёстко шлёт на `http://localhost:8500/webhook/gitea`. Sandbox-репо `orchestrator-sandbox` пока БЕЗ хуков (настрою на 8501 в Этапе 3 при e2e).
|
||
- **Plane-webhooks через workspace API = 404** (Plane настраивает их через UI/инстанс plane-app-*, не через API). Прод получает Plane-события webhook'ом на 8500. Staging боевые Plane-события НЕ получит, пока ему отдельно не настроят webhook → плюс к безопасности.
|
||
- Орк роутеры: `/webhook/plane`, `/webhook/gitea` (main.py:92-93, prefix /webhook).
|
||
- 8500=прод (uvicorn pid живой), 8501=staging.
|
||
- `ORCH_REPOS_DIR` в .env=/home/slin/repos, но compose env-секция перебивает на /repos → внутри контейнера /repos (правильно).
|
||
- Образ staging: `orchestrator-orchestrator-staging:latest`, контейнер `orchestrator-staging`.
|
||
|
||
### Следующий шаг
|
||
Этап 3 (ORCH-33): тест-сьют staging — smoke + проверка доступов (Plane sandbox + Gitea sandbox реальными вызовами) + e2e (задача в SANDBOX → ветка в orchestrator-sandbox → статусы+комменты в Plane, верификация по API), режим full-real. Перед e2e: настроить Gitea-webhook sandbox-репо на localhost:8501. Это код для Dev (тест-скрипт) + моя инфра (webhook).
|
||
|
||
|
||
---
|
||
|
||
## Staging-среда orchestrator — Этапы 2-3 ВЫКАЧЕНЫ ✅ (05.06, утро)
|
||
|
||
### Этап 1 (ORCH-31) — закрыт
|
||
- **PR #28 смержен** в main, main HEAD `3b68a29` "Merge PR #28", коммит ORCH-31 `6c1e5ff` в main.
|
||
- ⚠️ Грабля мержа: заголовок авторизации Gitea при первом заходе пришёл как `***` (санитайзер) → HTTP 401 `token is required`. Фикс: явно `token <tok>` → HTTP 200 merged. Запомнить: при мерже через Gitea API проверять, что заголовок реально `token <значение>`, а не затёртый.
|
||
|
||
### Этап 2 (ORCH-32) — песочница создана + staging-контейнер ПОДНЯТ
|
||
- **Gitea-репо песочницы:** `admin/orchestrator-sandbox` (main, auto-init).
|
||
- **Plane-проект песочницы:** name "ORCH Sandbox" (Plane НЕ пускает дефис/спецсимволы в name → без дефиса), identifier `SANDBOX`, **project_id `8c5a3025-4f9d-4190-b79f-fa06276bb27e`**.
|
||
- **Токены — вариант 1 (решение Славы):** общие с продом, изоляция по проекту/репо + раздельная БД (НЕ отдельные токены).
|
||
- **Telegram staging — вариант 1 (решение Славы):** пустой/выключенный, staging молчит в телегу (смотрим по логам/API). Никакого спама в боевой канал.
|
||
- **`.env.staging` собран** на проде (`/home/slin/repos/orchestrator/.env.staging`, в .gitignore, НЕ коммитится): реестр `ORCH_PROJECTS_JSON` = ТОЛЬКО sandbox (боевые ET/ORCH → ignored фильтром ORCH-6), Telegram пустой, БД через volume, `ORCH_STAGING=true`. Прод `.env` (23 строки) цел, бэкап сделан.
|
||
- **Контейнер `orchestrator-staging` поднят на 8501** (`docker compose --profile staging up -d`), образ `orchestrator-orchestrator-staging:latest`. Проверено лично: `/health`=ok, `/queue`=ok (Claude Code 2.1.142 виден), прод `orchestrator` Up 16h БЕЗ рестарта.
|
||
- **Изоляция подтверждена:** staging знает ТОЛЬКО sandbox (`known_plane_project_ids()`={8c5a3025...}); боевые ORCH(8da6aa25)/ET(7a79f0a9) → False; БД физически раздельная `data/staging/orchestrator.db`.
|
||
|
||
### Webhook-изоляция (важная находка)
|
||
- **Gitea webhook прод-репо `orchestrator`** шлёт жёстко на `localhost:8500/webhook/gitea` (прод). Sandbox-репо пока БЕЗ хуков (правильно).
|
||
- **Plane webhooks через workspace API недоступны** (404) — настраиваются на уровне Plane-инстанса/UI (`plane-app-*` контейнеры). Прод-Plane шлёт на 8500. Staging боевые Plane-события НЕ получит, пока webhook в Plane не настроен на 8501.
|
||
- **Главный ключ изоляции:** `ORCH_PROJECTS_JSON` staging = только sandbox → даже если событие прилетит, всё не-sandbox → `ignored` (фильтр ORCH-6).
|
||
|
||
### Этап 3 (ORCH-33) — тест-сьют ГОТОВ, PR #29 (ждёт мержа)
|
||
- Dev написал `scripts/staging_check.py` (smoke A + доступы B + e2e C, exit-code, cleanup в finally) + `docs/STAGING_CHECK.md`. Ветка `feature/ORCH-33-staging-testsuite`. **PR #29 open.**
|
||
- **Проверено лично на проде: 10/10 PASS, exit 0.** Файлы только новые (src/tests/compose/.env не тронуты). Боевое НЕ задето (нет staging-check веток в orchestrator/enduro-trails, нет тест-задач в боевом ORCH). Песочница чиста после cleanup (sandbox-репо = только main, Plane SANDBOX = 0 задач). Прод 8500 жив.
|
||
- **Ключевое архитектурное знание (порядок старта конвейера):** при старте сначала resolve проекта → подтяг name/desc из Plane → QG-0 валидация → **создаётся work_item_id + ветка + начальные доки + строка задачи в БД** → ТОЛЬКО ПОТОМ enqueue аналитика (Claude CLI через launcher). Значит e2e проверяет РАННИЕ артефакты (ветка/доки) ДО запуска LLM — быстро, без расхода кредитов. Аналитика не ждём.
|
||
- **Режима заглушек агентов (гибрид C) в коде НЕТ** — но для e2e он и не нужен (проверяем раннюю стадию до LLM).
|
||
|
||
### Открытый нюанс (не блокер)
|
||
- Bot-токены агентов (`ORCH_PLANE_BOT_ANALYST` и пр.) НЕ добавлены членами в SANDBOX-проект → `add_comment` от их имени = 403. Dev заменил проверку «коммент в Plane» на надёжный ранний артефакт «analyst job в очереди». Чтобы закрыть полностью — добавить бот-аккаунты в SANDBOX через Plane API (моя инфра-работа, мелкая).
|
||
|
||
### Следующие шаги
|
||
1. Мерж PR #29 (Этап 3) — предложено + добавить ботов в SANDBOX.
|
||
2. **Этап 4 (ORCH-34):** хост-деплой-хук `orchestrator-deploy-hook.sh` (промоут staging→prod, health 10×6с=60с, auto-rollback PREV_IMG). Образец `/home/slin/bin/enduro-deploy-hook.sh`.
|
||
3. **Этап 5 (ORCH-35):** стадия `deploy-staging` перед `deploy-prod` в конвейере.
|
||
|
||
### Идентификаторы (Этап 2-3)
|
||
- Plane SANDBOX project_id: `8c5a3025-4f9d-4190-b79f-fa06276bb27e`, identifier `SANDBOX`
|
||
- Gitea sandbox-репо: `admin/orchestrator-sandbox`
|
||
- staging порт 8501, контейнер `orchestrator-staging`, профиль compose `staging`, образ `orchestrator-orchestrator-staging:latest`, БД `data/staging/orchestrator.db`, `.env.staging` (в .gitignore)
|
||
- main HEAD после Этапа 1: `3b68a29`; PR #28 merged, PR #29 open (Этап 3)
|
||
- ТЗ: `tasks/orchestrator/DEV_TASK_ORCH33_STAGING_TESTSUITE.md`; отчёт `tasks/orchestrator/reports/dev-2026-06-05-orch33-staging-testsuite.md`
|
||
|
||
---
|
||
|
||
## Этап 3 закрыт + боты в SANDBOX (05.06, продолжение)
|
||
|
||
### PR #29 смержен → Этап 3 в main
|
||
- **PR #29 merged** (HTTP 200, AUTH="token "+TOK — урок учтён). main HEAD `93169f1`, коммит сьюта `94334bd`.
|
||
|
||
### Нюанс с бот-комментами закрыт (Plane membership)
|
||
- **Корень 403 при `add_comment` бот-токеном:** бот-токен ВИДИТ проект (GET 200), но НЕ может постить комменты, пока его owner НЕ член проекта. Воспроизвела: бот POST comment=403, админ POST comment=201.
|
||
- **7 бот-аккаунтов Plane (workspace members):** Analyst `c925cbcd-a8dc-4506-978e-15354ce3ad31`, Developer `bfe59a48-a7cd-4ce1-a78b-83f8891a4aba`, Reviewer `9836a30d-1294-430d-8109-ceb3e784d1d8`, Tester `7cdfc9e7-c552-4fd1-b4a7-3b1f03e72751`, Architect `6d82b825-c8b2-447c-bca0-c4d34c6200ac`, Deployer `ebf17448-d544-465e-8b0e-57581f76507c`, Стрим `468040f8-f609-406a-84d2-a119880a5e8e`. (+ admin-токен owner = `mva154` daf4d3f4..., + системный `Plane` 43c79cc2...).
|
||
- **Identity бот-токена узнаётся через** `GET {PBASE}/users/me/` с `X-API-Key: <bot-token>` → возвращает id+display_name.
|
||
- **Добавление члена проекта Plane (РАБОЧИЙ формат):** `POST /workspaces/{slug}/projects/{pid}/members/` body `{"member": <user_id>, "role": 15}` ПООДИНОЧКЕ. ⚠️ Формат `{"members":[{...}]}` и `member_id` НЕ работают (400 "member: This field is required"). role 15 = member.
|
||
- **Все 7 ботов добавлены членами SANDBOX** (теперь 8 members). Верифицировано: Analyst и Developer боты постят комменты → HTTP 201. Нюанс Этапа 3 устранён.
|
||
|
||
### Дальше
|
||
Этап 4 (ORCH-34): хост-деплой-хук `orchestrator-deploy-hook.sh` (промоут staging→prod, health 10×6с=60с, auto-rollback по PREV_IMG). Образец `/home/slin/bin/enduro-deploy-hook.sh`.
|