Files
wiki/memory/2026-06-05.md
2026-06-06 00:40:01 +03:00

833 lines
121 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`.
---
## Этап 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/<id>/members/` с телом `{"member": <user_id>, "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/<wi>/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 <repo>")`, файл `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/<role>.md`) + task. Канон держится на 3 слоях.
### 3-слойный канон (согласован):
1. **Структура docs/**: README, ARCHITECTURE, PIPELINE, PRODUCT_VISION, adr/ (1 решение=1 файл adr-NNNN-slug.md), operations/, work-items/<id>/, 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/<id>/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":"<uuid>"}` → 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/<id>/members/` поле `{"member":<id>,"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>` + `agent_effort_<agent>` (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 <b64> | 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 <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 (надёжность запуска агента)