31 KiB
Документация: 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)
Функции:
- Merge PR через Gitea API
- Создать semver tag (patch increment)
- Deploy (git pull main на сервере)
- Healthcheck (до 60 сек, 12 попыток)
- Smoke test (ключевые endpoints)
- Rollback к предыдущему тегу при fail
- Записать
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 |
Тесты пройдены |
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(envORCH_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:
- Определяет текущий stage задачи
- Проверяет QG следующего stage
- Если QG green → advance stage → launch next agent
- Если 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_RETRIES→enqueue_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)
- Слава создаёт Issue в Plane: "Добавить фильтр по высоте"
- QG-0 ✓ → branch
feature/ET-012-filter-altitude→ analyst запущен - Analyst пишет BRD/ТЗ/AC/TestPlan → Issue → In Review
- Слава читает, пишет
:approved:→ Issue → In Progress - Architect → ADR → auto-advance
- Developer → код + тесты → PR → auto-advance
- Reviewer → APPROVED → auto-advance
- Tester → PASS → auto-advance
- Deployer → merge → tag → deploy → smoke ✓ → Issue → Done
- Telegram: "🎉 ET-012: задача завершена!"
🟡 Analyst задаёт вопросы
- Analyst не понимает требования → создаёт
01-questions.md - Issue → Needs Input + Telegram: "❓ ET-012: Analyst задаёт вопросы"
- Слава отвечает комментарием в Plane
- Orchestrator ловит комментарий → Issue → In Progress → analyst перезапущен
- Analyst учитывает ответы → пишет ТЗ → Issue → In Review
- (Максимум 3 раунда вопросов, потом → Blocked)
🟡 Слава отклоняет ТЗ
- Issue в In Review, Слава пишет
:rejected: Не учтены мобильные устройства - Issue → In Progress → analyst перезапущен с причиной отклонения
- Analyst исправляет → Issue → In Review (повторно)
🔴 Tester находит баги
- Tester прогоняет тесты → FAIL в
13-test-report.md - Issue остаётся In Progress → developer перезапущен для фикса
- Developer фиксит → reviewer → tester (повторно)
- Если 3 попытки developer'а не помогли → Issue → Blocked
- Telegram: "🚨 ET-012: Tests still failing after 3 retries"
🔴 Deploy fail
- Deployer мержит PR, деплоит, smoke test FAIL
- Deployer откатывает к предыдущему тегу
- Issue → Blocked
- Telegram: "🚨 ET-012: Deploy failed! Rolled back."
🔴 Architect conflict
- Architect находит конфликт с ТЗ → создаёт
10-conflict.md - Issue → In Progress → analyst перезапущен с описанием конфликта
- 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) делает:
git pull origin mainв репо проектаdocker compose up -d app— перезапуск app контейнера- Опционально:
docker compose --profile batch run --rm gps-collector(флаг--run-gps-collector) - Логирует всё в
/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: конвейер дошёл до стадии development→review и вскрыл цепочку багов 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_local → check_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_local→check_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 webhook — handle_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 webhook — handle_comment читает поле issue (Plane шлёт именно его) + comment_stripped |
| 2026-06-01 | Fix: ET-008 GPS-треки — pipeline завершён, v0.0.1 задеплоен, gps-collector запущен |