From ab569eae10824e1ec4e5dc643881bd2c0451b196 Mon Sep 17 00:00:00 2001 From: Stream Date: Mon, 4 May 2026 11:40:01 +0300 Subject: [PATCH] auto-sync: 2026-05-04 11:40:01 --- installer/registry.jsonl | 2 + tasks/enduro-trails/prototype/app.py | 27 +++++++ tasks/enduro-trails/prototype/static/app.js | 1 + .../reports/dev-2026-05-04-phase3-bugfix.md | 75 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 tasks/enduro-trails/reports/dev-2026-05-04-phase3-bugfix.md diff --git a/installer/registry.jsonl b/installer/registry.jsonl index 4ac06b8..4350473 100644 --- a/installer/registry.jsonl +++ b/installer/registry.jsonl @@ -18,3 +18,5 @@ {"ts":"2026-05-02T20:19:00Z","session":"20260502-201802_mva154_enduro-zoom-consistency_7250","host":"mva154","status":"success","agent":"stream","files":["/home/slin/openclaw/config/tasks/enduro-trails/prototype/app.py"]} {"ts":"2026-05-03T05:17:34Z","session":"20260503-051453_mva154_nginx-enduro-location_3cee","host":"mva154","status":"success","agent":"stream","files":["/etc/nginx/sites-enabled/openclaw.mva154.duckdns.org"]} {"ts":"2026-05-03T18:17:28Z","session":"20260503-051453_mva154_nginx-enduro-location_3cee","host":"mva154","status":"success","agent":"stream","files":["/etc/nginx/sites-enabled/openclaw.mva154.duckdns.org"]} +{"ts":"2026-05-04T08:32:10Z","action":"cleanup","deleted_orphaned_sessions":0,"deleted_logs":0,"retention_days":30} +{"ts":"2026-05-04T08:37:04Z","session":"20260504-083250_mva154_enduro-phase3-bugfix_d0a2","host":"mva154","status":"success","agent":"dev","files":["/home/slin/enduro-trails/prototype/app.py","/home/slin/enduro-trails/prototype/static/app.js"]} diff --git a/tasks/enduro-trails/prototype/app.py b/tasks/enduro-trails/prototype/app.py index fde7041..8edec22 100644 --- a/tasks/enduro-trails/prototype/app.py +++ b/tasks/enduro-trails/prototype/app.py @@ -497,6 +497,33 @@ async def post_route(req: RouteRequest): except Exception as e: raise HTTPException(503, f"OSRM недоступен: {e}") + # OSRM возвращает TooBig когда маршрут слишком длинный для N альтернатив + if data.get("code") == "TooBig": + # Пробуем с меньшим числом альтернатив + url_retry3 = ( + f"{OSRM_URL}/route/v1/driving/{coords_str}" + f"?alternatives=3&overview=full&geometries=geojson&annotations=false" + ) + try: + async with httpx.AsyncClient(timeout=30) as client: + resp = await client.get(url_retry3) + data = resp.json() + except Exception as e: + raise HTTPException(503, f"OSRM недоступен: {e}") + + if data.get("code") == "TooBig": + # Всё ещё TooBig — пробуем совсем без альтернатив + url_retry1 = ( + f"{OSRM_URL}/route/v1/driving/{coords_str}" + f"?overview=full&geometries=geojson&alternatives=false" + ) + try: + async with httpx.AsyncClient(timeout=30) as client: + resp = await client.get(url_retry1) + data = resp.json() + except Exception as e: + raise HTTPException(503, f"OSRM недоступен: {e}") + if data.get("code") != "Ok" or not data.get("routes"): raise HTTPException(404, "Маршрут не найден") diff --git a/tasks/enduro-trails/prototype/static/app.js b/tasks/enduro-trails/prototype/static/app.js index 9396f27..615c9f9 100644 --- a/tasks/enduro-trails/prototype/static/app.js +++ b/tasks/enduro-trails/prototype/static/app.js @@ -7,6 +7,7 @@ function formatDuration(seconds) { const hours = Math.floor((totalMin % 1440) / 60); const mins = totalMin % 60; if (days > 0) { + if (hours === 0 && mins === 0) return `${days} дн`; if (mins === 0) return `${days} дн ${hours} ч`; return `${days} дн ${hours} ч ${mins} мин`; } diff --git a/tasks/enduro-trails/reports/dev-2026-05-04-phase3-bugfix.md b/tasks/enduro-trails/reports/dev-2026-05-04-phase3-bugfix.md new file mode 100644 index 0000000..5781ecf --- /dev/null +++ b/tasks/enduro-trails/reports/dev-2026-05-04-phase3-bugfix.md @@ -0,0 +1,75 @@ +# Dev Report: Enduro Trails Фаза 3 — Bugfix +Дата: 2026-05-04 +Статус: DONE + +## Задача +Исправить 2 бага в Enduro Trails Фаза 3: +1. app.py: OSRM возвращает `code: "TooBig"` при `alternatives=5` → 404 +2. app.js: `formatDuration(86400)` → `"1 дн 0 ч"` вместо `"1 дн"` + +## Сделано +- [x] Прочитал app.py и app.js +- [x] Баг 1: добавил retry-логику в POST `/api/route` — сначала `alternatives=3`, затем `alternatives=false` +- [x] Баг 2: исправил ветку `days > 0` в `formatDuration` — добавил проверку `hours === 0 && mins === 0` +- [x] Обновил файлы в workspace +- [x] Задеплоил через Node.js ssh2 (SSH бинарник не работает из контейнера — GLIBC mismatch) +- [x] Обнаружил что контейнер собран из образа (не bind-mount) → использовал `docker cp` для копирования файлов в контейнер +- [x] Перезапустил контейнер (`docker compose restart`) +- [x] Проверил что фикс выжил после рестарта (TooBig: 4 вхождения в контейнере) +- [x] Прогнал тест — маршрут возвращается, pct sum = 100 + +## Изменённые файлы +- `workspace/tasks/enduro-trails/prototype/app.py` — retry-логика TooBig (строки ~500-525) +- `workspace/tasks/enduro-trails/prototype/static/app.js` — formatDuration fix + +## Результат + +### Баг 1 — TooBig fix +OSRM на mva154 имеет максимум 3 альтернативы (не 5). Любой запрос с `alternatives=5` возвращает `TooBig`. +Retry-цепочка: `alternatives=5` → TooBig → `alternatives=3` → если снова TooBig → `alternatives=false`. + +Тест короткого маршрута (37.6184,55.7512 → 37.8,55.85): +``` +routes count: 3 +distance_m: 18858 +pct sum: 100 OK +``` + +Тест длинного маршрута ~127км (37.6184,55.7512 → 36.7,56.3): +``` +routes count: 1 +distance_m: 127088 +pct sum: 100 OK +``` + +### Баг 2 — formatDuration fix +``` +formatDuration(86400): "1 дн" ✅ (было "1 дн 0 ч") +formatDuration(90000): "1 дн 1 ч" ✅ +formatDuration(93600): "1 дн 2 ч" ✅ +``` + +## Проблемы и решения + +### SSH бинарник не работает из контейнера +GLIBC mismatch: `ssh: /lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.38' not found` +→ Решение: Node.js скрипт с npm `ssh2` для всех SSH операций. + +### Stale lock на mva154 +Осталась незавершённая сессия от 2026-05-03 (add-swap-4g). PID 78077 мёртв. +→ Решение: удалил lock directory вручную, создал новую сессию. + +### Контейнер собран из образа (не bind-mount) +`docker compose restart` перезапускает контейнер из существующего образа — файлы на хосте не попадают внутрь. +→ Решение: `docker cp` для копирования файлов прямо в работающий контейнер, затем restart. +→ Урок: при следующем деплое либо добавить bind-mount в docker-compose.yml, либо делать `docker compose build && docker compose up -d`. + +## Следующий шаг +Для постоянного решения — добавить bind-mount в docker-compose.yml: +```yaml +volumes: + - /home/slin/enduro-trails/data:/data + - /home/slin/enduro-trails/prototype/app.py:/app/app.py + - /home/slin/enduro-trails/prototype/static:/app/static +``` +Тогда деплой = просто скопировать файл на хост + `docker compose restart`.