# 2026-06-02 — Daily Log ## ET-009: GPS Sources (EnduroRussia + Wikiloc) — Pipeline Completed 🎉 ### Pipeline stages (all passed): 1. ✅ **analysis** — analyst (Sonnet), produced BRD, TRZ, acceptance criteria, test plans 2. ✅ **architecture** — architect v2 (Opus 4.7), ADRs + infrastructure requirements 3. ✅ **development** — developer (Opus 4.7 1M), 19 files, 1287 lines. Commit `3577ff3` 4. ✅ **review** — reviewer (Opus), found P1 bugs F-01, F-02 5. ✅ **development fix** — developer (Sonnet), commit `fc03746`: 159 lines in `gps_tracks.js` 6. ✅ **review round 2** — reviewer (Opus), APPROVED, only P3 minors remain 7. ✅ **testing** — tester (Sonnet), 25/25 pytest + 24/24 js tests PASS 8. ✅ **deploy** — deployer (Sonnet), PR #16 merged, image rebuilt, collector running ### Key results: - **EnduroRussia parser**: `enduro_russia.py` — scraping + GPX parsing - **Wikiloc parser**: `wikiloc.py` — Wikiloc GPX integration - **Dynamic source filters (F-01)**: `_buildGpsFiltersUI` pulls source_id from `/api/gps-tracks/health.tracks_by_source` - **Attribution fix (F-02)**: attribution set at `addSource` time via `_ensureGpsSources(map, attribution)`, not by mutating `src.attribution` (MapLibre AttributionControl issue) - **Collector running**: 305 EnduroRussia tracks, fetching one per 5s, 34+ already in DB - **Commits**: `eaa6b4c` (analyst), `4be7fbf` (architect), `3577ff3` (dev), `fc03746` (dev fix) - **PR**: #16 merged → main at `b5ba7b2` ### Known issues: - **Nginx 502** on external URL (port 5556 routing) — not ET-009 specific, needs nginx config fix - **gps_sources.yaml** — ADR files inside Docker image (not volume), old image had `proposed`; fixed by rebuilding image --- ## Orchestrator Issues Discovered ### Critical bug: Launcher Popen broken inside container - All Claude processes (claude.exe) become zombies when launched via orchestrator's Python subprocess - Root cause: `docker` binary not available inside container, Popen flags wrong - **Workaround established**: base64-encode Python launch script → ssh to host → decode → docker cp → docker exec python3 - This pattern avoids shell quoting hell ### Other orchestrator bugs: - `.task-arch.md`, `.task-dev.md`, `.task-review.md` not regenerated per-stage (carry over from previous task) - Workaround: manually rewrite these files before each stage launch - No CI configured in Gitea → every commit triggers false "CI failed" webhook alert - Tokenator API: all 8 models down for maintenance (June 1, still down June 2 morning) ### Agent launch manual pattern: ```bash # 1. Base64-encode the Python launch script cat launch_script.py | base64 -w0 # 2. SSH to host, decode, cp to container, exec ssh slin@82.22.50.71 " echo 'BASE64_STRING' | base64 -d > /tmp/launch.py docker cp /tmp/launch.py orchestrator:/tmp/launch.py docker exec orchestrator python3 /tmp/launch.py " ``` --- ## Models Configuration Changes - **DeepSeek V4 models added** to openclaw.json: - `openrouter/deepseek/deepseek-v4` - `openrouter/deepseek/deepseek-v4-pro` - `openrouter/deepseek/deepseek-v4-flash` - Current model for main agent: `openrouter/deepseek/deepseek-v4-pro` --- ## User Preferences (re-confirmed during ET-009) - **User wants visibility at each pipeline stage** — frustrated by silent automated advances - **User wants to approve before advancing**: analyst → `:approved:` → architect → developer → reviewer → tester → deployer - Only analyst requires manual `:approved:`; architect, reviewer, tester should auto-advance but notify - Deployer should ask before deploying --- ## Глубокий аудит оркестратора (мультиагенты) — 2026-06-02 ### Проведено - **Аудит кода:** `tasks/multi-agent/AUDIT_2026-06-02.md` — 3 BLOCKER, 5 SERIOUS, 7 MEDIUM, 5 LOW - **Аудит документации:** `tasks/multi-agent/DOCS_AUDIT_2026-06-02.md` - **ТЗ для Dev:** `tasks/multi-agent/DEV_TASK_ORCHESTRATOR_FIXES.md` (9 задач) ### Корневые баги (BLOCKER) - **B-1:** нет `docker` бинарника в контейнере orchestrator → `_write_task_file` через `docker run` падает молча → агент читает старый `.task-*.md` - **B-2:** `Popen` + PIPE + daemon-поток → claude-зомби, `exit_code` теряется (в БД `exit=None` для всех ET-009) - **B-3:** `.task-*.md` тащатся между задачами + коммитятся в git ### Ключевая находка по докам - **P1 zombie из `LESSONS_ET006.md` (22 мая) = мой B-2.** Баг известен 11 дней, не починен → повторился на ET-008/009 - Системная проблема: lessons пишутся, но не конвертируются в задачи - Расхождение код↔док: README говорит review QG=`check_review_approved`, код использует `check_reviewer_verdict` ### Dev-агент запущен - Model: **tokenator/claude-opus-4-8** (modelApplied: true) - taskName: `orch_fixes`, runId: 2f18ca88 - Deploy-хук `/home/slin/bin/enduro-deploy-hook.sh` СУЩЕСТВУЕТ и корректен - В orchestrator были незакоммиченные правки (M launcher/config/notifications/plane_sync) — Dev разберёт в Task 1 ## ET-009 Artifacts - **Plane issue**: `64e98247-509f-4c30-9955-a5531ab7d1ee` (sequence #5) - **Plane workspace**: `ag_proj`, project `7a79f0a9-5278-49cd-9007-9a338f238f9c` - **Orchestrator DB**: task_id=16 - **Repo**: `/home/slin/repos/enduro-trails` on mva154 - **Docs**: `docs/work-items/ET-009/` — 00 through 14 (BRD, TRZ, acceptance, tests, ADRs, infra, data, risks, review, test report, deploy) - **Docker**: container `enduro-trails`, image rebuilt with new ADR files, collector running # 2026-06-02 — Daily Log ## ET-009: GPS Sources (EnduroRussia + Wikiloc) — Pipeline Completed 🎉 ### Pipeline stages (all passed): 1. ✅ **analysis** — analyst (Sonnet), produced BRD, TRZ, acceptance criteria, test plans 2. ✅ **architecture** — architect v2 (Opus 4.7), ADRs + infrastructure requirements 3. ✅ **development** — developer (Opus 4.7 1M), 19 files, 1287 lines. Commit `3577ff3` 4. ✅ **review** — reviewer (Opus), found P1 bugs F-01, F-02 5. ✅ **development fix** — developer (Sonnet), commit `fc03746`: 159 lines in `gps_tracks.js` 6. ✅ **review round 2** — reviewer (Opus), APPROVED, only P3 minors remain 7. ✅ **testing** — tester (Sonnet), 25/25 pytest + 24/24 js tests PASS 8. ✅ **deploy** — deployer (Sonnet), PR #16 merged, image rebuilt, collector running ### Key results: - **EnduroRussia parser**: `enduro_russia.py` — scraping + GPX parsing - **Wikiloc parser**: `wikiloc.py` — Wikiloc GPX integration - **Dynamic source filters (F-01)**: `_buildGpsFiltersUI` pulls source_id from `/api/gps-tracks/health.tracks_by_source` - **Attribution fix (F-02)**: attribution set at `addSource` time via `_ensureGpsSources(map, attribution)`, not by mutating `src.attribution` (MapLibre AttributionControl issue) - **Collector running**: 305 EnduroRussia tracks, fetching one per 5s, 34+ already in DB - **Commits**: `eaa6b4c` (analyst), `4be7fbf` (architect), `3577ff3` (dev), `fc03746` (dev fix) - **PR**: #16 merged → main at `b5ba7b2` ### Known issues: - **Nginx 502** on external URL (port 5556 routing) — not ET-009 specific, needs nginx config fix - **gps_sources.yaml** — ADR files inside Docker image (not volume), old image had `proposed`; fixed by rebuilding image --- ## Orchestrator Issues Discovered ### Critical bug: Launcher Popen broken inside container - All Claude processes (claude.exe) become zombies when launched via orchestrator's Python subprocess - Root cause: `docker` binary not available inside container, Popen flags wrong - **Workaround established**: base64-encode Python launch script → ssh to host → decode → docker cp → docker exec python3 - This pattern avoids shell quoting hell ### Other orchestrator bugs: - `.task-arch.md`, `.task-dev.md`, `.task-review.md` not regenerated per-stage (carry over from previous task) - Workaround: manually rewrite these files before each stage launch - No CI configured in Gitea → every commit triggers false "CI failed" webhook alert - Tokenator API: all 8 models down for maintenance (June 1, still down June 2 morning) ### Agent launch manual pattern: ```bash # 1. Base64-encode the Python launch script cat launch_script.py | base64 -w0 # 2. SSH to host, decode, cp to container, exec ssh slin@82.22.50.71 " echo 'BASE64_STRING' | base64 -d > /tmp/launch.py docker cp /tmp/launch.py orchestrator:/tmp/launch.py docker exec orchestrator python3 /tmp/launch.py " ``` --- ## Models Configuration Changes - **DeepSeek V4 models added** to openclaw.json: - `openrouter/deepseek/deepseek-v4` - `openrouter/deepseek/deepseek-v4-pro` - `openrouter/deepseek/deepseek-v4-flash` - Current model for main agent: `openrouter/deepseek/deepseek-v4-pro` --- ## User Preferences (re-confirmed during ET-009) - **User wants visibility at each pipeline stage** — frustrated by silent automated advances - **User wants to approve before advancing**: analyst → `:approved:` → architect → developer → reviewer → tester → deployer - Only analyst requires manual `:approved:`; architect, reviewer, tester should auto-advance but notify - Deployer should ask before deploying --- ## Глубокий аудит оркестратора (мультиагенты) — 2026-06-02 ### Проведено - **Аудит кода:** `tasks/multi-agent/AUDIT_2026-06-02.md` — 3 BLOCKER, 5 SERIOUS, 7 MEDIUM, 5 LOW - **Аудит документации:** `tasks/multi-agent/DOCS_AUDIT_2026-06-02.md` - **ТЗ для Dev:** `tasks/multi-agent/DEV_TASK_ORCHESTRATOR_FIXES.md` (9 задач) ### Корневые баги (BLOCKER) - **B-1:** нет `docker` бинарника в контейнере orchestrator → `_write_task_file` через `docker run` падает молча → агент читает старый `.task-*.md` - **B-2:** `Popen` + PIPE + daemon-поток → claude-зомби, `exit_code` теряется (в БД `exit=None` для всех ET-009) - **B-3:** `.task-*.md` тащатся между задачами + коммитятся в git ### Ключевая находка по докам - **P1 zombie из `LESSONS_ET006.md` (22 мая) = мой B-2.** Баг известен 11 дней, не починен → повторился на ET-008/009 - Системная проблема: lessons пишутся, но не конвертируются в задачи - Расхождение код↔док: README говорит review QG=`check_review_approved`, код использует `check_reviewer_verdict` ### Dev-агент — РЕЗУЛЬТАТ (ПРИНЯТО ✅) - Model: **tokenator/claude-opus-4-8** (modelApplied: true), taskName `orch_fixes`, runId 2f18ca88 - **Починено:** B-1, B-2, B-3, S-5, S-1, M-1 + 2 доп-фикса найденных в бою: - **git safe.directory** в Dockerfile (без него auto-commit падал на «dubious ownership») - **init:true** в compose (tini как PID 1, добивает grandchild-зомби от claude/node) - **11 коммитов** в main orchestrator (Conventional Commits), запушены - **Тесты:** 26 passed (launcher + qg) — гонял в контейнере (хостовый .venv сломан, symlinks на py3.10) - **Автономный прогон:** через `launcher.launch()`, 0 зомби, auto commit+push сработал - **Доки обновлены:** ARCHITECTURE, README (QG-таблица), `BUGFIXES_2026-06-02.md` ### Моя независимая проверка (на сервере, не на слово) - ✅ health `{"status":"ok"}`, 0 defunct процессов - ✅ B-1: `_write_task_file` через `open()` + raise (код подтверждён) - ✅ S-5: verdict читается только из YAML frontmatter - ✅ 26 тестов зелёные - ✅ init:true в compose, PR #19 open+mergeable ### ⚠️ ТРЕБУЕТ ДЕЙСТВИЯ - **PR #19** (enduro-trails: `.gitignore` + `reviewer.md`) — ветка main защищена, нужен merge человеком. Спросила Славу — ждёт ответа. ### Честные расхождения (Dev не скрыл) - Хостовый `.venv` сломан (symlinks py3.10) — тесты в контейнере - `test_webhooks.py` — 9 pre-existing падений (401/signature), были ДО правок, вне scope - **Вне scope (отдельные задачи на потом):** S-2/S-3 (rollback в shared-репо), S-4 (git worktree per task), M-3 (дубль `_try_advance_stage`), **F-2b (очередь задач вместо daemon-потоков — главный целевой рефактор)**, M-7 (идемпотентность webhook) ### Открытый вопрос Славе - Смержить PR #19? - Завести в Plane оставшиеся задачи (worktree, очередь задач)? ## ET-009 Artifacts - **Plane issue**: `64e98247-509f-4c30-9955-a5531ab7d1ee` (sequence #5) - **Plane workspace**: `ag_proj`, project `7a79f0a9-5278-49cd-9007-9a338f238f9c` - **Orchestrator DB**: task_id=16 - **Repo**: `/home/slin/repos/enduro-trails` on mva154 - **Docs**: `docs/work-items/ET-009/` — 00 through 14 (BRD, TRZ, acceptance, tests, ADRs, infra, data, risks, review, test report, deploy) - **Docker**: container `enduro-trails`, image rebuilt with new ADR files, collector running --- ## ORCH-2 [S-4] git worktree — ПРИНЯТО ✅ (2026-06-02) ### Dev-агент (Opus 4.8 Tokenator) - taskName: `orch2_worktree`, TЗ: `tasks/orchestrator/DEV_TASK_ORCH2_WORKTREE.md` - НОВЫЙ файл: `src/git_worktree.py` (5 функций: `_safe`, `get_worktree_path`, `ensure_worktree`, `remove_worktree`, `cleanup_orphaned`) - Изменены: `src/agents/launcher.py` (worktree-пути), `src/qg/checks.py` (чтение артефактов + тесты из worktree), `src/webhooks/gitea.py` (git-операция), `src/config.py` (+worktrees_dir) - Тесты: **37 passed** (9 fail = pre-existing webhook 401, baseline — не изменилось) - **Тест изоляции (live):** два worktree на независимые ветки → A≠B, shared repo не тронут ✅ - PR #1 в orchestrator: open, mergeable ### Замечен побочный эффект (важно!) В shared `/repos/enduro-trails` обнаружена ветка **`ET-012-m-3-stage-engine`** с авто-коммитом от **analyst, run_id=52**. Это M-3 (ORCH-4) — оркестратор САМ запустил analyst и тот отработал АВТОНОМНО. Но создал задачу в неправильном репо (enduro-trails вместо orchestrator), потому что default_repo всё ещё enduro-trails. Доказывает: автономность починена, но multi-repo пока не настроено. ### Обсуждение self-hosting оркестратора - Слава заметил: оркестратор пилится Dev-агентом в обход своего конвейера - Причина: bootstrap-проблема — нельзя чинить сломанную машину, пока едешь на ней - Цель на будущее: self-hosting (оркестратор берёт свои же задачи через полный конвейер) - Нужна задача ORCH-6: self-hosting (после ORCH-1 очереди задач + multi-repo) ### Нейминг — финальное решение - Единое имя: **`orchestrator`** - Gitea-репо переименован `agent-dev` → `orchestrator` - Plane-проект `orchestrator` (identifier `ORCH`, id `8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a`) - Workspace `tasks/multi-agent/` → `tasks/orchestrator/` - Папка/контейнер/compose уже были `orchestrator` - Plane задачи: ORCH-1 (F-2b), ORCH-2 (S-4), ORCH-3 (S-2/S-3), ORCH-4 (M-3), ORCH-5 (M-7) ### Открытые вопросы Славе 1. Смержить PR #19 (enduro-trails)? 2. Смержить PR #1 (orchestrator worktree)? --- ## ИНЦИДЕНТ: Plane-webhook авто-запустил конвейер по всем ORCH-1..7 (2026-06-02 19:00) ### Что случилось - Создала в Plane задачи ORCH-1..7 — **Plane-webhook поймал каждую и авто-запустил конвейер** (analyst→architect, auto-commit) - Всё ушло в **неправильный репо enduro-trails** (`plane.py:91` hardcode `repo=settings.default_repo`), наплодило мусор ET-010..016 - Корень: Plane-webhook (id `93f0c342-a614-4248-9d0f-c107276f5620`) срабатывает на ЛЮБ\u041eЕ issue в workspace, без фильтра по проекту - ⚠️ **ПОЗИТИВ:** автономность реально работает — analyst exit=0, auto-commit, worktree (ORCH-2) сработал ### Меры (сделано) - 🛡️ **Plane-webhook ДЕАКТИВИРОВАН** в Plane postgres: `UPDATE webhooks SET is_active=false`. Проверено: `is_active=f` - Plane postgres: контейнер `plane-app-plane-db-1`, `PGPASSWORD=plane`, db `plane`, user `plane`, table `webhooks` - Обратно включить после ORCH-6: `UPDATE webhooks SET is_active=true WHERE id=...` - 🧹 Вычищено: все ветки ET-010..016 (git local+remote, 204), worktree `_wt/enduro-trails/*` (root-owned → sudo rm), тестовые iso-A/iso-B, tasks≥19 в БД орка, agent_runs≥19 - Plane чист: orchestrator=7 (ORCH-1..7), enduro=5 (родные). Junk ET-issues в Plane не было (орк генерил ET-номера сам в git+БД) - Заметка на сервере: `orchestrator/docs/INCIDENT_2026-06-02_webhook_autorun.txt` ### ROOT FIX = ORCH-6 (multi-repo) - `plane.py:91` `repo=settings.default_repo` → нужен фильтр по `plane_project_id` + маппинг repo per project - Пока ORCH-6 не сделан — webhook ДЕРЖАТЬ ВЫКЛЮЧЕННЫМ ### Открытые вопросы - Смержить PR #19 (enduro-trails) + PR #1 (orchestrator worktree)? ### Нейминг — финальное решение - Единое имя: **`orchestrator`** - Gitea-репо переименован `agent-dev` → `orchestrator` - Plane-проект `orchestrator` (identifier `ORCH`, id `8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a`) - Workspace `tasks/multi-agent/` → `tasks/orchestrator/` - Папка/контейнер/compose уже были `orchestrator` - Plane задачи: ORCH-1 (F-2b), ORCH-2 (S-4), ORCH-3 (S-2/S-3), ORCH-4 (M-3), ORCH-5 (M-7) ### Открытые вопросы Славе 1. Смержить PR #19 (enduro-trails)? 2. Смержить PR #1 (orchestrator worktree)? --- ## ИНЦИДЕНТ: Plane-webhook авто-запустил конвейер по всем ORCH-1..7 (2026-06-02 19:00) ### Что случилось - Создала в Plane задачи ORCH-1..7 — **Plane-webhook поймал каждую и авто-запустил конвейер** (analyst→architect, auto-commit) - Всё ушло в **неправильный репо enduro-trails** (`plane.py:91` hardcode `repo=settings.default_repo`), наплодило мусор ET-010..016 - Корень: Plane-webhook (id `93f0c342-a614-4248-9d0f-c107276f5620`) срабатывает на ЛЮБ\u041eЕ issue в workspace, без фильтра по проекту - ⚠️ **ПОЗИТИВ:** автономность реально работает — analyst exit=0, auto-commit, worktree (ORCH-2) сработал ### Меры (сделано) - 🛡️ **Plane-webhook ДЕАКТИВИРОВАН** в Plane postgres: `UPDATE webhooks SET is_active=false`. Проверено: `is_active=f` - Plane postgres: контейнер `plane-app-plane-db-1`, `PGPASSWORD=plane`, db `plane`, user `plane`, table `webhooks` - Обратно включить после ORCH-6: `UPDATE webhooks SET is_active=true WHERE id=...` - 🧹 Вычищено: все ветки ET-010..016 (git local+remote, 204), worktree `_wt/enduro-trails/*` (root-owned → sudo rm), тестовые iso-A/iso-B, tasks≥19 в БД орка, agent_runs≥19 - Plane чист: orchestrator=7 (ORCH-1..7), enduro=5 (родные). Junk ET-issues в Plane не было (орк генерил ET-номера сам в git+БД) - Заметка на сервере: `orchestrator/docs/INCIDENT_2026-06-02_webhook_autorun.txt` ### ROOT FIX = ORCH-6 (multi-repo) - `plane.py:91` `repo=settings.default_repo` → нужен фильтр по `plane_project_id` + маппинг repo per project - Пока ORCH-6 не сделан — webhook ДЕРЖАТЬ ВЫКЛЮЧЕННЫМ ### Открытые вопросы - Смержить PR #19 (enduro-trails) + PR #1 (orchestrator worktree)? --- ## ORCH-6 (Multi-repo) — Dev-прогон (2026-06-02 ~19:20-19:28) ### ТЗ - Файл: `tasks/orchestrator/DEV_TASK_ORCH6_MULTIREPO.md` (снайперское, все точки кода file:line собраны Стрим заранее) - Цель: реестр проектов (Plane id→repo+prefix) + фильтр webhook по проекту + resolve repo + plane_sync в правильный проект + prefix per project. Закрывает корень инцидента, снимает предохранитель. - Маппинг по умолчанию: enduro `7a79f0a9-...`→repo enduro-trails/ET; orchestrator `8da6aa25-...`→repo orchestrator/ORCH ### Прогон 1 (упал по таймауту LLM на Task 2, не вина кода) — но сделал ~75%, ФУНКЦИОНАЛ РАБОТАЕТ ✅ Готово (Task 1-5), проверено вживую: - `src/projects.py` (4607 байт) — ProjectConfig + 4 резолвера + дефолт-реестр - plane.py — фильтр по проекту (unknown→ignored) + resolve repo - db.py — `get_next_work_item_id(repo, prefix)` per project (ORCH-001 vs ET-010) - plane_sync.py — `_resolve_project_id`, параметризация (обратно совместимо) - gitea.py — unknown repo→ignored (3 хэндлера) - **Resolve-тест в контейнере прошёл:** orchestrator→orchestrator/ORCH, enduro→enduro-trails/ET, unknown→None ✅ - Все файлы компилируются; тесты 37 passed / 9 failed (те же pre-existing 401/signature, baseline не сломан) ❌ НЕ доделано (Task 6-7): тесты test_projects/test_plane_webhook, коммит, PR, пересборка, доки. Всё в working tree (не закоммичено). ### Решение: НЕ начинать заново, дослать Dev добивку (Task 6-7) — рабочие 75% терять глупо из-за инфра-таймаута - Запущен 2-й прогон (taskName `orch6_finish`/добивка), session subagent `24ac376a...` - ⚠️ Дубль-событие о падении прогона 1 (subagent `080bc9bc...`) прилетело позже — уже обработано, NO_REPLY ### КРИТИЧНО на потом - 🚫 Webhook ОСТАЁТСЯ выключенным до моего финального ревью фильтра (иначе риск повторить инцидент) - Включить webhook (`is_active=true`) — мой шаг ПОСЛЕ проверки что фильтр реально режет unknown-проекты - Tokenator API: жив, ключ в `/home/slin/openclaw/data/.env` (НЕ в orchestrator/.env). Ключ содержит `|` — bash sed/grep его режет, брать через Python - Plane API токен (60 симв) в orchestrator/.env РАБОЧИЙ — баг был в bash sed-парсинге, через Python HTTP 200 - Тесты орка — ТОЛЬКО в контейнере через образ (хостовый .venv сломан): `IMG=$(docker inspect orchestrator --format '{{.Config.Image}}'); docker run --rm -v /home/slin/repos/orchestrator:/code -w /code --entrypoint python3 $IMG -m pytest tests/ -q` - Workspace `tasks/multi-agent/` → `tasks/orchestrator/` - Папка/контейнер/compose уже были `orchestrator` - Plane задачи: ORCH-1 (F-2b), ORCH-2 (S-4), ORCH-3 (S-2/S-3), ORCH-4 (M-3), ORCH-5 (M-7) ### Открытые вопросы Славе 1. Смержить PR #19 (enduro-trails)? 2. Смержить PR #1 (orchestrator worktree)? --- ## ИНЦИДЕНТ: Plane-webhook авто-запустил конвейер по всем ORCH-1..7 (2026-06-02 19:00) ### Что случилось - Создала в Plane задачи ORCH-1..7 — **Plane-webhook поймал каждую и авто-запустил конвейер** (analyst→architect, auto-commit) - Всё ушло в **неправильный репо enduro-trails** (`plane.py:91` hardcode `repo=settings.default_repo`), наплодило мусор ET-010..016 - Корень: Plane-webhook (id `93f0c342-a614-4248-9d0f-c107276f5620`) срабатывает на ЛЮБ\u041eЕ issue в workspace, без фильтра по проекту - ⚠️ **ПОЗИТИВ:** автономность реально работает — analyst exit=0, auto-commit, worktree (ORCH-2) сработал ### Меры (сделано) - 🛡️ **Plane-webhook ДЕАКТИВИРОВАН** в Plane postgres: `UPDATE webhooks SET is_active=false`. Проверено: `is_active=f` - Plane postgres: контейнер `plane-app-plane-db-1`, `PGPASSWORD=plane`, db `plane`, user `plane`, table `webhooks` - Обратно включить после ORCH-6: `UPDATE webhooks SET is_active=true WHERE id=...` - 🧹 Вычищено: все ветки ET-010..016 (git local+remote, 204), worktree `_wt/enduro-trails/*` (root-owned → sudo rm), тестовые iso-A/iso-B, tasks≥19 в БД орка, agent_runs≥19 - Plane чист: orchestrator=7 (ORCH-1..7), enduro=5 (родные). Junk ET-issues в Plane не было (орк генерил ET-номера сам в git+БД) - Заметка на сервере: `orchestrator/docs/INCIDENT_2026-06-02_webhook_autorun.txt` ### ROOT FIX = ORCH-6 (multi-repo) - `plane.py:91` `repo=settings.default_repo` → нужен фильтр по `plane_project_id` + маппинг repo per project - Пока ORCH-6 не сделан — webhook ДЕРЖАТЬ ВЫКЛЮЧЕННЫМ ### Открытые вопросы - Смержить PR #19 (enduro-trails) + PR #1 (orchestrator worktree)? --- ## ORCH-6 (Multi-repo) — Dev-прогон (2026-06-02 ~19:20-19:28) ### ТЗ - Файл: `tasks/orchestrator/DEV_TASK_ORCH6_MULTIREPO.md` (снайперское, все точки кода file:line собраны Стрим заранее) - Цель: реестр проектов (Plane id→repo+prefix) + фильтр webhook по проекту + resolve repo + plane_sync в правильный проект + prefix per project. Закрывает корень инцидента, снимает предохранитель. - Маппинг по умолчанию: enduro `7a79f0a9-...`→repo enduro-trails/ET; orchestrator `8da6aa25-...`→repo orchestrator/ORCH ### Прогон 1 (упал по таймауту LLM на Task 2, не вина кода) — но сделал ~75%, ФУНКЦИОНАЛ РАБОТАЕТ ✅ Готово (Task 1-5), проверено вживую: - `src/projects.py` (4607 байт) — ProjectConfig + 4 резолвера + дефолт-реестр - plane.py — фильтр по проекту (unknown→ignored) + resolve repo - db.py — `get_next_work_item_id(repo, prefix)` per project (ORCH-001 vs ET-010) - plane_sync.py — `_resolve_project_id`, параметризация (обратно совместимо) - gitea.py — unknown repo→ignored (3 хэндлера) - **Resolve-тест в контейнере прошёл:** orchestrator→orchestrator/ORCH, enduro→enduro-trails/ET, unknown→None ✅ - Все файлы компилируются; тесты 37 passed / 9 failed (те же pre-existing 401/signature, baseline не сломан) ❌ НЕ доделано (Task 6-7): тесты test_projects/test_plane_webhook, коммит, PR, пересборка, доки. Всё в working tree (не закоммичено). ### Решение: НЕ начинать заново, дослать Dev добивку (Task 6-7) — рабочие 75% терять глупо из-за инфра-таймаута - Запущен 2-й прогон (taskName `orch6_finish`/добивка), session subagent `24ac376a...` - ⚠️ Дубль-событие о падении прогона 1 (subagent `080bc9bc...`) прилетело позже — уже обработано, NO_REPLY ### КРИТИЧНО на потом - 🚫 Webhook ОСТАЁТСЯ выключенным до моего финального ревью фильтра (иначе риск повторить инцидент) - Включить webhook (`is_active=true`) — мой шаг ПОСЛЕ проверки что фильтр реально режет unknown-проекты - Tokenator API: жив, ключ в `/home/slin/openclaw/data/.env` (НЕ в orchestrator/.env). Ключ содержит `|` — bash sed/grep его режет, брать через Python - Plane API токен (60 симв) в orchestrator/.env РАБОЧИЙ — баг был в bash sed-парсинге, через Python HTTP 200 - Тесты орка — ТОЛЬКО в контейнере через образ (хостовый .venv сломан): `IMG=$(docker inspect orchestrator --format '{{.Config.Image}}'); docker run --rm -v /home/slin/repos/orchestrator:/code -w /code --entrypoint python3 $IMG -m pytest tests/ -q` ### ✅ ORCH-6 ДОДЕЛАН (прогон 2, ~19:35) — проверено мной вживую, НЕ на слово - **PR #2** (orchestrator, ветка `feature/ORCH-6-multirepo`) — open, **mergeable:True** - 7 коммитов Conventional Commits - Оба тест-файла созданы (test_projects, test_plane_webhook) - **Тесты: 57 passed** (20 новых зелёных), 9 fail — те же pre-existing 401/TypeError, baseline ЦЕЛ - Контейнер пересобран, health ok - Resolve вживую: orchestrator→ORCH, enduro→ET, unknown→None ✅ - 🛡️ Webhook ОСТАЁТСЯ выключен (`is_active=f`) — Dev не трогал, как и договорено ### 🔵 ЖДЁТ РЕШЕНИЯ СЛАВЫ (спросила, ОК пока нет) 1. Смержить **PR #2** (multi-repo) в main orchestrator 2. После мержа — **включить Plane-webhook** (`UPDATE webhooks SET is_active=true`) — теперь безопасно, фильтр режет чужие проекты - Делать без ОК НЕ буду: мерж в main + включение автозапуска = живая автономная система - Также висят: PR #19 (enduro-trails), PR #1 (orchestrator worktree) ### Следующий бэклог ORCH (после ORCH-6 merge+webhook on) - ORCH-1 (F-2b очередь задач вместо in-process daemon) — следующий приоритет - ORCH-3 (S-2/S-3 rollback), ORCH-4 (M-3 stage-engine), ORCH-5 (M-7 идемпотентность webhook dedup) --- ## ORCH-6 ЗАМЕРЖЕН + Webhook ВКЛЮЧЁН (2026-06-02 ~21:00) — проверено вживую ### Сделано (с ОК Славы «Делай») - ✅ **PR #2 смержен** в main orchestrator (HTTP 200, merge commit `b021ff7`) - ✅ Контейнер пересобран из main, health ok - ✅ В main также прилетел `test_git_worktree.py` (ORCH-2 хвост) — норма - ✅ **Plane-webhook ВКЛЮЧЁН обратно**: `UPDATE webhooks SET is_active=true` → `is_active=t`, UPDATE 1 ### Боевой тест предохранителя (двойная защита, подтверждено на проде) 1. 🛡️ HMAC-подпись: webhook без валидной подписи → `401 Invalid signature` (секрет 40 симв настроен) 2. 🛡️ Фильтр проекта: webhook с ВАЛИДНОЙ подписью от неизвестного проекта → `200 {"status":"ignored","reason":"unknown project"}`, лог `ignoring event from unknown project (known: 2)` 3. ✅ Задача НЕ создалась (11→11) — инцидент технически невозможен ### Грабли (повтор из инцидента — записать чтоб не наступать) - Postgres-пароль Plane: `\x27`-экранирование кавычек через ssh+docker ЛОМАЕТСЯ. Рабочий способ — писать SQL в файл и `psql -f`, пароль брать из env Plane-контейнера (`len=5`) - Plane postgres: контейнер `plane-app-plane-db-1`, db/user `plane` --- ## ORCH-1 (F-2b) — Персистентная очередь задач (2026-06-02 ~21:00) ### Контекст проблемы (in-process архитектура) - `launcher.launch()` синхронно: `subprocess.Popen(claude)` + 2 daemon-thread (`_watchdog` таймаут-киллер 1800с + `_monitor_agent` ждёт/коммитит/advance stage) - 8 точек вызова: `plane.py:189,234,308,389` + `gitea.py:126,203,275,300` - Беды: рестарт орка = агенты-сироты + потеря работы; нет лимита параллелизма; нет ретраев; webhook блокируется на спавне ### ТЗ - `tasks/orchestrator/DEV_TASK_ORCH1_QUEUE.md` (снайперское, все file:line собраны заранее) - Решение: таблица `jobs` (queued/running/done/failed) + atomic `claim_next_job` + `queue_worker.py` петля + `max_concurrency` + ретраи + requeue running на старте (restart-safe) + `/queue` эндпоинт ### ✅ Базовая очередь готова (PR #3) — проверено мной вживую - **76 passed** (19 новых тестов очереди, вкл. атомарность claim на 8 потоках/20 jobs), 9 fail — те же pre-existing 401 - `/queue` живой: counts, max_concurrency, recent - PR #3 open, mergeable:True - Фиксы B-1/B-2/M-1/ORCH-2/ORCH-6 не тронуты - Живой прогон: queued→running→done, ретрай, restart-safe ### ⚠️ Resilience-слой Dev в базовый PR #3 НЕ встроил - Моё уточнение (preflight/429/backoff/breaker) пришло когда Dev уже ушёл в финал T8-T12 → в коде НЕТ ни `preflight.py`, ни классификатора 429, ни breaker, ни колонок backoff - Урок: при дослыле уточнения в активную сессию Dev — проверять, что оно реально вошло в код, а не только в отчёт «done» --- ## ORCH-1b (Resilience-слой) — дослан отдельной задачей (2026-06-02 ~21:00) ### Идея Славы (отличный вопрос про надёжность claude CLI) - Два РАЗНЫХ зверя, лечить раздельно: - **CLI недоступен** (бинарь/сеть) → дешёвый preflight `claude --version` + TCP, кэш 45с, токены НЕ жжёт. Мёртв → job ждёт в очереди, не падает - **Rate limit 429** → предсказать НЕЛЬЗЯ; prompt-ping перед запуском = трата лимита, ТАК НЕ ДЕЛАТЬ. Ловить 429 на ВЫХОДЕ (паттерны в логе: `429`/`rate limit`/`overloaded`/`Retry-After`), классифицировать transient vs permanent - **Backoff** для transient: exp + `available_at`/`next_attempt_at` колонка в очереди + уважать `Retry-After`. Очередь = идеальное место для backoff - **Circuit breaker**: 3 фейла подряд → пауза 5 мин (CLI не дёргаем, лимит не выжигаем) + алерт → half-open проба → закрыли - Ретраи раздельные: transient (429) ≠ code-fault (attempts=2) ### Статус - Задача `orch1b_resilience` запущена на Dev (Opus 4.8), поверх той же ветки/PR #3 (фокусные коммиты) - Требует: безопасная миграция БД через PRAGMA-проверку (prod-база `jobs` уже живая) ### ⚠️ Урок: тест-алерты дёргают Славу - Dev гонял retry-тест с синтетическим `repo r-retry` / job 3 → fail-алерт долетел в Telegram, Слава испугался («Ау») - Проверка: `/queue` всё по нулям, в прод-БД никакого `r-retry`/job 3 нет — жил только в эфемерной pytest-БД - **TODO для ORCH-1b**: подавить Telegram-нотификации в тестовых прогонах (нотификации только прод, не pytest) ### Следующие шаги - Дождаться `orch1b_resilience`, проверить вживую (preflight без трат токенов, 429-классификатор, backoff, breaker, миграция) - Слить PR #3 (base queue + resilience) ОДНИМ куском после полной проверки - Дальше бэклог: ORCH-3 (S-2/S-3 rollback), ORCH-4 (M-3 stage-engine), ORCH-5 (M-7 idempotency/webhook dedup) ### Висящие вопросы Славе - PR #19 (enduro-trails), PR #1 (orchestrator worktree) — мержить? - PR #2 уже смержен (ORCH-6)