Files
wiki/tasks/orchestrator/ORCHESTRATOR_DOCS.md
2026-06-04 03:00:01 +03:00

31 KiB
Raw Blame History

Документация: Orchestrator Multi-Agent Pipeline

Статус: 2026-06-03 (актуально)

Свежее (03.06.2026): переход на status-only verdict model (PR #12) — вердикт Славы теперь через смену статуса Issue (Approved/Rejected), а НЕ через коммент :approved:. Закрыты 7 багов конвейера (PR #12#18) при боевой обкатке на ET-011 (task 29). Конвейер впервые прошёл analysis→architecture→development end-to-end с одного Approved, дошёл до честного CI-гейта и получил автономное самовосстановление на красном CI (с лимитом попыток). Подробности — в разделах «Переходы статусов», «Механизмы автономности» и Changelog.


Архитектура

Plane (Work Items) → Webhook → Orchestrator → Claude CLI agents → Gitea → Deploy

Orchestrator — Python FastAPI приложение в Docker на mva154 (port 8500). Слушает webhooks от Plane и Gitea, управляет жизненным циклом задач.


Конвейер (Pipeline)

created → analysis → architecture → development → review → testing → deploy → done
Stage Agent QG (вход) Что делает
analysis analyst BRD, ТЗ, AC, Test Plan
architecture architect check_analysis_approved (:approved: от Славы) ADR, архитектурные решения
development developer check_architecture_done (файлы ADR есть) Код + тесты + PR. Выход гейтится check_ci_green (PR #17): зелёный CI → review; красный CI → developer retry (PR #18, max 3)
review reviewer check_ci_green (Gitea CI status, выход development) Code review → 12-review.md
testing tester check_reviewer_verdict (APPROVED в 12-review.md) Прогон тестов → 13-test-report.md
deploy deployer check_tests_passed (PASS в 13-test-report.md) Merge PR → tag → deploy → smoke
done Задача завершена

Агенты

Конфигурация (AGENT_CONFIGS)

Agent Task file System prompt Model
analyst .task.md .openclaw/agents/analyst.md claude-sonnet-4-6
architect .task-arch.md .openclaw/agents/architect.md claude-opus-4-7
developer .task-dev.md .openclaw/agents/developer.md claude-sonnet-4-6
reviewer .task-review.md .openclaw/agents/reviewer.md claude-opus-4-7
tester .task-test.md .openclaw/agents/tester.md claude-sonnet-4-6
deployer .task-deploy.md .openclaw/agents/deployer.md claude-sonnet-4-6

Deployer (добавлен 2026-06-01)

Функции:

  1. Merge PR через Gitea API
  2. Создать semver tag (patch increment)
  3. Deploy (git pull main на сервере)
  4. Healthcheck (до 60 сек, 12 попыток)
  5. Smoke test (ключевые endpoints)
  6. Rollback к предыдущему тегу при fail
  7. Записать 14-deploy-log.md + обновить CHANGELOG.md

Запрещено: менять код, force push, деплоить без merge.


Quality Gates

QG Функция Что проверяет
QG-0 Валидация при создании Issue title 5-80 chars, description ≥2 предложений
check_analysis_approved :approved: в комментарии Plane от стейкхолдера Человеческое подтверждение ТЗ
check_architecture_done Наличие ADR файлов в docs/work-items/<id>/06-adr/ Архитектура задокументирована
check_ci_green Gitea commit status API CI pipeline зелёный (гейт стадии development, PR #17)
check_reviewer_verdict Парсинг 12-review.md → APPROVED/REQUEST_CHANGES Код прошёл ревью
check_tests_passed Парсинг 13-test-report.md → PASS/FAIL Тесты пройдены
check_tests_local локальный pytest целевого репо DEPRECATED (PR #17): заменён check_ci_green на development. Остаётся в QG_CHECKS для совместимости, не wired ни к одной стадии

Plane Integration (полная)

Статусы Issue

Статус ID Когда Что значит для Славы
Backlog 113b24f6... Создан, ещё не взят Ничего не происходит
Todo 2c7d3df3... Прошёл QG-0, ждёт запуска Скоро начнётся
In Progress b873d9eb... Агент работает Система работает, ждать
Needs Input babf08a3... Analyst задал вопросы Слава, ответь в комментарии
In Review 38fb1f64... ТЗ готово, ждёт approve Слава, прочитай и :approved: / :rejected:
Blocked 6c4543f9... Ошибка / retry исчерпаны Нужно ручное вмешательство
Done 381a2833... Всё задеплоено Готово
Cancelled b1cae7f9... Отменена

Переходы статусов (status-only verdict model, PR #12, 03.06.2026)

Ключевое изменение: вердикт Славы принимается только по смене статуса Issue в Plane (Approved / Rejected), не по комменту :approved:. Комменты теперь logged only, no pipeline action. Причина Rejected берётся из последнего коммента.

Backlog → [QG-0 pass] → In Progress (analyst запущен)
In Progress → [analyst questions] → Needs Input
Needs Input → [Слава ответил] → In Progress (analyst перезапущен)
In Progress → [analyst done] → In Review (BRD/ТЗ/AC готовы, ждёт статус Approved)
In Review → [Слава → статус Approved] → Architecture (architect запущен)   ← БАГ 4 фикс (PR #15)
In Review → [Слава → статус Rejected + причина комментом] → In Progress (analyst перезапущен)
Architecture → [architect done + QG] → Development → ... → Done
In Progress → [3 retry исчерпаны / deploy fail] → Blocked

Статусы-вердикты (новые):

  • Approved (a519a341...) — Слава одобрил ТЗ → конвейер двигается на следующую стадию (analysis→architecture).
  • Rejected — Слава отклонил → причина из коммента → analyst перезапуск.
  • Architecture (3020bbb7...) — рабочая стадия architect.
  • Без мелькания In Progress при advance: _try_advance_stage сразу PATCH-ит статус следующей стадии.

Комментарии в Plane

Orchestrator автоматически пишет комментарии при:

  • Каждом переходе stage (с ссылками на branch и PR)
  • QG failure (что не прошло и почему)
  • Запуске агента
  • Вопросах analyst'а (текст вопросов)
  • Ошибках (deploy fail, retry exhausted)
  • Завершении задачи

Ссылки в комментариях

При переходах stage / готовности analyst комментарий содержит кликабельные ссылки на доки (BRD/ТЗ/AC) + branch/PR.

ВАЖНО (PR #14, 03.06.2026): ссылки строятся от отдельного публичного URL gitea_public_url (env ORCH_GITEA_PUBLIC_URL, прод: https://git.mva154.duckdns.org), А НЕ от внутреннего gitea_url (localhost:3000, он для git clone/push). Без этого ссылки вели на localhost и не кликались из браузера. Fallback: если gitea_public_url пустой → используется gitea_url.

  • 📂 Branch: ссылка на ветку в Gitea (публичный URL)
  • 🔗 PR: ссылка на Pull Request (на этапах review/testing/deploy)
  • 📄 Доки: Business request / BRD / ТЗ / Acceptance Criteria (публичный URL, кликабельные)

Webhook events

Event Действие
work_item.created / issue.created QG-0 → create branch → init docs → launch analyst
issue.updated (смена статуса) Главный вердикт-путь (PR #12): Approved → advance, Rejected → rollback+relaunch, In Progress → start pipeline
comment.created / issue_comment.created Только лог (logged only, no pipeline action) — комменты БОЛЬШЕ НЕ двигают конвейер (было: :approved:/:rejected:). Причина Rejected читается из последнего коммента при вердикте

QG-0: Валидация при создании Issue

При создании Issue в Plane, orchestrator проверяет:

  • Title: 5-80 символов
  • Description: ≥2 предложений

Если не проходит → Issue переходит в Blocked + комментарий с описанием что исправить.


Механизмы автономности

Auto-advance

После завершения агента (exit 0), _monitor_agent вызывает _try_advance_stage:

  1. Определяет текущий stage задачи
  2. Проверяет QG следующего stage
  3. Если QG green → advance stage → launch next agent
  4. Если QG red → stop (ждёт внешнего события)

Auto-PR

После developer push, _ensure_pr() автоматически создаёт PR в Gitea.

Auto-init

При создании Issue в Plane → webhook → QG-0 → branch → docs → analyst. Слава просто создаёт Issue — всё остальное автоматически.

Retry (developer)

При REQUEST_CHANGES от reviewer'а — developer перезапускается (до 3 раз). Код: src/webhooks/gitea.py handle_pr, ветка REQUEST_CHANGES.

Retry (CI fail) — баг 7, PR #18 (03.06.2026)

При красном Gitea CI на стадии development конвейер не виснет, а автономно возвращает задачу developer'у на доработку — симметрично review-retry.

  • Триггер: handle_ci_status, ветка state == "failure" and current_stage == "development".
  • Логика: notify_qg_failure (уведомить о провале) → если retry_count < MAX_DEV_RETRIESenqueue_job("developer", ..., "CI failed, fix and re-push (attempt N/3)"); иначе → notify_error (escalate, ручное вмешательство).
  • Задача УЖЕ в development → смены стадии нет (в отличие от review-retry, где был переход review→development).
  • Лимит общий: MAX_DEV_RETRIES = 3 считается по ВСЕМ agent_runs агента developer задачи → review-правки + CI-правки в сумме ≤ 3. После 3 попыток — эскалация.
  • Проверено боевым прогоном на ET-011: красный CI → developer перезапущен (run 1→2, attempt 2/3) полностью автономно.

Retry (tester fail)

При FAIL тестов — developer перезапускается для фикса (до 3 раз). После 3 неудач → Issue переходит в Blocked.

Analyst questions

Analyst может создать 01-questions.md → Issue переходит в Needs Input. Слава отвечает комментарием → analyst перезапускается с ответами (до 3 раундов).

Notifications

Telegram уведомления на каждом переходе stage + при ошибках.


Сценарии работы

🟢 Позитивный (happy path)

  1. Слава создаёт Issue в Plane: "Добавить фильтр по высоте"
  2. QG-0 ✓ → branch feature/ET-012-filter-altitude → analyst запущен
  3. Analyst пишет BRD/ТЗ/AC/TestPlan → Issue → In Review
  4. Слава читает, пишет :approved: → Issue → In Progress
  5. Architect → ADR → auto-advance
  6. Developer → код + тесты → PR → auto-advance
  7. Reviewer → APPROVED → auto-advance
  8. Tester → PASS → auto-advance
  9. Deployer → merge → tag → deploy → smoke ✓ → Issue → Done
  10. Telegram: "🎉 ET-012: задача завершена!"

🟡 Analyst задаёт вопросы

  1. Analyst не понимает требования → создаёт 01-questions.md
  2. Issue → Needs Input + Telegram: " ET-012: Analyst задаёт вопросы"
  3. Слава отвечает комментарием в Plane
  4. Orchestrator ловит комментарий → Issue → In Progress → analyst перезапущен
  5. Analyst учитывает ответы → пишет ТЗ → Issue → In Review
  6. (Максимум 3 раунда вопросов, потом → Blocked)

🟡 Слава отклоняет ТЗ

  1. Issue в In Review, Слава пишет :rejected: Не учтены мобильные устройства
  2. Issue → In Progress → analyst перезапущен с причиной отклонения
  3. Analyst исправляет → Issue → In Review (повторно)

🔴 Tester находит баги

  1. Tester прогоняет тесты → FAIL в 13-test-report.md
  2. Issue остаётся In Progress → developer перезапущен для фикса
  3. Developer фиксит → reviewer → tester (повторно)
  4. Если 3 попытки developer'а не помогли → Issue → Blocked
  5. Telegram: "🚨 ET-012: Tests still failing after 3 retries"

🔴 Deploy fail

  1. Deployer мержит PR, деплоит, smoke test FAIL
  2. Deployer откатывает к предыдущему тегу
  3. Issue → Blocked
  4. Telegram: "🚨 ET-012: Deploy failed! Rolled back."

🔴 Architect conflict

  1. Architect находит конфликт с ТЗ → создаёт 10-conflict.md
  2. Issue → In Progress → analyst перезапущен с описанием конфликта
  3. Analyst пересматривает ТЗ → Issue → In Review (повторно)

Файловая структура

/home/slin/repos/orchestrator/
├── src/
│   ├── main.py              # FastAPI app
│   ├── config.py            # Settings (env vars)
│   ├── db.py                # SQLite (tasks, agent_runs, events)
│   ├── stages.py            # STAGE_TRANSITIONS
│   ├── notifications.py     # Telegram notifications
│   ├── plane_sync.py        # Plane API (states, comments, links)
│   ├── agents/
│   │   ├── launcher.py      # AgentLauncher (launch, monitor, retry, advance)
│   │   └── __init__.py
│   ├── webhooks/
│   │   ├── gitea.py         # Push, PR, CI status handlers
│   │   ├── plane.py         # work_item.created, comment handlers
│   │   └── __init__.py
│   └── qg/
│       ├── checks.py        # QG check functions
│       └── __init__.py
├── docker-compose.yml
├── Dockerfile
└── requirements.txt

Инфраструктура

  • Host: mva154 (82.22.50.71)
  • Container: orchestrator (port 8500)
  • Gitea: localhost:3000 (в docker network)
  • Plane: localhost:8091 (в docker network)
  • Repos: /home/slin/repos/orchestrator, /repos/enduro-trails (в контейнере)
  • DB: SQLite (/app/data/orchestrator.db)
  • Logs: /app/data/logs/ (per-agent run logs)

Единственная точка ручного вмешательства

:approved: после analyst'а — Слава подтверждает ТЗ в Plane.

Всё остальное — полностью автономно:

  • auto-init при создании Issue
  • architect запускается автоматически после approve
  • developer → после architecture done
  • reviewer → после CI green
  • tester → после review approved
  • deployer → после tests passed
  • done → после deploy success
  • retry при ошибках (до 3 раз)
  • rollback при deploy fail

Автономный деплой

Deployer выполняет деплой через SSH на хост:

ssh slin@127.0.0.1 "bash /home/slin/bin/enduro-deploy-hook.sh"

Hook (/home/slin/bin/enduro-deploy-hook.sh) делает:

  1. git pull origin main в репо проекта
  2. docker compose up -d app — перезапуск app контейнера
  3. Опционально: docker compose --profile batch run --rm gps-collector (флаг --run-gps-collector)
  4. Логирует всё в /var/log/enduro-trails/deploy-hook.log

SSH ключ orchestrator'а: /home/slin/.orchestrator-ssh/id_ed25519 (смонтирован в контейнер как /root/.ssh/)


Расхождения с Proposal v1

Полная таблица: tasks/multi-agent/PROPOSAL_VS_REALITY.md

Ключевые отличия от идеала:

  • Designer не реализован (skip для не-UI задач)
  • QG упрощены (проверка файлов, не lint-скрипты)
  • Один environment (test), нет prod
  • Нет budget tracking
  • Architect и Reviewer на Opus, остальные на Sonnet (proposal: все на Sonnet)
  • Нет Plane подзадач (7 subtasks) — один Issue, этапы в orchestrator DB

🐛 Баги входа/выхода analyst — сессия 03.06.2026 (PR #12#15)

Цепочка из 4 багов, вскрытых при переходе на status-only verdict model и прогоне реальной задачи ET-011 (#6, task 29). Все подтверждены боевыми прогонами.

# PR Баг Корень Фикс
Баг 3 #12 Эхо-самоудар: собственный коммент/статус analyst сбивал стадию Коммент-вердикт (:approved:) ловился на собственных комментах бота status-only verdict model: вердикт только по смене статуса, комменты logged only
Баг A #13 description из Plane НЕ попадал в .task.md (пустышка 101 байт) Описание тянулось из API, но не писалось в файл задачи .task.md = 973 байта с полным ТЗ
Баг B #13 name не дотягивался → ветка untitled Имя Issue не читалось из API ветка feature/ET-011-popup-enduro-trails
Баг C #13 Устаревший коммент «Жду :approved:» + нет ссылок на доки Коммент analyst не обновлён под status-only коммент про Approved-статус + ссылки на 6 доков
#14 Ссылки в комменте вели на localhost:3000 — не кликались из браузера Ссылки строились от внутреннего gitea_url новое поле gitea_public_url (env ORCH_GITEA_PUBLIC_URL), fallback на gitea_url; git-операции не тронуты
Баг 4 #15 БЛОКЕР: ручной Approved из analysis НЕ двигал конвейер — task застревал в analysis, architect не запускался advance_stage(): ветка check_analysis_approved ВСЕГДА делала ранний return result → блок Advance недостижим. На webhook-пути (Approved, finished_agent=None) _handle_analysis_approved_flow выходил ничего не делая развёл ветку по agent: analyst(launcher)→flow+return (In Review+коммент), None(вердикт)→провал в Advance (update_task_stage+enqueue architect)

Итог: конвейер впервые прошёл analysis→architecture end-to-end через живой Approved Славы. architect запущен, создал ADR-014/ADR-015 + infra-requirements.


🐛 Баги QG-гейта development — сессия 03.06.2026 (PR #16#18)

Продолжение боевой обкатки ET-011: конвейер дошёл до стадии developmentreview и вскрыл цепочку багов QG-гейта (спуск по слоям инфраструктуры: каждый фикс открывал следующий). Все подтверждены боевыми прогонами.

# PR Баг Корень Фикс
Баг 5 #16 QG check_tests_local падал — make НЕТ в контейнере оркестратора check_tests_local звал ["make","test"], но в контейнере только pytest, без make прямой вызов ["python","-m","pytest","../../tests/","-v"], cwd=<repo>/src/api (1:1 с Makefile целью test). make в Dockerfile НЕ добавляли намеренно
Баг 6 #17 check_tests_local дублировал CI и гонял тесты enduro-trails в окружении оркестратора без зависимостей проекта (ModuleNotFoundError: lxml/shapely/defusedxml) check_tests_local — легаси-затычка эпохи S-1 «Gitea CI не настроен → always false». CI теперь настроен (.gitea/workflows/ci.yml, гоняет в ПРАВИЛЬНОМ окружении с pip install ".[dev]") → затычка устарела QG стадии development: check_tests_localcheck_ci_green (доверились CI). check_tests_local НЕ удалён — помечен DEPRECATED, остался в QG_CHECKS, не wired ни к одной стадии. CI-failure больше не подавляется → notify_qg_failure
Баг 7 #18 ДЫРА: красный CI на development НЕ возвращал задачу developer'у — конвейер вис, требовал ручного вмешательства побочка фикса бага 6: CI стал авторитетным гейтом, но handle_ci_status при failure делал ТОЛЬКО notify_qg_failure. retry developer'а был только на review request_changes добавлен retry developer'а на красный CI симметрично review: retry_count < MAX_DEV_RETRIES(=3)enqueue_job("developer", attempt N/3); иначе → escalate. Лимит общий (review+CI ≤ 3). Подробно — раздел «Retry (CI fail)»
Баг 8 #19 КРИТИЧНЫЙ: провалившийся деплой уходил в done — фича нерабочая, а задача «выполнена». Вскрыто на ET-011: deployer честно написал Status: FAILED (hook permission denied, контейнер не пересобрался), но done (1) stages.py стадия deploy имела qg: None — ГЕЙТА ВЫХОДА НЕТ вообще. (2) exit_code = код LLM-процесса (всегда 0 при успешной сессии) → защита launcher.py:475 exit_code!=0 не срабатывала новый QG check_deploy_status (по образцу check_reviewer_verdict): читает frontmatter deploy_status: из 14-deploy-log.md. deploy.qg=check_deploy_status. Вердикт SUCCESS→done, FAILED→откат в development + Blocked + alert (по ВЕРДИКТУ, не exit_code). deployer-промпт enduro-trails обязан писать deploy_status: SUCCESS/FAILED

Итог: после бага 7 конвейер самовосстанавливается на красном CI. Боевой прогон ET-011: красный CI (10× E402 — импорты не в шапке src/api/main.py) → developer автономно перезапущен (run 1→2, attempt 2/3).

Баг 8 — важный урок: «зелёный в CI ≠ работает на проде». Конвейер пометил ET-011 done, но фича (скачивание GPX) НЕ работала: deploy-hook упал на permission denied (/var/log/enduro-trails root-owned, slin без sudo), контейнер остался на старом образе 37 часов. Инфра-блокер (TODO ops): sudo chown slin:slin /var/log/enduro-trails или сменить LOG-путь в hook на доступный slin. После фикса бага 8 такой провал будет честно откатывать задачу в development, а не помечать done.

Важный принцип (из багов 5/6): оркестратор НЕ гоняет тесты целевых проектов в своём контейнере — это делает Gitea CI в правильном окружении со всеми зависимостями. QG-гейт development доверяет CI-статусу (check_ci_green), а не локальному прогону. НЕ ставить lxml/shapely/defusedxml/make в Dockerfile оркестратора.


Changelog

Дата Изменение
2026-06-03 PR #19 Fix Баг 8: deploy→done гейтится новым check_deploy_status (вердикт deploy_status: из 14-deploy-log.md), а не exit-code LLM-процесса. Провал deploy → откат в development + Blocked. + deployer-промпт enduro-trails пишет frontmatter (enduro-trails #23)
2026-06-03 enduro-trails #23 Feat (A1, решение владельца): enduro_russia download_allowed: true — скачивание GPX включено
2026-06-03 PR #18 Fix Баг 7: красный CI на development автономно возвращает задачу developer'у (retry с общим лимитом 3, симметрично review)
2026-06-03 PR #17 Fix Баг 6: QG development check_tests_localcheck_ci_green (доверились CI, не гоняем чужие тесты в контейнере; check_tests_local DEPRECATED, CI-failure больше не подавляется)
2026-06-03 PR #16 Fix Баг 5: check_tests_local зовёт pytest напрямую вместо make (make нет в контейнере)
2026-06-03 PR #15 Fix Баг 4: Approved-вердикт двигает analysis→architecture (развёд check_analysis_approved по finished_agent)
2026-06-03 PR #14 Add: gitea_public_url — внешний URL для кликабельных ссылок в комментах (git-операции на localhost не тронуты)
2026-06-03 PR #13 Fix Баги A/B/C: description.task.md, name→ветка (не untitled), коммент analyst под status-only + ссылки на доки
2026-06-03 PR #12 Add: status-only verdict model — вердикт по смене статуса (Approved/Rejected), комменты logged only (фикс Баг 3 эхо-самоудар)
2026-05-31 Fix: _monitor_agent PIPE streaming (race condition)
2026-05-31 Fix: check_reviewer_verdict вместо check_review_approved
2026-05-31 Add: _ensure_pr (auto-PR after developer push)
2026-05-31 Add: REQUEST_CHANGES retry logic (3 attempts)
2026-06-01 Add: deployer agent (merge → tag → deploy → smoke → rollback)
2026-06-01 Remove: _auto_merge_pr hardcode from _try_advance_stage
2026-06-01 Add: Plane states — Needs Input, In Review, Blocked
2026-06-01 Add: Analyst questions flow (01-questions.md → Needs Input → relaunch)
2026-06-01 Add: :rejected: handler с причиной + relaunch
2026-06-01 Add: Tester FAIL → developer retry (до 3 раз → Blocked)
2026-06-01 Add: Deploy FAIL → Blocked + rollback
2026-06-01 Add: Architect conflict (10-conflict.md → rollback to analysis)
2026-06-01 Add: QG-0 валидация при создании Issue
2026-06-01 Add: Ссылки в комментариях (branch + PR URLs)
2026-06-01 Add: Max 3 question rounds для analyst
2026-06-01 Fix: Analyst prompt — добавлена явная инструкция использовать Write tool (артефакты на диск, не в stdout)
2026-06-01 Fix: Analyst model — возвращён на Sonnet (был переключён на Opus, расходовал лимиты Max 5x)
2026-06-01 Add: Startup timeout 120s — если Claude CLI не выдаёт output за 120 сек → kill + Telegram уведомление
2026-06-01 Fix: Plane comment webhookhandle_comment теперь читает поле issue (Plane шлёт именно его, не work_item_id/issue_id) + comment_stripped вместо comment_html
2026-06-01 Add: SSH deploy hook — deployer использует SSH для вызова /home/slin/bin/enduro-deploy-hook.sh на хосте
2026-06-01 Add: openssh-client в Dockerfile orchestrator, SSH ключ смонтирован с хоста (/home/slin/.orchestrator-ssh/)
2026-06-01 Fix: Plane comment webhookhandle_comment читает поле issue (Plane шлёт именно его) + comment_stripped
2026-06-01 Fix: ET-008 GPS-треки — pipeline завершён, v0.0.1 задеплоен, gps-collector запущен