docs: lessons learned ET-006 — problems and solutions
This commit is contained in:
190
docs/LESSONS_ET006.md
Normal file
190
docs/LESSONS_ET006.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# Lessons Learned — ET-006 (GPX Upload & Visualization)
|
||||
|
||||
## Дата: 2026-05-22
|
||||
## Задача: ET-006 — Загрузка и визуализация GPX-треков
|
||||
|
||||
---
|
||||
|
||||
## Что сработало хорошо
|
||||
|
||||
### 1. Review bounce — реальный баг найден и исправлен автоматически
|
||||
Reviewer обнаружил P1: `Math.min.apply(null, array)` падает с RangeError на массивах >100K элементов.
|
||||
Developer пофиксил за 6 минут (attempt 2), второй review прошёл чисто.
|
||||
**Вывод:** reviewer в пайплайне оправдывает себя — ловит баги которые unit-тесты пропускают.
|
||||
|
||||
### 2. Auto-advance testing → deploy
|
||||
Новый `_try_advance_stage()` в launcher сработал без ручного вмешательства.
|
||||
|
||||
### 3. Качество артефактов агентов
|
||||
- Analyst предусмотрел REQ-F-13 (persist GPX layers при map style switch) — предотвратил архитектурный bounce-back
|
||||
- Architect обосновал невозможность Web Worker (DOMParser отсутствует в WorkerGlobalScope)
|
||||
- Developer: ~1300 строк production + 700 строк тестов, все REQ покрыты
|
||||
- Tester: полный e2e с Playwright, 48 pass / 0 fail
|
||||
|
||||
### 4. Полный цикл с bounce
|
||||
```
|
||||
analysis → architecture → development → review (REQUEST_CHANGES)
|
||||
→ development (fix P1) → review (APPROVED) → testing → deploy → done
|
||||
```
|
||||
Время: ~6.5 часов (включая ожидание API и e2e тесты)
|
||||
|
||||
---
|
||||
|
||||
## Проблемы найденные
|
||||
|
||||
### P1. Zombie processes после docker rebuild
|
||||
**Симптом:** Monitor threads умирают при `docker compose up --build`, agent процессы остаются zombie.
|
||||
**Влияние:** Ручное вмешательство для commit/push и advance stage.
|
||||
**Root cause:** Daemon threads в Python не переживают restart контейнера, но child processes (claude.exe) наследуются init (PID 1).
|
||||
|
||||
### P2. Stale reviews блокируют merge
|
||||
**Симптом:** Tester пушит коммит после review approval → approval становится stale → merge отклоняется.
|
||||
**Влияние:** Ручной re-approve перед каждым merge.
|
||||
**Root cause:** Branch protection `dismiss_stale_approvals: true`.
|
||||
|
||||
### P3. Plane sync 404
|
||||
**Симптом:** `plane_issue_id` в orchestrator DB не совпадает с реальным UUID issue в Plane API.
|
||||
**Влияние:** State updates в Plane не работают (comments работают).
|
||||
**Root cause:** Webhook payload содержит ID объекта webhook event, не issue ID.
|
||||
|
||||
### P4. Неполный event routing
|
||||
**Симптом:** `pull_request_rejected` event type не роутился в `handle_pr`.
|
||||
**Влияние:** REQUEST_CHANGES от reviewer не откатывал задачу автоматически.
|
||||
**Root cause:** Gitea использует разные event types: `pull_request`, `pull_request_approved`, `pull_request_rejected`.
|
||||
|
||||
### P5. Analyst не запускался автоматически
|
||||
**Симптом:** После создания задачи через Plane webhook analyst не стартовал.
|
||||
**Влияние:** Ручной запуск analyst.
|
||||
**Root cause:** В `handle_work_item_created` не было вызова `launcher.launch("analyst")`.
|
||||
|
||||
### P6. Tester долгий (25 мин)
|
||||
**Симптом:** Playwright e2e тесты с headless Chromium на GPX-фиче заняли 25 минут.
|
||||
**Влияние:** Долгое ожидание, watchdog timeout (30 мин) почти сработал.
|
||||
**Root cause:** Рендеринг 700K точек + установка зависимостей (Playwright, shapely) в runtime.
|
||||
|
||||
---
|
||||
|
||||
## Решения
|
||||
|
||||
### P1. Zombie processes → Entrypoint + orphan recovery
|
||||
|
||||
**Решение A (быстрое):** Добавить в Dockerfile:
|
||||
```dockerfile
|
||||
RUN git config --global --add safe.directory '*'
|
||||
```
|
||||
|
||||
**Решение B (полное):** Startup recovery в `main.py`:
|
||||
```python
|
||||
@app.on_event("startup")
|
||||
async def recover_orphaned_runs():
|
||||
"""Mark orphaned runs (started but never finished) as failed."""
|
||||
conn = get_db()
|
||||
orphans = conn.execute(
|
||||
"UPDATE agent_runs SET finished_at=datetime('now'), exit_code=-1 "
|
||||
"WHERE finished_at IS NULL AND started_at < datetime('now', '-35 minutes')"
|
||||
).rowcount
|
||||
conn.commit()
|
||||
if orphans:
|
||||
logger.warning(f"Recovered {orphans} orphaned agent runs")
|
||||
# Re-check tasks stuck in intermediate stages
|
||||
stuck = conn.execute(
|
||||
"SELECT id, stage, work_item_id, repo, branch FROM tasks "
|
||||
"WHERE stage NOT IN ('done', 'created')"
|
||||
).fetchall()
|
||||
for task in stuck:
|
||||
# Try to advance if QG passes
|
||||
...
|
||||
```
|
||||
|
||||
**Решение C (robust):** Использовать `tini` как PID 1 в контейнере для proper zombie reaping:
|
||||
```dockerfile
|
||||
RUN apt-get install -y tini
|
||||
ENTRYPOINT ["tini", "--"]
|
||||
CMD ["uvicorn", "src.main:app", ...]
|
||||
```
|
||||
|
||||
### P2. Stale reviews → Отключить dismiss или auto-re-approve
|
||||
|
||||
**Решение A (простое):** Отключить `dismiss_stale_approvals`:
|
||||
```bash
|
||||
curl -X PATCH '.../branch_protections/main' -d '{"dismiss_stale_approvals": false}'
|
||||
```
|
||||
|
||||
**Решение B (лучше):** Auto-re-approve в launcher после tester push:
|
||||
```python
|
||||
# В _monitor_agent, после успешного push для tester:
|
||||
if agent == "tester":
|
||||
_reapprove_pr(repo, branch)
|
||||
```
|
||||
|
||||
**Рекомендация:** Решение A — проще и безопаснее. В нашем пайплайне reviewer уже проверяет код, stale dismiss не добавляет ценности.
|
||||
|
||||
### P3. Plane sync → Исправить маппинг ID
|
||||
|
||||
**Решение:** При `work_item.created` webhook сохранять правильный `issue_id`:
|
||||
```python
|
||||
# В handle_work_item_created:
|
||||
plane_issue_id = data.get("id") # Это ID issue, не event
|
||||
# Проверить через Plane API: GET /issues/{id} — если 404, искать по name
|
||||
```
|
||||
|
||||
**Диагностика:** Сравнить `plane_issue_id` в DB с реальным через:
|
||||
```bash
|
||||
curl http://localhost:8091/api/v1/workspaces/ag_proj/projects/.../issues/?search=ET-006
|
||||
```
|
||||
|
||||
### P4. Event routing → Wildcard для pull_request_*
|
||||
|
||||
**Решение:**
|
||||
```python
|
||||
if event_type == "push":
|
||||
await handle_push(payload)
|
||||
elif event_type.startswith("pull_request"):
|
||||
await handle_pr(payload)
|
||||
elif event_type == "status":
|
||||
await handle_ci_status(payload)
|
||||
```
|
||||
|
||||
### P5. Analyst auto-launch → Уже исправлено
|
||||
Патч применён: `launcher.launch("analyst")` добавлен в `handle_work_item_created`.
|
||||
|
||||
### P6. Tester долгий → Pre-bake dependencies
|
||||
|
||||
**Решение A:** Добавить Playwright и зависимости в Dockerfile:
|
||||
```dockerfile
|
||||
RUN pip install playwright pytest-playwright shapely mapbox-vector-tile && \
|
||||
playwright install chromium --with-deps
|
||||
```
|
||||
|
||||
**Решение B:** Разделить unit/integration и e2e тесты. Unit/integration — обязательные (быстрые), e2e — опциональные (по флагу в task description).
|
||||
|
||||
**Решение C:** Увеличить timeout для tester до 45 минут:
|
||||
```python
|
||||
AGENT_CONFIGS = {
|
||||
"tester": {..., "timeout": 2700}, # 45 min
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Приоритет исправлений
|
||||
|
||||
| # | Проблема | Приоритет | Усилие | Решение |
|
||||
|---|----------|-----------|--------|---------|
|
||||
| P1 | Zombie processes | HIGH | Medium | tini + startup recovery |
|
||||
| P2 | Stale reviews | HIGH | Low | Отключить dismiss_stale_approvals |
|
||||
| P4 | Event routing | HIGH | Low | startswith("pull_request") |
|
||||
| P5 | Analyst auto-launch | DONE | — | Уже исправлено |
|
||||
| P6 | Tester timeout | MEDIUM | Medium | Pre-bake deps в Dockerfile |
|
||||
| P3 | Plane sync 404 | LOW | Medium | Исправить маппинг ID |
|
||||
|
||||
---
|
||||
|
||||
## Метрики ET-006
|
||||
|
||||
- **Общее время:** ~6.5 часов (00:20 → 06:45 UTC)
|
||||
- **Agent runs:** 7 (analyst, architect, developer×2, reviewer×2, tester)
|
||||
- **Ручные вмешательства:** 4 (zombie recovery×2, PR approve, event re-trigger)
|
||||
- **Код написан агентами:** ~2000 строк (1300 production + 700 tests)
|
||||
- **Баги найдены reviewer:** 1×P1, 3×P2, 6×P3
|
||||
- **Баги исправлены developer:** все P1 + все P2 + 3×P3
|
||||
Reference in New Issue
Block a user