408 lines
31 KiB
Markdown
408 lines
31 KiB
Markdown
# Документация: 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_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)
|
||
|
||
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 на хост:
|
||
```bash
|
||
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: конвейер дошёл до стадии `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 запущен |
|