# 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/` ДОЛЖЕН показать коммит ДО отчёта «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 ` → 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: ` → возвращает id+display_name. - **Добавление члена проекта Plane (РАБОЧИЙ формат):** `POST /workspaces/{slug}/projects/{pid}/members/` body `{"member": , "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`. --- ## Этап 4 (ORCH-34) деплой-хук — ГОТОВО ✅ + чистка Plane (05.06, продолжение) ### Закрыты в Plane (Backlog → Done НАПРЯМУЮ, минуя In Progress) - ✅ ORCH-30, ORCH-31, ORCH-32, ORCH-33 → Done (верифицированы). - ⚠️ **Важная тонкость безопасности:** боевой webhook ORCH-проекта идёт на прод (8500). Переход задачи **В In Progress запустил бы конвейер** по ней! Поэтому выполненные задачи двигать **Backlog → Done напрямую, минуя In Progress**. Прод не дёрнулся. - **State id Done** в проекте ORCH: `3738cd3c-7610-4907-ba5e-26b9a248d9c0`. - ⚠️ **In Progress id ПЛАВАЕТ** — был `b873d9eb...` (в памяти), стал `e331bfb3...`. ВСЕГДА запрашивать states свежим API-вызовом, НЕ по памяти. - ОстаютсяBacklog: ORCH-34 (закрою после мержа), ORCH-35 (не начат). ### Бот-аккаунты добавлены в SANDBOX (нюанс Этапа 3 закрыт) - 403 при коммите бот-токеном был НЕ из-за доступа к проекту (GET 200 у всех 7 ботов), а из-за **членства**: чтобы постить комменты, владелец бот-токена должен быть **member** проекта. - **Plane API формат добавления члена:** `POST /projects//members/` с телом `{"member": , "role": 15}` — ПООДИНОЧКЕ (не массивом), поле `member` (НЕ `member_id`!), role 15 = member. - Добавила всех 7 владельцев бот-токенов в SANDBOX → коммент бот-токеном теперь 201 (было 403). Проверено воспроизведением. - user-id ботов узнаются через workspace-members API. ### Этап 4 — деплой-хук (проверено мной на проде, оба сценария) - Dev: `scripts/orchestrator-deploy-hook.sh` (176 строк) + `docs/DEPLOY_HOOK.md`. Ветка `feature/ORCH-34-deploy-hook`, коммит `a6cbacb`. **PR #30 open.** - **Happy-path ✅:** deploy → health ok за 1 попытку → exit 0. - **Авто-rollback ✅ (главное):** Я сама подсунула битый образ (busybox `exit 1`, перетегла как staging-образ) → хук прождал 10×6с=60с (HTTP 000) → САМ откатился на PREV_IMG → рестарт → post-health 5×3с → поднялся → staging снова ok. **Реальный exit-code хука = 1** при фейле (проверила без пайпа `| tail`, который съедал rc). - **Heredoc-грабля Dev:** при передаче скрипта через heredoc терялись кавычки в `grep`/`curl -w` → health давал «not ready» при HTTP 200. Фикс Dev: `cat > файл` из локального файла, не heredoc. ЗАПОМНИТЬ для будущих shell-скриптов через heredoc. - **Прод цел:** StartedAt `2026-06-04T13:08:13Z` не менялся (Up 17h), 8500 ok. Файлы только новые, staging восстановлен, временные теги убраны. - **Параметризация:** дефолт БЕЗОПАСНЫЙ (TARGET_SERVICE=orchestrator-staging, PORT=8501, profile staging). Прод поддержан через override env, но НЕ дефолт. Отдельный PREV_IMAGE_FILE для staging. ### Этап 5 (ORCH-35) — последний, ПЛАН (ещё не спущен Dev) - Цель: встроить стадию **`deploy-staging` ПЕРЕД `deploy-prod`** в конвейер (`src/stages.py`), тестер привязать к staging-эндпоинту 8501. - ⚠️ **Самый рискованный этап:** трогает боевой конвейер деплоя, часть `src/` в off-limits. Перед спуском Dev — ЖИВАЯ разведка по коду стадий (как устроены deploy-стадии, точки встройки), показать план Славе. - Из дизайна §4/§7: промоут с **ручным approve на старте** (`DEPLOY_REQUIRE_MANUAL_APPROVE=true`) — хук тормозит после зелёного staging, ждёт «go» Славы. Полный авто — позже. - Из дизайна §6: агенты на staging — **гибрид C** (заглушки по умолчанию + full-real по флагу). Режима заглушек в коде ПОКА НЕТ (выяснено на Этапе 3) — возможно, понадобится на Этапе 5 или отдельной задачей. ### Идентификаторы (обновление) - main HEAD после Этапа 3 (PR #29 merged): `93169f1` - PR #30 (Этап 4) — open, коммит `a6cbacb` - Done state id (ORCH project): `3738cd3c-7610-4907-ba5e-26b9a248d9c0` - ТЗ Этап 4: `tasks/orchestrator/DEV_TASK_ORCH34_DEPLOY_HOOK.md`; отчёт `tasks/orchestrator/reports/dev-2026-06-05-orch34-deploy-hook.md` - Деплой-хук: `scripts/orchestrator-deploy-hook.sh`, образец enduro: `/home/slin/bin/enduro-deploy-hook.sh` --- ## ORCH-36 (Вариант B самодеплоя) заведён в Backlog + критерии «доверия к автоматике» (05.06) ### ORCH-36 создан в Plane Backlog - **id `84a6c09d-7a03-4cb7-a58b-3d8963c565a5`**, seq 36, name "ORCH-36: Исполняемый самодеплой — стадия deploy дёргает хост-хук (Вариант B)". - Суть: стадия `deploy` реально дёргает хост-хук `orchestrator-deploy-hook.sh` (ORCH-34) через ssh → промоут в прод (8500) с health+авто-rollback. На старте — ОБЯЗАТЕЛЬНЫЙ ручной approve (`DEPLOY_REQUIRE_MANUAL_APPROVE=true`). Делается ПОСЛЕ ORCH-35 (Вариант A — staging-гейт ворота). - Слава: "позже вернёмся" → лежит в бэклоге детально описанной. ### «Доверие к автоматике» — ФОРМАЛЬНЫЕ критерии (для флага true→false) Переход `DEPLOY_REQUIRE_MANUAL_APPROVE` true→false (manual approve → полный авто) — ТОЛЬКО когда ВСЕ 5 закрыты (метрики набираются в режиме ручного approve): 1. **≥10 успешных промоутов подряд** (staging зелёный → approve → прод поднялся, откат не нужен). 2. **Zero false-negative (критично):** staging-гейт НИ РАЗУ не пропустил битый деплой как «зелёный». 3. **Авто-rollback проверен в бою ≥2-3 раза:** recovery rate 100%, MTTR <60с. 4. **Ни одного «молчаливого» деплоя:** каждый промоут/откат → Plane + Telegram. 5. **Период наблюдения:** ≥10 деплоев ИЛИ ≥2 недели без инцидентов в manual-approve. Когда 5/5 → осознанное переключение флага отдельным шагом. ### Этап 5 (ORCH-35) = Вариант A (решение по объёму ждёт Славу: только A или A+B) - Вариант A: стадия `deploy-staging` МЕЖДУ testing и deploy, QG `check_staging_status` (образец `check_deploy_status`), deployer гоняет `staging_check.py` против 8501. Прод-деплой недостижим пока staging не зелёный. Off-limits: не ломать существующие QG/rollback. - Полный план разведки — в `tasks/orchestrator/DESIGN_STAGING_ENV.md` (раздел "РАЗВЕДКА КОДА ДЛЯ ЭТАПА 5"). --- ## Этап 5 (ORCH-35) — staging-гейт встроен ✅, проверено лично + найден архитектурный нюанс (05.06 ~07:30 UTC) ### Что сделано Dev (PR #31, ветка `feature/ORCH-35-staging-gate`, коммит `e0b6e92`, НЕ мержен) Вставлена стадия `deploy-staging` МЕЖДУ `testing` и `deploy`. Новая цепочка: `testing → deploy-staging → deploy → done`. - `src/stages.py` — `STAGE_TRANSITIONS`: `testing→deploy-staging` (agent=deployer, qg=check_tests_passed), `deploy-staging→deploy` (agent=deployer, qg=check_staging_status), `deploy→done` без изменений - `src/qg/checks.py` — новый `check_staging_status` + `_parse_staging_status` (парсит `staging_status: SUCCESS|FAILED` из `15-staging-log.md`), зарегистрирован в `QG_CHECKS` - `src/stage_engine.py` — rollback-ветка: FAILED на deploy-staging → откат на `development` (по образцу БАГ-8 deploy) - `.openclaw/agents/deployer.md` — НОВЫЙ файл (в репо его не было), инструкция для обеих стадий deployer - `tests/test_qg.py`, `tests/test_stage_engine.py` — обновлены + 18 новых staging-тестов ### Проверено МНОЙ лично на проде (не со слов Dev) - **312 passed, 0 failed** — прогнала весь набор сама. Способ: прод-образ орка (там все зависимости) + примонтировала исходники ветки поверх → честный прогон в реальном окружении. (В прод-контейнере `tests/` нет — образ собран без них; чистый python-образ не имеет зависимостей — поэтому монтирование в прод-образ.) - Цепочка вживую: `get_next_stage("testing")=="deploy-staging"`, `("deploy-staging")=="deploy"`, `("deploy")=="done"`; `get_qg_for_stage("deploy-staging")=="check_staging_status"` ✓ - QG-логика вживую: SUCCESS→(True), FAILED→(False), missing→(False) ✓ - Rollback staging-провала → `development` (3 теста) ✓ - git diff: только код (`.openclaw/agents/deployer.md`, `src/qg/checks.py`, `src/stage_engine.py`, `src/stages.py`, `tests/*`). off-limits (.env/compose/staging_check.py/deploy-hook.sh) не тронуты. Прод 8500 не задет. ### ⚠️ АРХИТЕКТУРНЫЙ НЮАНС (раскопала сама, ЖДЁТ решения Славы перед мержем) **Промпты агентов (`deployer.md` и пр.) живут В КАЖДОМ репозитории задач, а не в репо orchestrator.** - `launcher.py` делает `cat {system_prompt}` ВНУТРИ `work_path` (= клон ЦЕЛЕВОГО репо задачи). Путь `.openclaw/agents/deployer.md`. - **enduro-trails-репо** имеет полный набор промптов (analyst/architect/deployer/developer/reviewer/tester.md от 04.06), но deployer.md там СТАРЫЙ — про staging-гейт не знает. - **orchestrator-репо** — Dev положил новый deployer.md с staging-инструкцией (правильно для self-hosting: орк деплоит сам себя, work_path=клон orchestrator). **Проблема:** стадия `deploy-staging` ГЛОБАЛЬНАЯ (в STAGE_TRANSITIONS) → применяется ко ВСЕМ проектам конвейера. Но: 1. У enduro deployer-промпт не знает про staging → не напишет `15-staging-log.md` → гейт FAIL → enduro-задачи откатятся на `development` и застрянут 2. `staging_check.py --base-url localhost:8501` = staging ОРКА. У enduro своего staging нет. Гейт концептуально orchestrator-специфичный. **Варианты (предложены Славе):** - 🅰️ (моя рекомендация) `deploy-staging` УСЛОВНЫЙ — гейт только для self-hosting (проект orchestrator), для остальных стадия пропускается/пустой pass. Правильная инкапсуляция. - 🅱️ оставить как есть + обновить enduro deployer.md + поднять enduro-staging (большой объём, выходит за рамки) - 🅲️ заморозить мерж как known-issue (активных enduro-задач нет), мержить после A **СТАТУС: жду решение Славы. PR #31 НЕ мержен. ORCH-35 НЕ закрыт.** ### Identifiers Этапа 5 - PR `#31` в Gitea (admin/orchestrator), ветка `feature/ORCH-35-staging-gate`, коммит `e0b6e92`, НЕ merged - ORCH-35 issue id: `4ead9be7-e1bf-4a28-8c76-88bda1c1fc2c` - Done state id: `3738cd3c-7610-4907-ba5e-26b9a248d9c0` - Новый артефакт стадии: `docs/work-items//15-staging-log.md`, машинное поле `staging_status:` - Прогон тестов: образ прод-орка + монтирование исходников ветки → 312 passed ## Вариант B вынесен в ORCH-36 (Backlog) — исполняемый самодеплой Создан ORCH-36 «Исполняемый самодеплой — стадия deploy дёргает хост-хук (Вариант B)» в Backlog с детальным описанием. Внутри зашиты 5 метрик «доверия к автоматике» для переключения флага manual approve → авто: 1. ≥10 успешных промоутов подряд (откат не понадобился) 2. Zero false-negative — staging-гейт ни разу не пропустил битый деплой (критично) 3. Авто-rollback в бою ≥2-3 раза (recovery 100%, MTTR <60с) 4. Ни одного «молчаливого» деплоя (каждый → Plane + Telegram) 5. Период ≥10 деплоев ИЛИ ≥2 недели без инцидентов Связи: ORCH-7/21/34/35. Ждёт когда вернёмся. --- ## ORCH-35 ДОРАБОТКА — условный staging-гейт (Вариант А) ✅ проверено лично (05.06 ~07:40 UTC) ### Решение Славы: Вариант А — условный гейт Гейт `deploy-staging` срабатывает реально ТОЛЬКО для self-hosting (проект orchestrator). Для остальных проектов (enduro-trails и пр.) — мгновенный зелёный pass, чтобы их задачи НЕ застряли на откате. ### Что сделал Dev (коммит `e0c14fa` в той же ветке `feature/ORCH-35-staging-gate`) - `src/qg/checks.py:451-455` — `SELF_HOSTING_REPO = "orchestrator"` + `is_self_hosting_repo(repo)` (case-insensitive) - `check_staging_status`: если repo НЕ self-hosting → сразу `(True, "Staging gate N/A for ")`, файл `15-staging-log.md` даже не читается. Если orchestrator → реальная проверка как было. - `STAGE_TRANSITIONS` НЕ трогали — стадия остаётся в цепочке для всех, условность зашита в QG. - `tests/test_qg.py` — +7 новых тестов под условную логику ### Проверено МНОЙ лично на проде (прод-образ орка + примонтированы исходники ветки) - **319 passed, 0 failed** (было 312, +7 новых) - Условность вживую (через `docker cp` файла в контейнер, НЕ `-v` mount — volume-mount файла НЕ подхватывается, урок!): - `check_staging_status("enduro-trails", ...)` → (True, "Staging gate N/A...") БЕЗ файла ✓ - `check_staging_status("orchestrator", ...)` без файла → (False) ✓, с `staging_status: SUCCESS` → (True) ✓ - repo приходит как plain gitea name (`ProjectConfig.repo` из реестра `projects.py`) — подтверждено, сравнение корректное - Доработка тронула только `qg/checks.py` + `tests/test_qg.py`. git diff ветки показывает 6 файлов — это НАКОПЛЕННЫЙ diff всей ветки против main (первый коммит e0b6e92 + доработка e0c14fa), сама доработка stages.py НЕ меняла. ### projects.py (разведано, реестр проектов из ORCH-6 фикса 02.06) Связывает Plane-проект uuid ↔ Gitea-репо ↔ префикс. `ProjectConfig` (frozen): plane_project_id, repo, work_item_prefix, name. Источник: env `ORCH_PROJECTS_JSON` → settings.projects_json, fallback `_DEFAULT_PROJECTS` (enduro-trails ET первый намеренно, orchestrator ORCH). Парсер устойчив (битый элемент скип, пусто→дефолт). Отсюда берётся способ отличить self-hosting (repo=="orchestrator"). ### СТАТУС: ✅ СМЕРЖЕНО И ЗАКРЫТО (05.06 ~07:43 UTC) - PR `#31` СМЕРЖЕН (merge commit `f1b3146`, merged=True/closed). main HEAD = `f1b3146`, под ним `e0c14fa` + `e0b6e92`. - ORCH-35 переведён Backlog→Done напрямую (HTTP 200, state `3738cd3c`). Мимо In Progress — webhook не дёрнут. - ORCH-35 id `4ead9be7-e1bf-4a28-8c76-88bda1c1fc2c` ### 🏁 СЕРИЯ САМОДЕПЛОЯ — ФИНАЛ Все 5 этапов готовы и проверены лично: - Этап 1 ORCH-31 ✅ Done (PR #28) - Этап 2 ORCH-32 ✅ Done (песочница staging 8501) - Этап 3 ORCH-33 ✅ Done (PR #29, staging_check.py) - Этап 4 ORCH-34 ✅ Done (PR #30, deploy-hook.sh + авто-rollback) - Этап 5 ORCH-35 ✅ DONE (PR #31 смержен `f1b3146`, условный staging-гейт, 319 тестов) - Вариант B вынесен в ORCH-36 (Backlog) — исполняемый деплой, на потом --- ## ДОКУМЕНТАЦИЯ ОРКА = golden source в репо (задача Славы 05.06 ~08:30) Слава хочет: вся дока по орку в репо (код+дока по единым канонам), чтобы мульти-агенты знали где дока, ИСПОЛЬЗОВАЛИ и АКТУАЛИЗИРОВАЛИ. ### КЛЮЧЕВОЙ ИНСАЙТ (подтверждён Славой): структура папок ≠ агенты её используют. Агент видит ТОЛЬКО свой system_prompt (`.openclaw/agents/.md`) + task. Канон держится на 3 слоях. ### 3-слойный канон (согласован): 1. **Структура docs/**: README, ARCHITECTURE, PIPELINE, PRODUCT_VISION, adr/ (1 решение=1 файл adr-NNNN-slug.md), operations/, work-items//, history/ (архив), CHANGELOG, CONTRIBUTING, AGENTS.md 2. **Промпты агентов** (★): полный набор `.openclaw/agents/*.md` в репо орка по образцу enduro — жёстко: читай docs/, пиши work-items, архитектор ведёт ADR, каждый обновляет CHANGELOG. **Reviewer-gate**: если доку не обновили → REQUEST_CHANGES (канон держится автоматически) 3. **Канон процесса**: CONTRIBUTING.md + AGENTS.md в корне, на них ссылаются промпты ### ⚠️ ИНФРА-ИЗОЛЯЦИЯ (проверено по факту): - **РИСК:** прод-орк (8500) — ОДИН инстанс на ВСЕ проекты (ET+ORCH), ОБЩАЯ БД `/app/data/orchestrator.db`, общая очередь. Self-доработка орка бежит в том же инстансе, что держит ET → рестарт/падение = групповой риск. Staging-гейт (ORCH-35) — страховка. - **ХОРОШО:** staging (8501) полностью изолирован (свой ORCH_PROJECTS_JSON=только sandbox); репы раздельные (worktree ORCH-2) - **Инфру ВЕДЁМ в репо:** `docs/operations/INFRA.md` (RUNBOOK). Секреты — ТОЛЬКО в .env хоста (.env.example канон). Уже есть: .env.example, .env.staging.example, compose, Dockerfile трекаются; .env НЕ в гите ✓ ### ⚠️ ДЫРА у орка: в репо orchestrator `.openclaw/agents/` — ТОЛЬКО deployer.md! Нет analyst/architect/developer/reviewer/tester. У enduro — полный набор с дока-каноном. self-доработка орка упадёт без этих промптов. ### ЗАДАЧИ Plane: - **ORCH-9** «Онбординг (turnkey)» — НАПОЛНИЛА детально (3-слойный канон + инфра + AC), id `c333bf6a-76dd-4214-aab2-61af4a8fbc58`, Backlog. Источник: `temp/orch9_desc.md` - ORCH-11 «Полная дока мультиагентов» id `a396db3e-8618-491f-b62c-cc2bc490e502` (пустая) - ORCH-24 «Персистентная БЗ» id `4c2009b3-3dad-456f-9f9e-1c1fa3d9dda6` (пустая) ### РЕШЕНИЯ Славы (финал по канону): 1. **Паспорт = per-repo `CLAUDE.md`** (НЕ AGENTS.md, НЕ единый на все). Изоляция репо/проектов — фича. Каждый проект — свой паспорт, точно описывает свой проект. Канон enduro: CLAUDE.md + docs/architecture/ (папка!) + adr/, артефакты 00-business-request..15-staging-log, 04-test-plan.YAML (не md!), per-wi ADR-NNN (upper) / global adr-NNNN (lower). НЕТ CONTRIBUTING.md — конвенции внутри CLAUDE.md. 2. INFRA.md остаётся как орк-специфика (у enduro аналога нет, но self-hosting риск реален). 3. Промпты агентов + reviewer-gate — СЕЙЧАС через Dev. 4. ORCH-9 — сформировать ПРИНЦИПЫ подготовки промптов (методичка), ET = пример-референс, НЕ генерить промпты под enduro. ### СДЕЛАНО: - **Комплект доки** (8 файлов) написала САМА по канону enduro, выверено против кода (ДВА ревью: сначала нашла что выдумала свой канон ≡ AGENTS/CONTRIBUTING, потом переписала под enduro-канон). Архив: `temp/orch_docs_canon.tgz`, доставлен на slin `/tmp/orch_docs_canon.tgz`. Исходники: `temp/orch_docs/`. - **Методичка ORCH-9** `tasks/orchestrator/ORCH9_PROMPT_PRINCIPLES.md` — принципы подготовки промптов (каркас, инварианты, роль-специфика, reviewer-gate, ET=референс). Ссылка добавлена в описание ORCH-9. - **Dev запущен** (orch9_docs_canon, session eef3f0c0): ТЗ `DEV_TASK_ORCH9_DOCS_CANON.md` — заливка доки + реструктуризация docs/ (git mv в operations/, history/, ARCHITECTURE.md→architecture/internals.md) + промпты агентов (analyst..tester) + reviewer-gate. Ветка docs/ORCH-9-canon, PR не мержить. ### ПРОВЕРИТЬ после Dev (лично): структура docs/ по канону, полный набор .openclaw/agents/ (6 ролей), 0 битых ссылок, git mv сохранил историю, README цепочка актуальная, reviewer-gate в promptе, diff только docs/.openclaw (НЕ src/tests/compose). 🏁🏁🏁 СЕРИЯ САМОДЕПЛОЯ ПОЛНОСТЬЮ ЗАВЕРШЕНА 05.06.2026. Орк имеет staging-предохранитель: прод-деплой недостижим, пока staging-гейт не зелёный (для self-hosting). Следующий шаг когда вернёмся — ORCH-36 (исполняемый деплой) с 5 метриками доверия. ### ORCH-9 (часть 1) ЗАВЕРШЕНА Dev → ПРОВЕРЕНО МНОЙ ЛИЧНО на проде ✅ (PR #32, коммит `7c68d1d`, НЕ смержен) Dev (session orch9_docs_canon) отработал, я проверила не со слов: - **Структура канона:** `CLAUDE.md` (5543b, паспорт орка) + `CHANGELOG.md` в корне; мои маркеры целы (self-hosting, deploy-staging, 04-test-plan.yaml, ADR-NNN). `docs/` по канону enduro: `architecture/` (README + adr/ + internals.md), `operations/` (INFRA, DEPLOY_HOOK, STAGING, STAGING_CHECK, SETUP_WEBHOOKS), `history/` (8 архивных BUGFIXES/LESSONS/INCIDENT). - **git mv сохранил историю** (R097/R100 в diff = renames, не пересоздание). Старый docs/ARCHITECTURE.md → docs/architecture/internals.md (глубина: схема БД SQL, resilience, потоки — сохранена). - **Промпты агентов (6 ролей)** `.openclaw/agents/`: analyst, architect, developer, reviewer, tester, deployer. Все ссылаются на CLAUDE.md + docs/architecture/README.md. Модели верные (architect/reviewer→opus, остальные→sonnet, сверено с launcher.py AGENT_CONFIGS). architect ведёт ADR (per-wi 06-adr/ADR-NNN + сверка с global architecture/adr/). self-hosting раздел у architect/developer/deployer (не ронять прод-контейнер, ссылка INFRA). - **Reviewer-gate:** reviewer.md содержит правило REQUEST_CHANGES при необновлённой доке (P0, через YAML verdict:, БЕЗ правки кода QG). - **Чистота diff:** ТОЛЬКО docs/ + .openclaw/agents/ + README/CLAUDE/CHANGELOG. Код/тесты/compose/.env/scripts НЕ тронуты. ✅ - README + internals цепочка актуальна (deploy-staging). ### РАЗДЕЛЕНИЕ СКОПА (Слава, 05.06 Вариант Б): две РАЗНЫЕ задачи, НЕ мешать! - **Орк-специфика (паспорт+промпты САМОГО орка+reviewer-gate)** = **self-hosting**, не ORCH-9. Остаётся в репо orchestrator, **PR #32 СМЕРЖЕН в main 05.06** (Слава дал «делай» → мерж через API): merge commit `5ecd1c4`, merged=True/closed. main HEAD = `5ecd1c4`. Методичка ОТКАЧЕНА из этой ветки (reset 7c68d1d, force-with-lease). Ветка docs/ORCH-9-canon HEAD = `7c68d1d` (только орк-канон). - **Онбординг (ORCH-9)** = **ОТДЕЛЬНЫЙ РЕПО `onboard2orch`** (Слава: онбординг ≠ код орка, изоляция). Создан: https://git.mva154.duckdns.org/admin/onboard2orch (коммит `3b0ea44`). Структура: README.md, principles/PROMPT_PRINCIPLES.md, checklists/ONBOARDING_CHECKLIST.md, examples/enduro-trails/README.md (референс-указатели, НЕ копии). Описание ORCH-9 в Plane обновлено ссылкой на репо. - Исходники onboard2orch: `temp/onboard2orch/`. Методичка-оригинал остаётся в `tasks/orchestrator/ORCH9_PROMPT_PRINCIPLES.md` (process-копия). - ГЛАВНЫЙ УРОК: не мешать «про орк как проект» и «про онбординг любых проектов». Разные репо, разные задачи. Слава поймал моё смешение скопа. ### (устарело, было до разделения): 1. **PR #32 мержит Слава ВРУЧНУЮ** (правило: агентам push/merge в main запрещён). Если попросит «мержи» прямо — могу через API. Пока ждёт его ручного мержа. 2. **Методичку положила в репо** → `docs/operations/ONBOARDING_PROMPTS.md` (коммит `23c7950`, в той же ветке docs/ORCH-9-canon → часть PR #32). Ветка теперь: 7c68d1d (канон+промпты) + 23c7950 (методичка). - Ветка docs/ORCH-9-canon HEAD = `23c7950`, main = `f1b3146` (до мержа PR #32). ### Артефакты ORCH-9: - ТЗ Dev: `tasks/orchestrator/DEV_TASK_ORCH9_DOCS_CANON.md` - Методичка: `tasks/orchestrator/ORCH9_PROMPT_PRINCIPLES.md` (КАРКАС промпта + инварианты канона + роль-специфика + чеклист готовности; ET=референс, не шаблон) - Комплект доки (исходники): `temp/orch_docs/` (CLAUDE.md, CHANGELOG.md, docs/architecture/README.md + adr/adr-0001..0003 + adr/README.md, docs/operations/INFRA.md) - Архив доставки: `temp/orch_docs_canon.tgz` → slin `/tmp/orch_docs_canon.tgz` - Отчёт Dev: `tasks/orchestrator/reports/dev-2026-06-05-orch9-docs-canon.md` ### ЗАПУСК САМОДОРАБОТКИ — ревью готовности (05.06, Слава: «Старт», таска ORCH-16): - **БЛОКЕР 1 УСТРАНЁН:** прод-образ отставал (checks.py без is_self_hosting_repo). Ребилд из main `5ecd1c4` (ОК Славы). Постпроверка: checks.py=main `3f9fe07`, is_self_hosting_repo(enduro)=False/(orchestrator)=True, staging-gate enduro=пропуск, 6 ET-задач на месте, 319 passed. Прод синхронен. (Тесты НЕ в образе — Dockerfile COPY только src/+data/, гонять из /repos/orchestrator или CI.) - **БЛОКЕР 2 = ORCH-10 (в работе):** plane_sync.py хардкодит PLANE_STATES = UUID СТАТУСОВ ТОЛЬКО ENDURO. ORCH-проект имел 5 базовых статусов, нет стадийных. Слава: «сделать в ORCH такую же статусную модель как в ET, недостающие добавить». - **СДЕЛАЛА:** создала 9 недостающих статусов в ORCH-проекте через Plane API (Architecture/Development/Review/Testing/Approved/Rejected/Needs Input/In Review/Blocked) — теперь 14 шт, идентично ET по составу. UUID НОВЫЕ (свои у ORCH). - **Dev запущен** (orch10_states, session 305f824d): ТЗ `DEV_TASK_ORCH10_PER_PROJECT_STATES.md` — динамический резолвинг статусов по project_id (get_project_states + кэш + fallback _DEFAULT_STATES). КРИТИЧНО: webhook-сравнение in_progress резолвить по проекту (иначе ORCH-задача не стартует). Ветка feature/ORCH-10-per-project-states. - **ORCH-10 ГОТОВ → ПРОВЕРЕНО МНОЙ лично (PR #33):** diff только plane_sync.py+webhooks/plane.py+tests, 342 passed (+23), резолвинг живой (ET→b873d9eb/3020bbb7, ORCH→e331bfb3/795cc32f, UUID разные), enduro не сломан. get_project_states(project_id)+кэш+fallback _DEFAULT_STATES. ЖДЁТ МЕРЖА PR #33. После мержа → ребилд прода → проверка в контейнере → ORCH-16 старт. - Полные карты UUID обоих проектов — в ТЗ (сняты с прода). ORCH-37 заведена (гигиена статусов Plane, Backlog, id 9ccc5490). ORCH-16 ОСТАЛАСЬ в Backlog (мой PATCH state упал 400 — и хорошо, конвейер НЕ запущен). В описание ORCH-16 дописаны ответы на 2 вопроса (текст+ссылка+1-строка вердикт; один коммент на агента). - **ПОРЯДОК:** ORCH-10 (Dev) → ребилд прода → проверка резолвинга лично → ТОГДА ORCH-16 Backlog→In Progress (старт конвейера). - ORCH-16 = «Единообразные коммент-артефакты в Plane» id `2b80c58c-2a83-4ab0-aa69-b7f5d2f8c345`, мелкая, наполнена. Первая самодоработка-прогрев. ### КЛЮЧЕВЫЕ PLANE state-id (оба проекта): - **ORCH** in_progress `e331bfb3-e17e-4699-ba48-4abb89c21b7b`, backlog `2d5d42ff-...`, done `3738cd3c-...`. Стадийные: architecture `795cc32f`, development `f5ed4705`, review `2026f3d9`, testing `81c5cd78`, approved `63f2c8fe`, rejected `4c769e90`, needs_input `99978b3f`, in_review `c52e99b9`, blocked `505f01a6`. - **ET** in_progress `b873d9eb-...` (остальные — в ТЗ ORCH-10 и plane_sync.py PLANE_STATES). - ORCH-проект plane_id `8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a`, ET plane_id `7a79f0a9-5278-49cd-9007-9a338f238f9c`. ### ФАКТЫ ОРКА (золотой источник, для будущих сессий): - НЕТ Makefile, НЕТ budget.yaml (в отличие от enduro). Тесты: `pytest tests/ -q` (из .gitea/workflows/ci.yml). CI = Gitea Actions. - Прод 8500, staging 8501 (изолированная БД ./data/staging, profile staging, только sandbox-проект). External: https://openclaw.mva154.duckdns.org/orchestrator/. Webhook: .../orchestrator/webhook/gitea (+ /webhook/plane). - Эндпоинты: GET /health, /status, /queue; POST /webhook/plane, /webhook/gitea (prefix /webhook + route). - ADR-формат: per-work-item `docs/work-items//06-adr/ADR-NNN-slug.md` (UPPER, 3 цифры); сквозные `docs/architecture/adr/adr-NNNN-slug.md` (lower, 4 цифры). Индекс — adr/README.md. - Канон артефактов: 00-business-request, 01-brd, 02-trz, 03-acceptance-criteria, 04-test-plan.YAML, 06-adr/, 07-infra-req, 08-data-req, 10-tech-risks, 12-review(verdict:), 13-test-report, 14-deploy-log(deploy_status:), 15-staging-log(staging_status:). - main HEAD до PR #32 = `f1b3146` (merge ORCH-35). ### Эталон enduro для канона: `/home/slin/repos/enduro-trails/` — CLAUDE.md (паспорт), docs/architecture/ (README+adr), .openclaw/agents/*.md (6 ролей, эталон каркаса промпта: frontmatter→контекст→что прочесть→что произвести→принципы→запрещено→эскалация). # 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 (подробности выше по тексту дня; см. историю) --- ## СЕССИЯ flush 11:36 UTC — ребилд прода + статусная модель ORCH = ET ### Ребилд прода ВЫПОЛНЕН ✅ (Слава дал ОК) - Блокер `src/qg/checks.py` рассинхрон устранён: `docker compose up -d --build orchestrator` из main (`5ecd1c4`). - Постпроверка ЛИЧНО: прод checks.py == main `3f9fe07`; `is_self_hosting_repo("enduro-trails")`=False (ET пропускает staging-гейт «N/A»), `("orchestrator")`=True; 6 ET-задач на месте; очередь+breaker(closed)+preflight живы; **319 passed** (тесты гонятся из /repos/orchestrator — в образ НЕ копируются, только src/+data/). - ФАКТ: Dockerfile орка `build: .` копирует только `src/` + `data/`; тестов в образе нет (CI/репо). ### Статусная модель ORCH приведена к ET ✅ (Слава: «использовать такую же модель как в ET, не хватает — добавь») - В ORCH-проекте было 5 базовых статусов, в ET — 14. **Создала 9 недостающих через Plane API** (Architecture/Development/Review/Testing/Approved/Rejected/Needs Input/In Review/Blocked) с теми же name/color/group. Теперь ORCH = 14, идентично ET по составу. - ⚠️ UUID у ORCH-статусов СВОИ (Plane генерит уникальные) → всплыл блокер ORCH-10 (код хардкодит ET-UUID). Самое критичное: webhook распознавал «старт конвейера» только по ET-UUID in_progress → ORCH-задача (её UUID e331bfb3) НЕ стартовала бы. Поэтому мой PATCH ORCH-16 state упал 400 — и хорошо, конвейер не встал криво. ### ORCH-10 (per-project резолвинг статусов) — ГОТОВ, ПРОВЕРЕН ЛИЧНО, PR #33 ЖДЁТ МЕРЖА - Сделал Dev по ТЗ `DEV_TASK_ORCH10_PER_PROJECT_STATES.md` (полные карты UUID обоих проектов в ТЗ — Dev не гадал). - Решение: `get_project_states(project_id)` читает статусы из Plane API + кэш `_STATES_CACHE` + fallback `_DEFAULT_STATES` (=текущие ET-значения). `reload_project_states()` для сброса. - Проверено мной: diff только plane_sync.py+webhooks/plane.py+tests; **342 passed (+23, 0 регрессий)**; живой резолвинг ET→ET-UUID (in_progress b873d9eb, architecture 3020bbb7), ORCH→ORCH-UUID (in_progress e331bfb3, architecture 795cc32f), UUID разные; enduro не сломан; webhook-старт распознаётся для обоих проектов. - **PR #33:** https://git.mva154.duckdns.org/admin/orchestrator/pulls/33 — НЕ смержен, жду «мержи» от Славы. ### ORCH-37 заведена (по просьбе Славы) — гигиена статусов Plane - Backlog, id `9ccc5490`. Суть: статусов на доске много, используем не все → ревизия + чистка неиспользуемых/дублей, минимальный набор под фактический конвейер. ОБЯЗАТЕЛЬНО согласовать со Славой и не сломать ET (статусы общие, после ORCH-10 резолвятся per-project). Не срочно. ### ✅✅✅ ORCH-16 ЗАПУЩЕНА — ПЕРВАЯ САМОДОРАБОТКА ОРКА В ПОЛЁТЕ (11:44 UTC) 1. ✅ PR #33 СМЕРЖЕН (Слава: «мержи»), merge commit `a2cf145`, main обновлён. 2. ✅ Ребилд прода из main выполнен, health 200. 3. ✅ Резолвинг в ЖИВОМ контейнере: ET→b873d9eb, ORCH→e331bfb3/795cc32f, разные, ET-задачи (6) целы, очередь жива. 4. ✅ ORCH-16 Backlog→In Progress → **webhook СТАРТАНУЛ конвейер**: Task 33, analyst запущен (run_id=93, pid=78), стадия analysis, ветка `feature/ORCH-016-plane`, worktree создан, 00-business-request.md записан. claude.exe реально пашет (роль analyst прочиталась из клона репо — self-hosting каркас работает). - **ГРАБЛЯ №1 (решена):** QG-0 завернул первый старт — `Title слишком длинный (макс 80 символов)`. Орк корректно перевёл в Blocked (наш новый ORCH-статус 505f01a6 сработал — резолвинг per-project в бою!). Укоротила название до 55 симв («Единообразные коммент-артефакты в Plane от всех агентов»), сброс Backlog→In Progress → старт прошёл. ⚠️ **УРОК:** название задачи ORCH/ET ≤80 символов, иначе QG-0 блок. - **ГРАБЛЯ №2 (не системная):** транзиентный 403 на коммент аналитика при залпе webhook-ов (гонка при сбросе статуса). Ручной POST коммента прошёл 201 — токен прав имеет. Не блокер, конвейер не встал. - ORCH-16 id `2b80c58c-2a83-4ab0-aa69-b7f5d2f8c345`, в описании ответы на 2 вопроса (текст+ссылка+1-строка вердикт; один коммент на агента за стадию). Дальше конвейер идёт сам: analysis→architecture→development→review→testing→deploy. НЕ дёргать без нужды. - **PATCH статуса Plane:** правильное поле = `state` (НЕ `state_id`), значение = UUID статуса. `{"state":""}` → HTTP 200. ### 🎉🎉 ORCH-16 ДОЕХАЛ ДО DONE — ПЕРВАЯ ПОЛНАЯ САМОДОРАБОТКА ОРКА (12:52, 05.06) - Полный цикл: Backlog→In Progress→analysis→architecture→development→review→testing→deploy-staging→deploy→**done**. Все стадии авто, очередь чистая (done 39, failed 0). Ветка feature/ORCH-016-plane, фича закоммичена (`0663da6 feat(plane): unified status-comment format with duration line`). - **Фикс ботов (важный урок):** 403 на комменты — боты-агенты не были членами ORCH-проекта. Добавила 7 ботов через `POST /projects//members/` поле `{"member":,"role":15}` (НЕ member_id). user_id ботов взяла из ET: Reviewer 9836a30d, Стрим 468040f8, Architect 6d82b825, Analyst c925cbcd, Deployer ebf17448, Tester 7cdfc9e7, Developer bfe59a48. Теперь ORCH = 8 членов. - **Rework-цикл работает:** Слава отклонил (Rejected) + коммент «добавьте длительность работы» → орк прокинул причину в .task.md → аналитик доработал. Результат: usage-метрики в комментах (`📛 Architect готов · 345.7k in / 14.7k out · $0.91`). - **ГРАБЛЯ QG-0:** название >80 символов → Blocked. Укоротила. Правило: название задачи ≤80. - onboard2orch чеклист обновлён (коммит e8d521bf): Шаг 1a (статусы Plane) + Шаг 1b (боты в проект) + усилен Шаг 5. ### 💰 РАСХОД ORCH-16 — вскрылась проблема бюджета (→ ORCH-38) - Итого ORCH-16: **~$20.32** (analyst $1.10+$1.71, architect $0.91, developer **$13.68**, reviewer $2.13, tester $0.78). - **КОРЕНЬ:** стоимость линейна от `cache_read_tokens` (перечитывание контекста циклами tool-call). developer run 96: cache_read **18.98M**. - **ET vs ORCH (пруф agent_runs):** ET developer avg **$1.91** (n=16), макс $9.16 (run 65, 11.98M). ORCH developer $13.68. Вывод: раздувание было и в ET (run 65), но в ORCH пик (~7.5x типичного). Гипотезы: промпт developer не даёт целевые файлы→слепой обход src/; модель opus дороже sonnet. - Агенты пишут usage в БД `agent_runs` (cols: cost_usd, input_tokens, output_tokens, cache_read_tokens, cache_creation_tokens, model, agent, task_id). `/app/data/orchestrator.db`. ### НОВЫЕ ORCH-ЗАДАЧИ (Backlog): - **ORCH-37** Гигиена статусов Plane (id 9ccc5490) — ревизия/чистка неиспользуемых. - **ORCH-38** Бюджет и эффективность агентов (id 2afa7b07) — контроль расхода токенов: целевые файлы в task, бюджет-лимит per-stage, метрика-сводка, sonnet vs opus. ### Скоуп ORCH-9 разведён (Вариант Б, ранее в сессии): - Орк-репо = только орк (PR #32 смержен в main `5ecd1c4`: CLAUDE.md паспорт + дока канона + 6 промптов + reviewer-gate). - Онбординг = отдельный репо `onboard2orch` (https://git.mva154.duckdns.org/admin/onboard2orch, коммит 3b0ea44): principles/checklist/examples(ET-референс). Методичка убрана из орк-ветки. ### КЛЮЧЕВЫЕ PLANE state-id (оба проекта, для будущих сессий): - **ORCH** (plane_id `8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a`): backlog `2d5d42ff`, todo `b5d3f512`, in_progress `e331bfb3`, architecture `795cc32f`, development `f5ed4705`, review `2026f3d9`, testing `81c5cd78`, approved `63f2c8fe`, rejected `4c769e90`, done `3738cd3c`, cancelled `59d1d210`, needs_input `99978b3f`, in_review `c52e99b9`, blocked `505f01a6`. - **ET** (plane_id `7a79f0a9-5278-49cd-9007-9a338f238f9c`): backlog `113b24f6`, todo `2c7d3df3`, in_progress `b873d9eb`, architecture `3020bbb7`, development `9920609b`, review `ba0d802c`, testing `7855d807`, approved `a519a341`, rejected `ba958f3c`, done `381a2833`, cancelled `b1cae7f9`, needs_input `babf08a3`, in_review `38fb1f64`, blocked `6c4543f9`. ### ФАКТЫ ОРКА (золотой источник): - НЕТ Makefile, НЕТ budget.yaml. Тесты: `pytest tests/ -q`. CI = Gitea Actions. - Прод 8500, staging 8501 (изолир. БД ./data/staging, profile staging). External: https://openclaw.mva154.duckdns.org/orchestrator/. Webhook: .../orchestrator/webhook/gitea (+ /webhook/plane). - Эндпоинты: GET /health, /status, /queue; POST /webhook/plane, /webhook/gitea. - Dockerfile `build: .` копирует только src/ + data/ (тестов в образе нет). - Webhook старт конвейера: `if new_state == PLANE_STATES["in_progress"]` (после ORCH-10 — резолв по project_id). Фильтр по проекту: unknown project → ignore (ORCH-6). - main HEAD = `5ecd1c4` (Merge PR #32). - Прод: контейнер `orchestrator`, image `orchestrator-orchestrator`. SSH: `sshpass -p 'motoZ@yaz2010' ssh slin@82.22.50.71`. compose `/home/slin/repos/orchestrator/docker-compose.yml`. ### Эталон enduro для канона: `/home/slin/repos/enduro-trails/` — CLAUDE.md, docs/architecture/, .openclaw/agents/*.md (6 ролей). --- ## 🔧 ORCH-16 деплой + ORCH-39 (тесты/CI) — финал дня (05.06 вечер) ### ORCH-16: done ≠ в проде (важное различие) - ORCH-16 в Plane = `done`, НО фича в прод НЕ выкачена. deploy-staging прошёл (`staging_status: SUCCESS`, коммит `053ea3b` — только docs, merge staging-log в main). - Фича-код `0663da6` (единый формат коммента + строка длительности) — только в ветке `feature/ORCH-016-plane`. **PR #34 ОТКРЫТ, не влит.** - Прод на 8500 работает на СТАРОМ коде. Это правильный предохранитель self-hosting: орк не мержит/не ребилдит себя сам без ОК Славы. ### Ревью PR #34 лично (вердикт) - +3452/-112, 27 файлов. Боялась мусора за $13.68 — оказалось код ГРАМОТНЫЙ. - `build_status_comment()` — единая точка для всех ролей. Обратная совместимость сохранена (старые `usage_comment`/`artifact_links` не удалены). `frontmatter.py` — защитный ридер, никогда не падает. - 43 теста ORCH-16 — зелёные. - НО: 4 теста падали (`test_m6_sequence.py` ×2, `test_plane_webhook.py` ×2) — НЕ вина ORCH-16, пришли с ORCH-10 (PR #33), отставший контракт. ### Типы item в Plane (этот инстанс) — проверено через API - ❌ Epics = 404, issue-types/work-item-types = 404 (кастомные типы выключены) - ✅ `parent` у issue → sub-issues (под-задачи) РАБОТАЮТ - ✅ `modules` (≈эпики), `cycles` (спринты) — есть, но пусты (n=0) - Декомпозиция: через `parent` + `modules`, не через Epic→Story→Task типы. ### ORCH-39: починка отставших тестов + дыра CI - Завела ORCH-39 (id `7c061055`, Backlog) — для трекинга. Исполнение НЕ конвейером, а **Dev напрямую** (принцип ORCH-38: не жечь $15-20 на правку 4 тестов). - **Корень падений (диагноз мой):** тесты хардкодят `_IN_PROGRESS = "b873d9eb..."` (ET in_progress UUID) для запросов по ORCH-проекту. После ORCH-10 `get_project_states(ORCH)["in_progress"]` = `e331bfb3`, не совпадает → pipeline не стартует → задача не создаётся → assert падает. Тесты отстали от per-project резолвинга, код прода правильный. - ТЗ: `tasks/orchestrator/DEV_TASK_ORCH39_FIX_WEBHOOK_TESTS.md` (точные UUID-карты ET/ORCH, точки мока, off-limits src/). ### Per-project state UUID (ЗАФИКСИРОВАТЬ — пригодятся) - **ET (enduro-trails):** in_progress=`b873d9eb-993c-48cd-97ac-99a9b1623967`, approved=`a519a341-dada-4a91-8910-7604f82b79c5`, rejected=`ba958f3c-5db5-461d-8f82-89425e413b97` - **ORCH (orchestrator):** in_progress=`e331bfb3-e17e-4699-ba48-4abb89c21b7b`, approved=`63f2c8fe-dcda-4ace-952f-dd88bd0118ff`, rejected=`4c769e90-bf80-4a52-b97a-e1c84904bfc3` ### Dev фейл на биллинге → перезапуск - Первый Dev упал: кончились кредиты дефолтной vibecode-модели. Перезапустила с `tokenator/claude-opus` явно. (Урок: при billing-фейле Dev — сразу перезапуск с tokenator-моделью.) ### PR #35 (ORCH-39) — проверено лично - `fix/ORCH-39-webhook-tests` → main, mergeable, НЕ смержен. +87/-9, 5 файлов. src/ НЕ тронут (только tests/ + pytest.ini + requirements.txt + ci.yml). - Мой прогон: `342 passed, 0 failed, 0 skipped` (было 336 passed/6 skipped/4 failed). - **БОНУС-находка Dev (глубже моей):** в `requirements.txt` не было `pytest-asyncio` → 6 async-тестов `test_orch10_states.py` МОЛЧА скипались. То есть async-пути ORCH-10 (per-project старт конвейера) вообще не проверялись, CI светил зелёным. Теперь pytest-asyncio добавлен, `asyncio_mode=auto`, `--strict-markers`, ci.yml `set -euo pipefail`. Те 6 тестов теперь PASSED. ### Порядок мержа (ждёт ОК Славы — НЕ мержу сама) 1. PR #35 (ORCH-39) → main (база честно зелёная) 2. PR #34 (ORCH-16) → main (фича единого коммента) 3. Ребилд прод-контейнера на 8500 → фича реально заработает ### Урок: CI-гейт был дырявым на самой важной логике - Две дыры в одном месте: (а) красные тесты пропускались, (б) async-тесты скипались из-за отсутствия pytest-asyncio. Оба светили зелёным CI. Для self-hosting честный гейт качества критичен — теперь закрыто в PR #35. --- ## 🏁 ФИНАЛ ДНЯ (05.06 вечер) — ORCH-16 в проде, ET-11 self-driving, ORCH-41 конфигурируемые модели ### ✅ ORCH-39 + ORCH-16 ВЫКАЧЕНЫ В ПРОД - PR #35 (ORCH-39, тесты+CI) смержен (`f375be24`, 342 passed). - PR #34 (ORCH-16, единый формат коммента) rebase на main → 402 passed → смержен (`8da571d`). - Прод ребилжен из main: `build_status_comment`×9, `frontmatter.py` в контейнере, `.env` цел (23 строки), очередь чистая. - **ORCH-39 → Done** (PATCH HTTP 200). ⚠️ Способ выполнения Plane-PATCH из контейнера: скрипт `/tmp/fix39.py` → `docker cp` в `orchestrator:/tmp/` → `docker exec orchestrator python3`. Вложенные `os.popen` внутри python-однострочника ломаются на экранировании (`printenv ... not found`) — НЕ делать, использовать heredoc+docker cp. ### ✅ ORCH-40 заведена (Backlog, id `cec9a5ef`) — фикс root-прав deployer - Контейнер orchestrator работает под uid=0(root) → агенты пишут root-файлы в смонтированный хост-репо → ломает git под slin. При ребилде чинила руками (`chown -R slin` + `git reset --hard` + clean). Корневой фикс отложен (трогает рантайм агентов, выше риск). ### ✅ АУДИТ БЭКЛОГА ORCH (обратный рассинхрон — НЕ найден, Done честные) Проверила материально 14 «Done»-задач на проде (файл/контейнер/таблица/эндпоинт, не по статусу): - ORCH-16 (build_status_comment ×9 + frontmatter.py в контейнере) ✅ - ORCH-1 (таблица `jobs`, `/queue` живой) ✅ - ORCH-2 (git_worktree.py, worktree enduro+orchestrator) ✅ - ORCH-6 (projects.py, plane_project_id ×10) ✅ - ORCH-31 (контейнер orchestrator-staging Up) ✅ - ORCH-29 (PRODUCT_VISION.md + .pptx) ✅ - ORCH-34/35/36 (deploy-hook.log 18.9KB) ✅ - ⚠️ **ORCH-36 нюанс (не баг статуса):** числится Done «исполняемый самодеплой», но при ребилде ORCH-16 катила прод РУКАМИ. deploy-hook.log есть → механизм есть, но автоматизм self-deploy орка-на-себя стоит перепроверить при случае. Не срочно. - **Итог:** 40 задач = 25 Backlog, 15 Done. Все Done подтверждены материально. ORCH-39 поправлена Backlog→Done. ### 🎉🎉 ET-11 — ПЕРВЫЙ ПОЛНЫЙ SELF-DRIVING ET-ЗАДАЧИ ЧЕРЕЗ ОРК НА ЖИВОМ ПРОДЕ - ET-11 = «Healthcheck enduro-trails-app падает: в контейнере нет curl (ложный unhealthy)» (id `e60715d4`, work_item ET-015). - **Диагноз (мой, лично):** healthcheck = `curl -f localhost:5556/api/health`, но в контейнере **нет ни curl, ни wget** (образ голый, только python) → healthcheck ВСЕГДА fail, FailingStreak **3762**. Само приложение здоровое (HTTP 200/7мс, живой трафик, RestartCount=0). Ложная тревога 31 час. - **Конвейер прошёл ВЕСЬ цикл сам:** analysis→architecture→development→review→testing→deploy→done. На гейте Approved **остановился и дождался Славы** (Слава заапрувил вручную в 15:17 — человек-в-петле сработал штатно, НЕ автопроскок). - **РЕАЛЬНО ПОЧИНИЛ БАГ НА ПРОДЕ:** PR #30 «use python urllib for container healthcheck» (заменили отсутствующий curl на python — ровно как я закладывала в ET-11). Смержен. PR #31 deploy (tag v0.0.7) смержен. - **Результат на живом проде:** контейнер `enduro-trails-app-1` теперь **`Up (healthy)`**, FailingStreak **0** (было 3762), HTTP 200/4мс. Прод НЕ упал даже без staging у ET. - **Боевая обкатка ORCH-16:** все агенты постили комменты единого формата (в логе `comment added to ET-015 author=deployer` ×2). Фича единого коммента работает в бою. - ⚠️ Риск был реальный: у ET НЕТ staging → deployer катил в живой прод 5556. Обошлось, но на будущее — для рискованных ET-задач держать стоп-флаг на deploy. ### ✅ ORCH-41 — КОНФИГУРИРУЕМЫЕ МОДЕЛИ + EFFORT per-agent + per-project (фундамент мультипровайдеров ORCH-13) **Задача Славы:** «модель выбирается в настройках, под каждого агента, с per-project override. Сделать сейчас.» **КОРЕНЬ почему агенты были на Opus 4.7 (разобрала лично, по боевым логам):** - `src/agents/launcher.py` AGENT_CONFIGS: architect/reviewer → `"model": "opus"` (алиас!), остальные — модели НЕТ (CLI-дефолт). - **Алиас `opus` в CLI 2.1.142 резолвится в `claude-opus-4-7`** (НЕ обновился на 4.8 авто). Подтверждено `runs/102.log`, `runs/103.log` → реально летит `claude-opus-4-7`. - **4.8 доступна** — проверила прямым вызовом: `claude-opus-4-8` / `opus-4-8` / `claude-opus-4-8-20250930` все `subtype: success`. CLI+аккаунт поддерживают, просто алиас не привязан. **Режимы работы CLI 2.1.142 (разведано, для будущего):** - `--effort low|medium|high|xhigh|max` — ⭐ ГЛАВНЫЙ рычаг «качество vs стоимость» (аналог reasoning-бюджета). Раз 4.7=4.8 по цене, effort важнее версии. - `--model` (алиас/полное имя), `--fallback-model` (автофолбэк при overloaded, работает с `--print`), `--permission-mode` (acceptEdits/auto/bypassPermissions/plan/dontAsk), `--bare` (без хуков/LSP/memory). **Реализация (Dev, PR #36 `feat/ORCH-41-agent-models`, проверено мной лично):** - `src/config.py` Settings: `agent_model_default` (дефолт `claude-opus-4-8`), `agent_model_` + `agent_effort_` (env `ORCH_AGENT_MODEL_*`, `ORCH_AGENT_EFFORT_*`). Паттерн как `plane_bot_*`. - `src/projects.py` ProjectConfig: поля `agent_models` + `agent_efforts` (dict, `field(default_factory=dict)` — frozen dataclass!), парсятся из projects_json (опционально). - `resolve_agent_model/effort` — приоритет: **per-project → env per-agent → default → CLI-дефолт**. - launcher.py: убран хардкод `"model":"opus"`, модель+effort резолвятся. - **Раскладка effort (согласовано Славой):** думающие (analyst/architect/developer/reviewer) → **high**, механические (tester/deployer) → **medium**. - **Дефолт модели = `claude-opus-4-8`** (Слава: «4.8 и 4.7 стоят одинаково, по дефолту 4.8»). - **Проверено лично на проде:** 423 passed (402+21), off-limits (gates/webhook/HMAC/queue) НЕ тронуты, резолвинг вживую: analyst/developer→opus-4-8/high, tester/deployer→opus-4-8/medium. Хардкод `opus` убран. - **PR #36 — Слава дал ОК на мерж (последнее сообщение), мерж+ребилд ещё НЕ выполнены на момент флаша.** После мержа: ребилд прода (учесть грабли root-прав ORCH-40), чтобы агенты реально поехали на 4.8/effort. Реальное переключение env прода — осознанно, с оглядкой на бюджет ORCH-38. ### НОВЫЕ ORCH-ЗАДАЧИ дня: - **ORCH-40** (id `cec9a5ef`) — фикс root-прав deployer, Backlog. - **ORCH-41** (id `17f9a73f`) — конфигурируемые модели per-agent, в работе → PR #36 готов, ждёт мержа. - **ET-11** (id `e60715d4`) — healthcheck curl, ✅ Done через конвейер (исправлено на проде, v0.0.7). ### КЛЮЧЕВЫЕ УРОКИ дня: - **launcher.py model был алиасом `opus`** → CLI резолвил в 4.7. Конфигурируемость (env+per-project) — правильное решение вместо хардкода версии. - **effort = главный рычаг цены/качества** при равной цене версий модели. - **Plane-PATCH из контейнера:** скрипт-файл + docker cp + docker exec, НЕ вложенные os.popen. - **Зеркало `/repos/orchestrator` отстаёт от Gitea** — источник истины при мерже = Gitea API, не локальный клон. - **PR #34 мержить squash через Gitea, не force-push rebase** (чище, mergeable=True). - **Человек-в-петле (гейт Approved) работает штатно** — ET-11 встала, дождалась ОК Славы, поехала. Не автопроскок. - Per-project state UUID (повтор для надёжности): ET in_progress `b873d9eb`, approved `a519a341`, rejected `ba958f3c`; ORCH in_progress `e331bfb3`, approved `63f2c8fe`, rejected `4c769e90`. ### Артефакты дня: - ТЗ ORCH-41: `tasks/orchestrator/DEV_TASK_ORCH41_AGENT_MODELS.md` - ТЗ ORCH-39: `tasks/orchestrator/DEV_TASK_ORCH39_FIX_WEBHOOK_TESTS.md` - Отчёт ORCH-39: `tasks/orchestrator/reports/dev-2026-06-05-orch39-webhook-tests.md` - main HEAD после PR #34: `8da571d`. PR #36 (ORCH-41) смержен `401bf66f` (squash), прод ребилжен. ### ✅ ORCH-41 ЗАКРЫТ + прод на 4.8 (финал) - PR #36 смержен (`401bf66f`), прод ребилжен из main (root-права починила превентивно — грабля ORCH-40, `.env` 23 строки цел). - РЕЗОЛВИНГ В ЖИВОМ КОНТЕЙНЕРЕ: analyst/architect/developer/reviewer→opus-4-8/high, tester/deployer→opus-4-8/medium. Алиас `opus`→4.7 устранён. - ORCH-41 → Done (Plane PATCH HTTP 200, минуя In Progress). prod /health=200, ET-задачи целы (17 в БД). ### ⚠️ ET-11 застряла в Testing → закрыта руками (Done) — ПРИЧИНА (не баг кода) - ET-11 (work_item ET-015) deploy завершился 15:43, БД орка стадия=`done`, фикс В ПРОДЕ (healthcheck healthy/streak 0, v0.0.7). НО Plane-статус застрял на **Testing**. - **Корень:** ET-11 ехала ДО мержа ORCH-16/39, на СТАРОМ `stage_engine`, где финальный переход `deploy→done` в Plane был дырявым. Фикс «set_issue_done всегда докручивает Plane Done» (`stage_engine.py:269`, через `set_issue_done` → `get_project_states(pid)["done"]`, ORCH-10 резолвинг) приехал в прод только при ребилде под ORCH-41 (16:45). - Проверено: резолвинг done-state для ET вживую = `381a2833` ✅, `_resolve_project_id("ET-015")`→ET-проект ✅. Код ТЕПЕРЬ правильный — будущие задачи дойдут до Done сами. Это РАЗОВЫЙ хвост старого кода, не системная дыра. - ET-11 закрыта вручную Testing→Done (PATCH `{"state":"381a2833"}` HTTP 200, минуя In Progress). - УРОК: при ребилде прода лог контейнера обнуляется (docker logs показывает только с нового StartedAt) — старую историю стадий смотреть в БД `tasks`, не в логе. ### 🏆 ORCH-7 ЗАКРЫТА (Done) — ГЛАВНАЯ ВЕХА SELF-HOSTING - Зонтичная мета-задача «орк пилит сам себя через конвейер» → Done (Backlog→Done напрямую, минуя In Progress; PATCH HTTP 200, итог-коммент 201). id `8a40d57a-1a4f-42dd-8e8c-48635bfb0bb9`. - **Доказано в бою:** ORCH-16 (первая самодоработка кода орка через весь конвейер) + ET-11 (self-driving для внешних проектов). Инфра: CI-гейт (ORCH-39), staging (ORCH-31..35), единый формат (ORCH-16), per-project статусы/модели (ORCH-10/41). - **Остаток в дочерних:** ORCH-36 (исполняемый самодеплой — сейчас прод ребилжу руками), ORCH-8 (самообучение). ### 🎯 ИТОГ ДНЯ 05.06 — 5 задач в Done: ORCH-7 (зонтик self-hosting), ORCH-16, ORCH-39, ORCH-41, ET-11. Орк официально умеет дорабатывать сам себя. ### ⚠️ КОНКУРЕНТНОСТЬ ОРКА — важный факт (разведано 05.06) - `max_concurrency=1` (дефолт, env `ORCH_MAX_CONCURRENCY` не задан, config.py:48). Считается **по JOBS (стадиям-агентам), НЕ по задачам**: `count_running_jobs()=COUNT(*) FROM jobs WHERE status=running`. - **СЛЕДСТВИЕ (критично):** когда задача висит на гейте Approved (ждёт ревью человека) — её job уже `done`, СЛОТ СВОБОДЕН → орк может стартовать СЛЕДУЮЩУЮ задачу в том же репо даже при concurrency=1. «Гуськом до деплоя» НЕ гарантировано. - **Обход Славы (решение):** запускать задачи в одном репо ПО ОДНОЙ вручную (A→done→B). Надёжно обходит гонку мержа без доработки. - worktree (ORCH-2) изолирует ветки на разработке, НО при параллели в одном репо — гонка мержа на финише (обе ветки от main@X, первый влил→main@Y, второй конфликт/старый код). Для РАЗНЫХ репо параллель безопасна. ### НОВЫЕ ORCH-ЗАДАЧИ в Backlog (05.06 вечер): - **ORCH-40** (id `cec9a5ef`) — фикс root-прав deployer. - **ORCH-41** (id `17f9a73f`) — СДЕЛАНО/Done (конфигурируемые модели). - **ORCH-42** (id `1564136e`) — Telegram live-tracker режим **bump** (карточка падает вниз при обновлении, флаг `ORCH_TRACKER_MODE`=edit|bump, deleteMessage+sendMessage тихо). Слава: «bump нравится, пусть орк делает» — self-hosting через конвейер. - **ORCH-43** (id `d770a7a2`) — безопасная параллель в одном репо: merge-gate + auto-rebase + re-test + **single-flight per repo** (не стартовать новую задачу пока предыдущая не дошла до done). Флаг `ORCH_SERIALIZE_PER_REPO`. --- ## 🔴 ИНЦИДЕНТ: ORCH-17 застряла на Analysis — ДВЕ причины (05.06 вечер ~17:00-17:35) Карточка ORCH-17 висела на Analysis ~30 мин. Аналитики стартовали (run 107/109/111) и **мгновенно умирали с пустым логом (0 байт)**, job 54 оставался `running`. Расследование выявило ДВА независимых корня: ### Причина №1: 🔐 Авторизация claude слетела (ГЛАВНАЯ) - При ребилде контейнера под ORCH-41 (16:45) пересоздание сломало claude-auth: - `/home/slin/.claude/.credentials.json` стал **owner=root** (контейнер под uid=0 портит владельца смонтированных файлов — снова грабля ORCH-40!) - `/root/.claude` в контейнере = ПУСТЫШКА (claude под `HOME=/root` создал болванку `.claude.json` 293 байта, настоящие creds лежат в `/home/slin/.claude*` но туда claude не смотрел) - Симптом: claude → `"Not logged in · Please run /login"`, is_error, 57ms, пустой stdout. - **ФИКС (двойной):** 1. `chown slin:slin /home/slin/.claude/.credentials.json` (вернула владельца — токен внутри был ВАЛИДНЫЙ, дело только в правах) 2. **ПОСТОЯННЫЙ:** в `docker-compose.yml` (prod+staging блоки) добавила монтирование `/home/slin/.claude → /root/.claude` и `.claude.json → /root/.claude.json` напрямую — переживёт рестарт (симлинки внутри контейнера НЕ переживают пересоздание). - ⚠️ **ВАЖНО launcher.py:** агенты запускаются с принудительным `HOME=/home/slin` (env в launcher, ~стр.290-320). НО claude всё равно умудрялся читать `/root` в части случаев → надёжнее смонтировать creds в ОБА места. ### Причина №2: ⚙️ `--effort` гасит вывод claude (РЕГРЕССИЯ ORCH-41) - Флаг `--effort <любое: low/medium/high/xhigh/max>` + `--print` в CLI **2.1.142** → **ПУСТОЙ stdout, even stderr молчит**, мгновенно. - Изолировано матрицей тестов: без effort работает ✅, с effort пусто ❌ (при любом значении). - **ФИКС (временный):** отключила effort в проде через `.env`: `ORCH_AGENT_EFFORT_DEFAULT=""` + пустые per-agent → резолвер вернёт пусто → флаг `--effort` НЕ добавляется в cmd. Модель `claude-opus-4-8` ОСТАЛАСЬ. - **TODO:** завести **ORCH-44** — корректная интеграция effort (возможно несовместим с `--output-format json`, или другой способ передачи). Сейчас effort отключён — не теряем фичу, просто не используем. ### Грабля диагностики (моя): - Промежуточные ручные тесты claude обрывались по **таймауту 40-50с** → выглядело как «зависание», сбивало диагноз. **Аналитик с system-prompt + task.md думает ~66с.** При таймауте 90с+ всё работает. ⚠️ НЕ ставить timeout <90с при ручной проверке claude-агента с полным контекстом. ### Команда launcher (рабочая, проверена E2E): - Полная команда launcher с `HOME=/home/slin`, `--print`, `--output-format json`, system-prompt + task.md, БЕЗ effort → работает (66с, 13 turns, is_error:false). ### ИТОГ инцидента: - ✅ ORCH-17 разблокирована: аналитик отработал (run 114, лог 3487 байт), job 54→done, BRD/ТЗ/AC написаны, Plane-комменты запощены, state→in_review (`c52e99b9`). **Ждёт Approved Славы.** - ✅ Авторизация claude: починена + защищена монтированием (постоянно). - ✅ effort: отключён в проде (конвейер работает на 4.8 без effort). - ✅ ORCH-44 заведена (id `d8ad65a7`, Backlog) — «Надёжность запуска агента», 3 дыры: (1) preflight слеп к auth, (2) --effort фикс, (3) пустой лог → failed. Приоритет высокий. - 📋 TODO: апрувнуть ORCH-17 (ждёт Approved Славы). ### 🔍 ДЫРА В PREFLIGHT (разведано 05.06 — почему проверка не поймала сбой) - `src/preflight.py` проверяет ТОЛЬКО: (a) `os.path.exists(CLAUDE_BIN)`, (b) `claude --version` (timeout 5s, без токенов). - ⚠️ **`claude --version` ОТВЕЧАЕТ ДАЖЕ БЕЗ ЛОГИНА** (версия — локальная инфа). Поэтому preflight=ok, а реальный запуск падает `Not logged in`. **Preflight слеп к авторизации и к битым флагам** (--effort). - Код прямым текстом: «🚫 deliberately do NOT do a prompt ping — would burn rate limit». Дизайн «дёшево, без токенов» → ценой слепоты к auth. - Фикс (ORCH-44): дешёвая проверка auth без токенов — читаемость+права `.credentials.json` + дата истечения OAuth (`claudeAiOauth.expiresAt`) внутри. ### КРИТИЧНЫЕ УРОКИ на будущее: 1. **Ребилд/пересоздание контейнера orchestrator ЛОМАЕТ claude-auth** (root-owned creds + `/root/.claude` пустышка). Теперь защищено монтированием в compose, НО проверять после каждого ребилда: `docker exec orchestrator bash -c 'cd /tmp && HOME=/home/slin /opt/claude-code/bin/claude.exe --print "ОК"'` (timeout 90с). 2. **claude бинарь:** реальный путь `/opt/claude-code/bin/claude.exe` (смонтирован ro, 232MB). `/usr/bin/claude` (env `ORCH_CLAUDE_BIN`) в контейнере НЕ существует — это хостовый симлинк, launcher хардкодит правильный путь. 3. **`--effort` НЕ использовать** с текущим CLI 2.1.142 + `--print`/`--output-format json` — гасит вывод. Ждёт ORCH-44. 4. **Пустой run-лог (0 байт) + job running + процесс мёртв** = claude упал на старте (auth ИЛИ битый флаг). Смотреть: сначала auth (`claude --print` вручную), потом флаги (effort). ### 🏁 ORCH-17 — застряла ВТОРОЙ раз на гейте check_ci_green (RACE, разведано 05.06 18:1x) - После починки auth задача доехала dev→PR #37 (434 теста), но застряла на `stage=development`, `agent_running=None`, очередь пустая. - **Корень — гонка CI:** гейт `check_ci_green` опросил Gitea-CI **ровно один раз** в 17:58:54 → `pending`. CI дописал `success` в **17:58:55** (промах на 1 сек). Лог: `Task 35: QG 'check_ci_green' not passed after developer: CI state: pending`. **Повторного опроса гейта НЕТ** → задача висит насмерть с зелёным CI. - Проверка CI: `combined state: success` (push #46 + PR #47 оба success). Готова, гейт промахнулся. - **Пинок вручную (безопасно, без ребилда/мержа):** `advance_stage(task_id=35, current_stage='development', repo='orchestrator', work_item_id='ORCH-017', branch='feature/ORCH-017-brd-plane-telegram', finished_agent='developer')` → `advanced=True development->review`, reviewer запущен (run 117, job 57). Поехала. - **ORCH-45 заведена** (id `ab21608b-31e2-44fe-a2a5-99701a3a1ec3`, Backlog, high) — `check_ci_green` должен ПОЛЛИТЬ CI с ретраем (pending→ждать N×15с, success→advance, failure→rollback, вечный pending→уведомить, не застревать молча). Родственна ORCH-44. ### 🛠️ Инфра-грабли прода (05.06) - **В контейнере `orchestrator` НЕТ `curl` и НЕТ `sqlite3`** — запросы к Gitea/Plane/БД делать через `python3 -c` (urllib + sqlite3-модуль). - **Таблица `tasks`: нет колонок `status`/`role`** — реальные: `id, plane_id, repo, branch, stage, agent_running, work_item_id, plane_issue_id, tracker_message_id, title, brd_review_started_at, brd_review_ended_at`. Статус задачи = `stage` + Plane-state; статус job — в таблице `jobs` (колонка `agent`, не `role`). - **Создание задачи Plane через скрипт:** лучший способ — написать .py локально → `base64 -w0` → `ssh "echo | base64 -d > /tmp/x.py"` → `docker cp` → `docker exec python3`. **base64 полностью обходит экранирование кириллицы/скобок** (heredoc с кириллицей и `(` падает с `Syntax error`). Локальный heredoc+scp НЕ работает — разные хосты. ### 🔁 ORCH-17 — петля dev↔review↔testing и разбор с Славой (05.06 вечер) - После пинка CI-гейта задача нарезала круги и упёрлась в **`max retries reached`** (MAX_DEVELOPER_RETRIES=3, stage_engine.py:56). Встала на development, ждёт человека. - **Два разных заворота в петле:** (a) tester FAIL `check_tests_passed: No machine-readable verdict/status`; (b) reviewer `REQUEST_CHANGES` — governance: дев протащил правку **shared quality-gate** `src/qg/checks.py` в косметическую задачу про ссылки (влияет на ВСЕ проекты общего прода, требует ADR по CLAUDE.md правило 2). - **Ключевой вывод про правку гейта:** дев починил РЕАЛЬНЫЙ баг ядра — `_parse_tests_verdict` читал только `verdict:/status:`, а промпт тестера велит писать `result: PASS`. Честный тестер → ложный FAIL → петля. Т.е. дев прав по сути, reviewer прав процедурно (shared-инфра без ADR). - **Почему дев не понял ревьюера (корень для ORCH-46):** орк при REQUEST_CHANGES шлёт деву только *"Fix findings in 12-review.md"* — без текста претензий (испорченный телефон); + противоречивые сигналы (tester "чини тесты" vs reviewer "не трогай gate"); + нет памяти между кругами (каждый dev = новый чистый агент). - **Решение Славы (вариант А):** из ORCH-17 убрать правку гейта (оставить только ссылки), фикс гейта — отдельной задачей следующей. - **Новые задачи:** ORCH-46 (id `beaab0e7-eb49-41b9-b5e5-8d7246a3d9f1`, Backlog, high) — передача замечаний деву; **ORCH-47** (id `89d9a4b3-f80c-4387-b6f1-97b1f6dc9113`, Backlog, high) — фикс `check_tests_passed` читать `result:` (с ADR, идёт следующей, готовый код-референс уже в ветке ORCH-017). - **Дотолкивание ORCH-17:** Dev-агент откатывает 2 файла к origin/main (`src/qg/checks.py`, `tests/test_qg.py`), остальное (ссылки/доки/ADR) остаётся → потом пинок гейта. ### 🪤 ORCH-17 — ДЕДЛОК после отката (05.06 поздний вечер) — НЕ повторять карусель - Откат дева (revert `d615747`, PR #37) убрал КОД гейта (`src/qg/checks.py`+`tests/test_qg.py` к origin/main), но **оставил 2 doc-строки** про ту правку → ревьюер снова `REQUEST_CHANGES`: - `docs/architecture/README.md:61` — описывает что гейт читает `result:` (код уже не читает) - `CHANGELOG.md:24` — запись про фикс гейта под ORCH-017 + ссылка на удалённые тесты - Обе строки принадлежат ORCH-47, в ORCH-017 их быть не должно. **Урок: при откате кода чистить И доки/CHANGELOG, иначе рассинхрон код↔доки → ревьюер заворачивает.** - **ОБЪЕКТИВНЫЙ ДЕДЛОК (главное):** тест-отчёт ORCH-017 написан с `result: PASS` (под новый контракт). Поэтому: - С фиксом гейта в ветке → reviewer заворачивает (governance/ADR). ❌ - Без фикса гейта (после отката) → `check_tests_passed` не видит `result:` → ложный «Tests FAILED» → откат. ❌ - **Куда ни кинь — клин.** ORCH-17 физически НЕ может пройти конвейер автономно, пока не приедет ORCH-47 (фикс `result:`). - **ORCH-17 застревала 4-5 раз, каждый раз пинала руками** — симптом: косметика (2 ссылки) ради полувечера возни, потому что орк сам не может (дыры ORCH-44/45/46/47). - **Развилка, предложена Славе (ждёт решения):** - 🅱️ Ручной мерж PR #37 (код ссылок готов, 434 теста зелёные, ревьюер: «технически корректно», претензии только процедурные) → ссылки уезжают в ядро, работают во всех проектах. Требует ОК Славы на мерж. - 🅲️ Сначала прогнать ORCH-47 (фикс гейта+ADR), потом ORCH-17 проедет сама — ещё один полный цикл ради готовых ссылок. - **Стрим рекомендует 🅱️** — хватит доказывать конвейеру то, что готово. - **Урок про мою роль:** когда раз за разом пинаю гейты и чищу за девом вручную — это сигнал «орк не тянет автономно», честнее предложить ручной мерж/эскалацию, чем гонять карусель кругов. ### ✅ ORCH-17 ЗАКРЫТА вручную + уроки в репо (05.06 поздний вечер) - **Ручной merge PR #37** (merge-commit `26c6f267`, merged=True, closed). Решение Славы «мержи» — выход из объективного дедлока (см. выше). Код ссылок (approve-ping links) уехал в ядро → работает во всех проектах (орк один на всех). - В смерженной ветке: `src/notifications.py`, `src/config.py`, тесты ссылок, ADR-001 на approve-links, полный пакет work-item доков. **БЕЗ** правки shared-гейта (она целиком в ORCH-47). - Прибрано: Plane ORCH-017 → **Done**; БД орка task 35 → `stage=done`, очередь пустая. - **Уроки сохранены в репо:** `docs/history/LESSONS_ORCH-017.md` через **PR #38 → смержен в main**. Папка `docs/history/` — устоявшийся паттерн постмортемов (LESSONS_*/BUGFIXES_*/INCIDENT_*). Внутри: хронология 5 застреваний, 4 корневые дыры (P1→ORCH-45, P2→ORCH-46, P3→ORCH-47, P4→ORCH-44), главный урок про дедлок shared-инфры, урок про откат (код+доки+changelog вместе), урок про роль оператора (ручной merge вместо карусели). ### 🔑 Gitea API грабля (05.06) - **create-PR** эндпоинт Gitea требует заголовок `Authorization: token `, а НЕ просто токен/другую форму → иначе 401. (merge-PR прошёл с другой формой, но на create Gitea строже.) Токен: `ORCH_GITEA_TOKEN` в env контейнера orchestrator. ### 🅲 План разравнивания дороги перед ORCH-47 (05.06, решение Славы «С») - Слава выбрал вариант 🅲: сначала починить ORCH-45 (CI-гонка) Dev-агентом напрямую (мелкая гигиена конвейера, НЕ через сам конвейер), потом ORCH-47 гнать конвейером гладко. - **Почему не конвейером:** ORCH-44/45/46 ещё не в проде → ORCH-47 наступит на те же грабли (CI-гонка, испорченный телефон). И ORCH-47 меняет сам гейт `check_tests_passed` — «чинить весы стоя на них» → нужен ADR + ручной контроль на мерже. ### ✅ ORCH-45 готова (CI-poll-retry) — ждёт мержа (05.06) - **PR #39**, ветка `feature/ORCH-045-ci-poll-retry`, открыт, НЕ мержен (ждёт ОК Славы — shared-гейт). - Dev-агент (`tokenator/claude-opus-4-8`) сделал: `check_ci_green` из single-shot → **поллинг с ретраем** (12 попыток × 10с): терминальные `success`/`failure` сразу, `pending` → ждёт, истёк лимит → явный `False` с причиной `"CI still pending after Ns"` (не виснет молча). - Параметры вынесены в `config.py` как env: `ORCH_CI_POLL_MAX_ATTEMPTS` / `ORCH_CI_POLL_INTERVAL_S`. - Файлы: `src/qg/checks.py`, `src/config.py`, тесты, `docs/architecture/decisions/ADR-0004*`, README-индекс, CHANGELOG. - **Проверила лично:** `check_tests_passed` НЕ тронут (grep пустой, ORCH-47 не задет); тесты прогнала своими руками — **62 passed** (5 новых на гонку); набор файлов ровно разрешённый. - ⚠️ **Сноска:** при совместном прогоне с `test_webhooks.py` 4 теста падают — **пре-существующая** проблема изоляции settings (воспроизводится на чистом main без наших правок). К ORCH-45 не относится → потенциальная будущая задача (изоляция settings в тестах). - **Следующий шаг:** ждёт «мержи» Славы на #39 → закрыть ORCH-45 в Plane → запустить ORCH-47 конвейером. ### ✅ ORCH-45 ЗАДЕПЛОЕНА в прод (05.06 ~20:30) — ребилд состоялся - PR #39 **смержен** (merge-commit `982698c4`), ORCH-45 → **Done** в Plane. - **Деплой потребовал ребилда образа** (не просто рестарт): `/app` запечён в образ (`build: .`, COPY src/), не volume на repo. Деплой-хук с `--no-build` НЕ довозит код — обязательно `docker compose build orchestrator`. - **prod орк = порт 8500** (status ok), staging = 8501, profile prod = пустой (стартует обычным `up -d`), `network_mode: host`. Деплой-хук по дефолту целит в STAGING (by design) — для прода нужны env TARGET_SERVICE=orchestrator TARGET_PORT=8500. - Новый поллящий гейт активен в `/app` (маркеры ci_poll = 4). Health 200. - **claude-auth ПЕРЕЖИЛ ребилд** (боевая проверка `HOME=/home/slin claude.exe --print` -> ОК; креды owner=slin 1000:1000). Инцидент НЕ повторился. ### ГРАБЛЯ: хост-репо рассинхронизирован с git (агенты пишут под root) — 05.06 - Хост-репо был на ветке `feature/ORCH-045-...`, не на main -> `git pull origin main` в хуке не подтягивал main. - Рабочая копия ЗАСЕЯНА untracked+modified файлами агентов **под uid=0 (root-owned)** -> `git pull --ff-only` падал Permission denied / would be overwritten, `rm` под slin не мог снести. - **Решение (отработано):** (1) `sudo chown -R slin:slin /home/slin/repos/orchestrator`; (2) проверить modified=MATCH-MAIN и untracked=IN-MAIN (дубликаты, ничего ценного); (3) `git reset --hard origin/main` + `git clean -fd -e '*.bak*' -e '.deploy-prev-image-prod'`; (4) build + up -d + health + проверка claude-auth. - **Урок:** перед деплоем орка ВСЕГДА сверять состояние хост-репо (ветка + git status). Хук сам это НЕ разруливает. ### Бэклог high после 05.06 (порядок): - **ORCH-45** — CI-poll-retry → PR #39 ГОТОВ, ждёт мержа - **ORCH-47** — гейт `check_tests_passed` читать `result:` (с ADR) → следующая, конвейером после ровной дороги - **ORCH-46** — испорченный телефон (передача замечаний деву: текст findings + склейка tester/reviewer + память между кругами) - **ORCH-44** — надёжность запуска агента (preflight слеп к auth, --effort гасит вывод, пустой лог→failed) ### ✅ ORCH-47 ЗАКРЫТА (фикс тестер-гейта `result:`) — 05.06 ~21:35 - Прошёл конвейером: analyst→arch→dev→review→testing. **Уловка-22:** ORCH-47 чинит гейт `check_tests_passed` (читать `result:`), но в проде крутился старый гейт → не понимал `result: PASS` от тестера → 3 круга dev↔review↔tester → Blocked. Тот же дедлок-класс, что у ORCH-17. - **Выход (🅱️):** проверила diff+тесты сама (68 passed, +6 на result:), reviewer APPROVED v3, CI green → ручной merge **PR #40** (`5d04de9e`) → ребилд прода (chown+reset+build+up+health+auth-check, claude-auth пережил) → умный гейт активен. - После деплоя пнула task 36 `advance_stage(dev,finished=developer)` → CI-гейт green → review→testing **прошёл check_tests_passed (принял `result: PASS`!)** → deploy-staging. - **Встал на staging:** `check_staging_status: FAILED`. Деплоер честно: 9/10 PASS, **B6 Registry isolation FAIL** (sandbox=NO, prod-ET/ORCH=YES BAD — staging видит боевые проекты, нарушает «staging только sandbox»). Деплоер НЕ стал натягивать зелёнку (вне мандата) → откат на development by design. К самому фиксу гейта отношения НЕ имеет — E2E против sandbox прошёл. - **Решение Славы:** B6 — отдельной задачей, ORCH-47 закрыть (код в проде, работает). - ✅ ORCH-047 → **Done** в Plane; task 36 → done в БД. Gitea merge-грабля подтвердилась снова (нужен `Authorization: token <…>`; heredoc через ssh+docker глотает вывод → скрипт+base64+docker cp). - **🆕 ORCH-048 заведена** (id `7fb4f0f0-576c-46e7-b7ec-84909c99fffe`, Backlog): B6 staging registry isolation — реестр staging должен видеть только sandbox; гипотеза — `src.projects.known_plane_project_ids()` читает host-env. Не блокер фикса гейта. ### Прод-гейты сейчас (после деплоев 05.06): - ✅ `check_ci_green` — поллинг с ретраем (ORCH-45, в проде) - ✅ `check_tests_passed` — читает `result:`/`verdict:`/`status:` (ORCH-47, в проде) - Бэклог high: ORCH-48 (staging isolation), ORCH-46 (испорченный телефон), ORCH-44 (надёжность запуска агента)