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