diff --git a/memory/.dreams/events.jsonl b/memory/.dreams/events.jsonl
index 2bc1733..e840e74 100644
--- a/memory/.dreams/events.jsonl
+++ b/memory/.dreams/events.jsonl
@@ -17,3 +17,4 @@
{"type":"memory.recall.recorded","timestamp":"2026-05-06T04:34:46.669Z","query":"enduro trails статус текущая фаза","resultCount":1,"results":[{"path":"memory/2026-05-04.md","startLine":1,"endLine":30,"score":0.36225839555263517}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-06T04:34:51.648Z","query":"enduro trails фаза 5 последнее что делали","resultCount":1,"results":[{"path":"memory/2026-05-04.md","startLine":1,"endLine":30,"score":0.35838418304920194}]}
{"type":"memory.recall.recorded","timestamp":"2026-05-08T11:29:28.323Z","query":"OpenClaw offline","resultCount":1,"results":[{"path":"memory/2026-03-21.md","startLine":27,"endLine":57,"score":0.35461454987525937}]}
+{"type":"memory.recall.recorded","timestamp":"2026-05-11T08:41:48.539Z","query":"enduro trails","resultCount":8,"results":[{"path":"memory/2026-05-03.md","startLine":1,"endLine":36,"score":0.5520287429057207},{"path":"memory/2026-05-02.md","startLine":107,"endLine":142,"score":0.5344992920917779},{"path":"memory/2026-05-04.md","startLine":1,"endLine":30,"score":0.5180976709974037},{"path":"memory/2026-05-02.md","startLine":1,"endLine":36,"score":0.5013019898600938},{"path":"memory/2026-05-02.md","startLine":168,"endLine":201,"score":0.4983071022156733},{"path":"memory/2026-05-02.md","startLine":86,"endLine":117,"score":0.49651338994897687},{"path":"memory/2026-05-02.md","startLine":196,"endLine":227,"score":0.48154737169778283},{"path":"memory/2026-05-02.md","startLine":217,"endLine":251,"score":0.479680287886423}]}
diff --git a/memory/.dreams/short-term-recall.json b/memory/.dreams/short-term-recall.json
index 6fef889..106b139 100644
--- a/memory/.dreams/short-term-recall.json
+++ b/memory/.dreams/short-term-recall.json
@@ -1,6 +1,6 @@
{
"version": 1,
- "updatedAt": "2026-05-08T11:29:28.323Z",
+ "updatedAt": "2026-05-11T08:41:48.539Z",
"entries": {
"memory:memory/2026-04-05.md:29:55": {
"key": "memory:memory/2026-04-05.md:29:55",
@@ -632,18 +632,20 @@
"endLine": 142,
"source": "memory",
"snippet": "- [ ] Обновить онтологию для проекта enduro-trails ## Enduro Trails — ревью прототипа (12:53 UTC) - Слава попросил ревью — после серии горячих фиксов (clip_by_rect, y_coord_down, swap lat/lon) код запутан - TODO: провести полное ревью app.py и index.html # 2026-05-02 — Дневник ## Enduro Trails — отладка прототипа (утро) ### Что делали Долгая отладка карты грунтовок ЦФО на http://82.22.50.71:5558 ### Проблемы и решения #### 1. style.json не грузился (404 на /static/style.json) - Путь в index.html был `/static/style.json`, а сервер отдаёт `/style.json` - Исправлено: путь исправлен на `/style.json` #### 2. Шрифты — demotiles.maplibre.org отдавал 404 - MapLibre зависал при инициализации -",
- "recallCount": 1,
+ "recallCount": 2,
"dailyCount": 0,
"groundedCount": 0,
- "totalScore": 0.375397714972496,
- "maxScore": 0.375397714972496,
+ "totalScore": 0.909897007064274,
+ "maxScore": 0.5344992920917779,
"firstRecalledAt": "2026-05-04T06:57:05.721Z",
- "lastRecalledAt": "2026-05-04T06:57:05.721Z",
+ "lastRecalledAt": "2026-05-11T08:41:48.539Z",
"queryHashes": [
- "af0cb8f00b60"
+ "af0cb8f00b60",
+ "1feee93c2d26"
],
"recallDays": [
- "2026-05-04"
+ "2026-05-04",
+ "2026-05-11"
],
"conceptTags": [
"enduro-trails",
@@ -663,18 +665,20 @@
"endLine": 117,
"source": "memory",
"snippet": "- \"Опять пляшут\" / \"Ещё как прыгают!!!\" — подтверждение что проблема не решена - Ключевое наблюдение Славы: **\"Треки же отражают дорогу, почему они смещаются\"** — треки из OSM должны идеально ложиться на OSM подложку ### Диагностика - Удаление `clip_by_rect` НЕ помогло — треки продолжали прыгать - Причина: без клиппинга геометрия выходит за `quantize_bounds`, координаты >4096 ломают MapLibre - **Найден корневой баг**: в WKB геометрии из БД координаты хранятся как `(lat, lon)`, а `wkb_to_coords()` читала их как `(lon, lat)`. Широта и долгота были перепутаны! ### Фикс (12:07 UTC) - В `wkb_to_coords()`: `lat, lon = struct.unpack_from('
4096 ломают MapLibre - **Найден корневой баг**: в WKB геометрии из БД координаты хранятся как `(lat, lon)`, а `wkb_to_coords()` читала их как `(lon, lat)`. Широта и долгота были перепутаны! ### Фикс (12:07 UTC) - В `wkb_",
+ "recallCount": 1,
+ "dailyCount": 0,
+ "groundedCount": 0,
+ "totalScore": 0.48154737169778283,
+ "maxScore": 0.48154737169778283,
+ "firstRecalledAt": "2026-05-11T08:41:48.539Z",
+ "lastRecalledAt": "2026-05-11T08:41:48.539Z",
+ "queryHashes": [
+ "1feee93c2d26"
+ ],
+ "recallDays": [
+ "2026-05-11"
+ ],
+ "conceptTags": [
+ "z12.4",
+ "z11.8/12.0",
+ "clip-by-rect",
+ "quantize-bounds",
+ "wkb-to-coords",
+ "скриншоты",
+ "славы",
+ "прислал"
+ ]
+ },
+ "memory:memory/2026-05-02.md:217:251": {
+ "key": "memory:memory/2026-05-02.md:217:251",
+ "path": "memory/2026-05-02.md",
+ "startLine": 217,
+ "endLine": 251,
+ "source": "memory",
+ "snippet": "- [ ] Синхронизировать app.py с workspace: `tasks/enduro-trails/prototype/app.py` - [ ] Обновить PROJECT.md и TASK.md для enduro-trails - [ ] Обновить онтологию для проекта enduro-trails ## Enduro Trails — ревью прототипа (12:53 UTC) - Слава попросил ревью — после серии горячих фиксов (clip_by_rect, y_coord_down, swap lat/lon) код запутан - TODO: провести полное ревью app.py и index.html --- ## Enduro Trails — полное ревью и план восстановления (13:07–13:57 UTC) ### Что сделано - Прочитаны все файлы прототипа: `app.py` (из контейнера), `docker-compose.yml`, `static/index.html`, `static/style.json`, `scripts/parse.py`, `scripts/download.sh` - Прочитаны требования: `TECHNICAL_SPEC.md`, `C",
+ "recallCount": 1,
+ "dailyCount": 0,
+ "groundedCount": 0,
+ "totalScore": 0.479680287886423,
+ "maxScore": 0.479680287886423,
+ "firstRecalledAt": "2026-05-11T08:41:48.539Z",
+ "lastRecalledAt": "2026-05-11T08:41:48.539Z",
+ "queryHashes": [
+ "1feee93c2d26"
+ ],
+ "recallDays": [
+ "2026-05-11"
+ ],
+ "conceptTags": [
+ "app.py",
+ "project.md",
+ "task.md",
+ "enduro-trails",
+ "clip-by-rect",
+ "y-coord-down",
+ "lat/lon",
+ "index.html"
+ ]
}
}
}
diff --git a/tasks/enduro-trails/TEST_CASES_TERRAIN.md b/tasks/enduro-trails/TEST_CASES_TERRAIN.md
new file mode 100644
index 0000000..01561c1
--- /dev/null
+++ b/tasks/enduro-trails/TEST_CASES_TERRAIN.md
@@ -0,0 +1,257 @@
+# Тест-кейсы: Рельеф (Terrain Layer) — Фаза 5.4
+
+**Дата:** 2026-05-11
+**Версия BRD:** BRD_TERRAIN.md
+**Исполнители:** Dev (автотесты + деплой), Стрим (ручная проверка), Слава (финальная приёмка)
+
+---
+
+## Распределение
+
+| Кто | Что |
+|-----|-----|
+| 🤖 Dev | TC-01..TC-06 — данные и деплой (автоматически, в процессе реализации) |
+| 🌊 Стрим | TC-07..TC-22 — ручная проверка через браузер/curl после деплоя |
+| 👤 Слава | Финальная приёмка — только после «✅ Всё зелёное» от Стрим |
+
+---
+
+## Блок 1: Данные и инфраструктура (Dev)
+
+### TC-01 — SRTM тайлы скачаны
+**Исполнитель:** Dev
+**Проверка:**
+```bash
+ls /home/slin/enduro-trails/data/srtm/*.hgt | wc -l
+# Ожидаемо: >= 30 файлов
+```
+**Ожидаемый результат:** ≥30 `.hgt` файлов в директории
+
+---
+
+### TC-02 — Тайлы hypso сгенерированы
+**Исполнитель:** Dev
+**Проверка:**
+```bash
+find /home/slin/enduro-trails/data/terrain/hypso -name "*.png" | wc -l
+# Ожидаемо: > 1000 файлов (зумы 5-15)
+```
+**Ожидаемый результат:** PNG тайлы присутствуют для зумов 5-15
+
+---
+
+### TC-03 — Тайлы hillshade сгенерированы
+**Исполнитель:** Dev
+**Проверка:**
+```bash
+find /home/slin/enduro-trails/data/terrain/hillshade -name "*.png" | wc -l
+# Ожидаемо: > 500 файлов (зумы 10-15)
+```
+**Ожидаемый результат:** PNG тайлы присутствуют для зумов 10-15
+
+---
+
+### TC-04 — Тайл hypso доступен через nginx
+**Исполнитель:** Dev
+**Проверка:**
+```bash
+curl -o /dev/null -s -w "%{http_code}" \
+ "https://openclaw.mva154.duckdns.org/enduro/terrain/hypso/8/75/42.png"
+# Ожидаемо: 200
+```
+**Ожидаемый результат:** HTTP 200, Content-Type: image/png
+
+---
+
+### TC-05 — Тайл hillshade доступен через nginx
+**Исполнитель:** Dev
+**Проверка:**
+```bash
+curl -o /dev/null -s -w "%{http_code}" \
+ "https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/12/2400/1340.png"
+# Ожидаемо: 200
+```
+**Ожидаемый результат:** HTTP 200, Content-Type: image/png
+
+---
+
+### TC-06 — Cache-Control заголовок
+**Исполнитель:** Dev
+**Проверка:**
+```bash
+curl -I "https://openclaw.mva154.duckdns.org/enduro/terrain/hypso/8/75/42.png" \
+ | grep -i cache-control
+# Ожидаемо: Cache-Control: public, immutable
+```
+**Ожидаемый результат:** `Cache-Control: public, immutable` в заголовках
+
+---
+
+## Блок 2: Фронтенд — кнопка и попап (Стрим)
+
+### TC-07 — Кнопка 🏔️ присутствует в toolbar
+**Исполнитель:** Стрим
+**Шаги:** Открыть https://openclaw.mva154.duckdns.org/enduro/
+**Ожидаемый результат:** Кнопка 🏔️ видна в toolbar, после кнопки слоёв, перед линейкой
+**Проверка:** `curl` + grep по `terrain-toggle` в HTML
+
+---
+
+### TC-08 — Попап открывается по нажатию
+**Исполнитель:** Стрим
+**Шаги:** Нажать кнопку 🏔️
+**Ожидаемый результат:** Появляется попап с двумя чекбоксами «Цветной рельеф» и «Теневой рельеф»
+
+---
+
+### TC-09 — Попап закрывается повторным нажатием
+**Исполнитель:** Стрим
+**Шаги:** Нажать 🏔️ → попап открылся → нажать 🏔️ снова
+**Ожидаемый результат:** Попап закрылся
+
+---
+
+### TC-10 — Попап закрывается по тапу вне
+**Исполнитель:** Стрим
+**Шаги:** Открыть попап → кликнуть на карту
+**Ожидаемый результат:** Попап закрылся
+
+---
+
+### TC-11 — Теневой чекбокс disabled на малом зуме
+**Исполнитель:** Стрим
+**Шаги:** Зум 8 → открыть попап
+**Ожидаемый результат:** Чекбокс «Теневой рельеф» серый (disabled), видна подпись «Доступно при приближении»
+
+---
+
+### TC-12 — Теневой чекбокс enabled на зуме 10+
+**Исполнитель:** Стрим
+**Шаги:** Зум 10 → открыть попап
+**Ожидаемый результат:** Чекбокс «Теневой рельеф» активен, подпись скрыта
+
+---
+
+## Блок 3: Слои на карте (Стрим)
+
+### TC-13 — Цветной рельеф включается
+**Исполнитель:** Стрим
+**Шаги:** Зум 6 → 🏔️ → включить «Цветной рельеф»
+**Ожидаемый результат:** На карте появляется цветная заливка рельефа (зелёный/жёлтый/коричневый)
+
+---
+
+### TC-14 — Цветной рельеф выключается
+**Исполнитель:** Стрим
+**Шаги:** Включить → выключить «Цветной рельеф»
+**Ожидаемый результат:** Цветная заливка исчезает, карта как была
+
+---
+
+### TC-15 — Теневой рельеф включается на зуме 12
+**Исполнитель:** Стрим
+**Шаги:** Зум 12 → 🏔️ → включить «Теневой рельеф»
+**Ожидаемый результат:** Появляются тени на склонах и оврагах
+
+---
+
+### TC-16 — Теневой рельеф не виден на зуме < 10 даже если включён
+**Исполнитель:** Стрим
+**Шаги:** Включить «Теневой» на зуме 12 → отзумить до зума 8
+**Ожидаемый результат:** Тени исчезают (слой скрыт), чекбокс остаётся checked
+
+---
+
+### TC-17 — Теневой рельеф возвращается при приближении
+**Исполнитель:** Стрим
+**Шаги:** Продолжение TC-16 → зумить обратно до 10+
+**Ожидаемый результат:** Тени снова появляются (чекбокс был checked)
+
+---
+
+### TC-18 — Оба слоя одновременно
+**Исполнитель:** Стрим
+**Шаги:** Зум 12 → включить оба чекбокса
+**Ожидаемый результат:** Видны и цвет рельефа, и тени поверх. Дороги видны поверх рельефа.
+
+---
+
+### TC-19 — Рельеф под дорогами (z-index)
+**Исполнитель:** Стрим
+**Шаги:** Включить оба слоя, зум 12
+**Ожидаемый результат:** Дороги и треки видны поверх рельефа, не перекрываются
+
+---
+
+### TC-20 — Кнопка подсвечивается при активном слое
+**Исполнитель:** Стрим
+**Шаги:** Включить хотя бы один слой
+**Ожидаемый результат:** Кнопка 🏔️ подсвечена (класс `active`)
+
+---
+
+### TC-21 — Кнопка не подсвечена когда оба выключены
+**Исполнитель:** Стрим
+**Шаги:** Выключить оба слоя
+**Ожидаемый результат:** Кнопка 🏔️ без подсветки
+
+---
+
+## Блок 4: Персистентность (Стрим)
+
+### TC-22 — Состояние сохраняется после перезагрузки
+**Исполнитель:** Стрим
+**Шаги:**
+1. Включить «Цветной рельеф», выключить «Теневой»
+2. Перезагрузить страницу (F5)
+**Ожидаемый результат:** «Цветной» включён, «Теневой» выключен — как было до перезагрузки
+
+---
+
+### TC-23 — Оба выключены после перезагрузки (дефолт)
+**Исполнитель:** Стрим
+**Шаги:** Выключить оба → перезагрузить
+**Ожидаемый результат:** Оба чекбокса сняты, слои не видны
+
+---
+
+## Блок 5: Мобильный (Стрим — через DevTools mobile emulation)
+
+### TC-24 — Попап не перекрывает кнопки на мобильном
+**Исполнитель:** Стрим
+**Шаги:** DevTools → iPhone 14 → открыть попап
+**Ожидаемый результат:** Попап виден полностью, не перекрывает toolbar и кнопки масштаба
+
+---
+
+### TC-25 — Тап вне попапа закрывает его на мобильном
+**Исполнитель:** Стрим
+**Шаги:** Мобильная эмуляция → открыть попап → тапнуть на карту
+**Ожидаемый результат:** Попап закрылся
+
+---
+
+## Итого
+
+| Блок | Тест-кейсов | Исполнитель |
+|------|-------------|-------------|
+| 1. Данные и инфраструктура | TC-01..TC-06 (6 шт) | 🤖 Dev |
+| 2. Кнопка и попап | TC-07..TC-12 (6 шт) | 🌊 Стрим |
+| 3. Слои на карте | TC-13..TC-21 (9 шт) | 🌊 Стрим |
+| 4. Персистентность | TC-22..TC-23 (2 шт) | 🌊 Стрим |
+| 5. Мобильный | TC-24..TC-25 (2 шт) | 🌊 Стрим |
+| **Итого** | **25 тест-кейсов** | |
+
+---
+
+## Порядок работы
+
+```
+Dev реализует → деплоит → сообщает Стрим
+ ↓
+Стрим прогоняет TC-07..TC-25 (ручные)
+ ↓
+Баги → Dev фиксит → Стрим перепроверяет
+ ↓
+Всё зелёное → Стрим даёт отмашку Славе
+```