diff --git a/memory/2026-06-05.md b/memory/2026-06-05.md new file mode 100644 index 0000000..96aa1d3 --- /dev/null +++ b/memory/2026-06-05.md @@ -0,0 +1,71 @@ +# 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 законно добавил и его сброс. + +### Развилка по мержу (ждёт кивка Славы на момент флаша) +- **#27** содержит ВСЁ (workflow + все фиксы тестов), зелёный. +- **#26** (ветка `ci/add-gitea-workflow`, только workflow) — поглощён #27. +- **План:** мержить #27 в main, #26 закрыть без мержа как поглощённый. Мерж PR — роль Стрим (ревьюер). + +## Staging-среда для orchestrator (ORCH-30..35) — дизайн оформлен, задачи в Backlog + +### Решения (гибрид C) +- Агенты на staging: ПО ДЕФОЛТУ заглушки (быстро/дёшево/детерминированно — гейт проверяет работоспособность ОРКа, не качество LLM) + режим `full-real` по флагу (настоящий Claude CLI через `claude-cli-proxy`). +- Plane/Gitea на staging — настоящие, но в песочнице (ORCH-SANDBOX проект + orchestrator-sandbox репо). +- `DEPLOY_REQUIRE_MANUAL_APPROVE=true` на старте — хук тормозит после зелёного staging, ждёт «go» Славы. +- **Деплоем рулит ВНЕШНИЙ хост-хук, не сам контейнер орка** (орк не может убить свой процесс на середине деплоя; rollback через PREV_IMG, образец `enduro-deploy-hook.sh`). +- Задачи только в Backlog — конвейер стартует ТОЛЬКО при переходе В In Progress (Feature 1). Backlog безопасен. + +### Задачи (все Backlog, project ORCH id 8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a) +- **ORCH-31** id=5a68a13c-3f3b-4d9e-91f7-24b0794bed06 — staging-инфра: контейнер `orchestrator-staging` (порт 8501), изолированная БД через `ORCH_DB_PATH`/volume `./data/staging`, профиль compose `staging` +- **ORCH-32** id=3dadcf0d-f1b6-4302-8075-8d428ace01f6 — песочница: Plane `ORCH-SANDBOX` + Gitea `orchestrator-sandbox`, реестр через env `ORCH_PROJECTS_JSON` (код не трогать) +- **ORCH-33** id=a11a7c0f-a78a-4309-9aa5-1c43d4355d0f — тест-сьют (smoke + доступы + e2e), режим full-real +- **ORCH-34** id=47fe9e75-d7ff-4ecb-bb99-67af9b23ab67 — хост-деплой-хук `orchestrator-deploy-hook.sh` (build candidate→staging-гейт→promote→health 10×6с→auto-rollback), пересекается с ORCH-21 +- **ORCH-35** id=4ead9be7-e1bf-4a28-8c76-88bda1c1fc2c — стадия `deploy-staging` перед `deploy-prod` + +### Разведка инфры (факты для точных ТЗ) +- compose: один service `orchestrator`, `network_mode: host`, порт 8500 в команде uvicorn (`uvicorn src.main:app --host 0.0.0.0 --port 8500`). Staging → просто другой порт 8501 + профиль `staging`. +- `ORCH_DB_PATH` УЖЕ параметризован (config.py:43 дефолт `/app/data/orchestrator.db`) → изоляция БД через него + отдельный volume `./data/staging`. +- Реестр проектов через env `ORCH_PROJECTS_JSON` (JSON-массив) → sandbox добавляется в `.env.staging`, код менять не надо. +- В Plane sandbox-проекта ещё НЕТ (есть ag_proj, First, ET, ORCH). В Gitea sandbox-репо ещё НЕТ (enduro-trails, openclaw-vault, orchestrator, wiki). Заведу сама через API при выкате Этапа 2. +- ТЗ готово: `tasks/orchestrator/DEV_TASK_ORCH31_STAGING_INFRA.md`. Запускать Dev на ORCH-31 ТОЛЬКО когда репо свободно (не толкать двух Dev на один git одновременно). + +## Грабли/правила (подтверждены этой сессией) +- Файлы памяти: durable → ТОЛЬКО `memory/YYYY-MM-DD.md` (append). Сегодня `2026-06-05.md`. +- Dev: код/тесты/конфиги → ТОЛЬКО в Gitea-репо orchestrator через PR. Push в main запрещён (pre-receive hook). Dev НЕ мержит — мержит ревьюер (Стрим/Слава). +- Инфра вне репо (`.env.staging` реальный, Plane/Gitea sandbox-сущности, хост-деплой-хук, поднятие контейнера) — делаю я через installer/API, НЕ Dev через PR. В репо только `.env.staging.example`. +- ⚠️ Dev: НЕ регистрировать раннеров, НЕ nohup. Раннер `mva154-runner-orch` уже есть. +- ⚠️ Off-limits без согласования: HMAC-механизм, 9 HMAC/401 тестов, src/config.py settings, check_reviewer_verdict, check_deploy_status, merge-gate gitea.py, PLANE_STATES, set_issue_done, launcher, queue, stages.py mapping, _parse_tests_verdict, check_tests_local (только DEPRECATED, не удалять). +- ⚠️ Грабля push: после push `git log origin/main..origin/` ДОЛЖЕН показать коммит ДО отчёта «PR готов». +- ⚠️ Plane API: дёргать через base64-stdin+docker cp в контейнер orchestrator. URL `http://localhost:8091` БЕЗ /api/v1 (суффикс добавляет код!), заголовок `X-API-Key`, токен `ORCH_PLANE_API_TOKEN`. Без /api/v1 Plane вернёт HTML(200) вместо JSON. +- Прогон тестов в чистом окружении (как CI): `docker run --rm -v /home/slin/repos/orchestrator:/code:ro -w /code -e PYTHONPATH=/code --entrypoint python3 $(docker inspect orchestrator --format '{{.Config.Image}}') -m pytest tests/ -q` +- Эндпоинт Actions: `GET /api/v1/repos/admin/orchestrator/actions/tasks`, токен `docker exec orchestrator printenv ORCH_GITEA_TOKEN`. +- Сервер: `slin@82.22.50.71` (sshpass, pw motoZ@yaz2010), репо `/home/slin/repos/orchestrator`, контейнер `orchestrator` порт 8500, Gitea https://git.mva154.duckdns.org. +- Модель Dev: `tokenator/claude-sonnet-4-6` (vibecode кредиты кончились; альт tokenator/claude-opus-4-8). +- ElevenLabs TTS квота кончилась → отвечать ТЕКСТОМ. + +## Уборка раннеров (TODO, ждёт ОК Славы) +3 процесса act-runner: systemd `act-runner.service` (рабочий, mva154-runner), PID 3828601 (старый mva154-runner с 19.05), PID 4091018 (mva154-runner-orch через nohup — НЕ переживёт reboot). План: systemd-unit вместо nohup, прибить лишние. Принести Славе на ОК. + +## Следующие шаги +1. [ждёт кивка] Мерж PR #27 в main, закрыть #26 → CI-гейт (пункт self-hosting) закрыт. +2. Запустить Dev на ORCH-31 (staging-инфра) когда репо свободно. +3. Этап 2 (ORCH-32): завести ORCH-SANDBOX в Plane + orchestrator-sandbox в Gitea при выкате. +4. Уборка раннеров (план Славе на ОК).