From 2eaa561892f289b4383f136761c624005149345d Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 23 Jun 2026 14:23:34 +0300 Subject: [PATCH] =?UTF-8?q?docs(domain=20I):=20v2=20=E2=80=94=20=D0=BD?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=B3=D0=B0=D1=86=D0=B8=D1=8F=20(offline=20O?= =?UTF-8?q?SM/=D1=80=D0=BE=D1=83=D1=82=D0=B8=D0=BD=D0=B3/turn-by-turn),=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20adversarial-=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D1=8C=D1=8E=20(24=20=D0=BD=D0=B0=D1=85=D0=BE=D0=B4=D0=BA=D0=B8?= =?UTF-8?q?)=20+=20=D0=BA=D1=80=D0=BE=D1=81=D1=81-=D0=B4=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Последний домен. Offline-first навигация: OSM-карты (MapLibre GL Native), оффлайн-роутинг (Valhalla), turn-by-turn, поиск/POI, связка с ассистентом. Не safety/ADAS (#1). Фаза v4. Многоагентный adversarial-ревью: 28 находок, 24 подтверждены (default-refute), все применены. Ключевое из ревью: - stale нав-промпт под звонком (проигрался бы ПОСЛЕ поворота) → продюсер I снимает заявку по окну релевантности; H остаётся контент-агностичным. - Нет секции отказ-путей → добавлена (no-route/geocoder-fail/битые-тайлы/ENOSPC, симметрично J/H/L). - Маршрут через границу регионов / назначение в нескачанном регионе → детект покрытия + предложение докачать / маршрут до края. - reroute-шторм в urban-canyon → детект схода с гистерезисом + HDOP/FixQuality-гейт; dead_reckoning трактуется как нет-фикса. - Якорь RDS-TMC G §7 → H §7 (FM-радио живёт в медиа-тракте H, не в сетевом G). - MapLibre Native = BSD-2-Clause (не BSD-3); ODbL-атрибуция (#12); единицы км/мили из локали (data-model §4, #10). - Интент «домой» разведён: D §6 = домашний экран (v1), навигация-домой = Nav-интент (v4). - Добавлены секции Зависимости и last-parked (K §2/L §5 ждали); Boot-Stage 2; speed-limit — пассивный бейдж, не предупреждение (#1). Кросс-док: d-assistant §6 («домой» = домашний экран; навигация-домой → Nav v4). (architecture §3/§6 уже содержат Nav; a-base apps-storage уже покрывает нав-PII.) Co-Authored-By: Claude Opus 4.8 --- docs/domains/d-assistant.md | 3 +- docs/domains/i-navigation.md | 232 +++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 docs/domains/i-navigation.md diff --git a/docs/domains/d-assistant.md b/docs/domains/d-assistant.md index 2958e87..2b84982 100644 --- a/docs/domains/d-assistant.md +++ b/docs/domains/d-assistant.md @@ -100,7 +100,8 @@ intent router · LLM backend (pluggable) · TTS (Silero, офлайн). ## 6. Интенты (routing) -- **Локальные латентно-критичные** (громче, домой, отмена) — без LLM, мгновенно. +- **Локальные латентно-критичные** (громче, **домой** = домашний экран/лаунчер, отмена) — без LLM, мгновенно. + *(Навигация-домой «поехали домой» — отдельный Nav-интент: матч фразы здесь, резолв+исполнение в I §9, v4.)* - **Свободный диалог / объяснения** — LLM (с контекстом машины + памятью). - **Plugin-интенты** — dispatch в `IntentHandler` плагина; коллизии разрешаются по политике [plugin-sdk](../contracts/plugin-sdk.md) §5; LLM-роутер — арбитр по контексту. diff --git a/docs/domains/i-navigation.md b/docs/domains/i-navigation.md new file mode 100644 index 0000000..010c341 --- /dev/null +++ b/docs/domains/i-navigation.md @@ -0,0 +1,232 @@ +# Домен I — Навигация + +> Офлайн-навигация: карты OSM, оффлайн-роутинг, turn-by-turn, поиск/POI, связка с ассистентом. +> **Offline-first** (#3 — карта не теряется в тоннеле/глуши). First-party ап на SDK; богатая +> карта-поверхность. Не safety/ADAS (#1). Поздний слой — **v4** (vision-лестница: нав+образ+ретрофит). + +Статус: **v2 (на ревью).** v2 — после adversarial-ревью (24 находки). +Связано с: [tech-stack.md](../tech-stack.md) (Карты: MapLibre + Valhalla/OSRM) · [architecture.md](../architecture.md) (§3 Nav — first-party, §6 boot Stage 2) · [ipc.md](../contracts/ipc.md) (`Nav`, `Location`) · [data-model.md](../contracts/data-model.md) (§4 единицы — конвертация на презентации) · домены **K** (§2 `Location`/FixQuality/zero-clamp, §3 руль, §4 IMU-опц., §10 DR), **H** (§3 роль `nav_guidance`, **§7 RDS-TMC задел**), **D** (§6 интенты, §2 TTS), **C** (§4 слоты, §6 тема, §7 distraction), **E** (§2 OBD-скорость v2), **G** (§2 онлайн/State/metered), **A** (§3 fscrypt/хранилище, §10 износ, §12 reset), **L** (§5/§7 обновление карт/синк), **B** (§4/§7 lifecycle) · [security-privacy.md](../contracts/security-privacy.md) (§3 `location`, §5 while-in-use, §7 приватность) · [principles.md](../principles.md) (#1,#3,#6,#8,#10,#11,#12,#13) + +--- + +## 1. Назначение и границы + +- **Что делает:** офлайн-карты + оффлайн-роутинг + turn-by-turn + поиск/POI + ввод назначения; связка с D и H. +- **Offline-first (#3) — определяющее:** карта/роутинг/ведение работают **без сети**; онлайн (трафик/поиск) — опц. улучшение. +- **Границы:** + - **Не safety/ADAS (#1):** ведёт, не управляет; никаких lane-keeping/ACC/регуляторных claim'ов. + - **Speed-limit display (OSM `maxspeed`):** если в скоупе — **строго пассивный инфо-бейдж** текущего сегмента, + **БЕЗ детекта/звукового предупреждения о превышении** (это warning/ADAS-зона — красная линия #1); камеры + контроля скорости/red-light — вне скоупа. Данные `maxspeed` неравномерны → риск ложного claim'а (§18). + - **Не источник позиции:** GPS/положение — у **K** (`Location`); I — потребитель + map-matching. + - **Не источник trip-данных машины:** пробег/средний расход (trip-производные) — trip-плагин (E §2, plugin-sdk §8); + мгновенный расход — core E. I считает только свои **нав-метрики** (ETA/дистанция). + - **Provider-agnostic роутинг (#8):** движок сменный за единым интерфейсом. +- **Plane:** карта — **Wayland-поверхность** (GPU) в слоте Shell (C §4); control — D-Bus (`Nav`); голос — PipeWire (`nav_guidance` H §3). +- **Фаза:** v4 (вся; онлайн-улучшения — later). + +## 2. Карты: данные, формат, хранилище, лицензия + +- **Источник — OpenStreetMap.** 🟡 **Лицензия ODbL** (OSM-данные): обязательна **атрибуция** «© OpenStreetMap + contributors» (в UI карты + «о картах»); share-alike — на **производную базу** (не на наш MIT-код), данные-актив + отдельно от кода (#12). → §18. +- **Формат:** **векторные тайлы** (MapLibre) — **PMTiles** (один файл/регион, offline) или MBTiles; роутинг-граф — + тайлы движка (§4). Сборка: OSM-экстракт (регион) → tilemaker/planetiler + Valhalla-тайлы. +- **Регионы по запросу:** качаем только нужные (РФ целиком — единицы–десятки ГБ), не весь планет. +- **Версионная когерентность:** **map-snapshot региона = когерентная пара** рендер-тайлов (PMTiles) + роутинг-тайлов + **одной OSM-версии**; оба набора версионируются и **заменяются атомарно вместе** (запрет смешения версий → иначе + геометрический рассинхрон рендер↔роутинг; ср. version-coherence L §6/§7). +- **Хранилище:** карты — крупный **read-mostly** актив; **отдельный носитель/раздел или `/data`** (a-base §3; износ + минимален — чтение, a-base §10). 🟡 размещение (§18). +- **Обновление:** периодическое, через **канал L §5/§7** (контент, не прошивка A) или ручная загрузка по `Connectivity` + (G §2, metered/online-гейт). **Атомарная замена региона** (не рвать активный маршрут — §13). + +## 3. Рендеринг карты + +- **MapLibre GL Native** (**BSD-2-Clause**, #12; NB: MapLibre GL **JS** — BSD-3, это другой слой) — векторные тайлы, + GPU-рендер через **Mesa/Panfrost** (RK3588), Wayland-поверхность в слоте Shell (C §4, slot-протокол). Плавность (#11) — GPU. +- **Тема день/ночь** — map-style-токены, синхронно с темой C §6 (по времени → GPS-восход K). +- **Виды:** 2D/3D, north-up/heading-up; маркер позиции (snap-to-road §7); оверлей маршрута + next-maneuver. +- На стоянке/без маршрута — свободный просмотр; в движении — гейтится distraction (владелец **C §7**; детали — §10). + +## 4. Роутинг (offline) + +- **Движок 🟡:** **Valhalla** (рек. — MIT, тайловый, on-device, costing) vs **OSRM** (BSD, быстрый, тяжёлый + препроцессинг/RAM). Provider-agnostic (#8). → §18. +- **Что даёт:** маршрут A→B (+ промежуточные), **ETA/дистанция**, профиль, **rerouting** при сходе (§7), альтернативы. +- **Покрытие регионами (важно для региональной нарезки §2):** назначение/коридор **вне загруженных тайлов** — + **детектируется**: при сети — предложение докачать регион (канал §2, metered/online-гейт G §2); офлайн/регион + недоступен — маршрут до **края покрытия** с явной пометкой «дальше карта не загружена», не тихий обрыв графа. + Геокодер (§6) для адреса вне загруженных регионов возвращает статус «вне загруженных карт», не пустой результат. +- **No-route-found** (недостижимо / точка вне графа / разрыв покрытия / отсечено costing) — **явный отказ-исход** + (§12), `NavigateTo` → `RouteNotFound`/`RouteActive=false` (§14), не зависание. +- **Дисциплина детекта схода (анти-reroute-шторм):** off-route объявляется только при **устойчивом** отклонении + > порога в течение N фиксов **И** при приемлемом `HDOP`/`FixQuality` (K §2; высокий HDOP / только `fix_2d` → + удерживать маршрут); при zero-clamp скорости (K §2) rerouting приморожен. +- **ETA — оценка** (см. §8): offline без трафика; остаток — от текущей позиции по маршруту (не от фикс-старта). + +## 5. Ведение (turn-by-turn) и аудио + +- **Turn-by-turn:** next-maneuver-карточка (поворот/дистанция/полоса-опц.) + голосовые промпты. +- **Голос — роль `nav_guidance`** (H §3): дакает медиа; под ассистента/звонок — очередь (H §3). Синтез — **TTS D**. + Тайминг — по **скорости** (K `Location.Speed`, доступна с **v1**; Nav потребляет в v4; уточнение OBD-скоростью E §2/v2) + и дистанции до манёвра. +- **Stale-промпт (не durable-очередь):** у каждого `nav_guidance`-промпта **окно релевантности** (дистанция/время до + манёвра). Пока длится cork звонка / подавление под ассистента — продюсер **I сам снимает заявку**, если манёвр + пройден или окно истекло (H остаётся контент-агностичным, H §2 — снятие устаревшего на стороне I, не арбитра H). По + освобождению фокуса I **переоценивает** текущий манёвр по реальной позиции (map-matching §7) и эмитит свежий промпт, + а не доигрывает протухший. +- **Map-matching:** snap позиции к дорожной сети для отображения и детекта схода/манёвра. +- **Деградация (#4):** нет голоса/занят (H) → карточка остаётся; нет фикса (§7) → ведение приостановлено с пометкой. + +## 6. Поиск, POI, ввод назначения + +- **Ввод:** (1) **голос** — интент D §6 (§9); (2) поиск (адрес/POI); (3) **избранное/дом/работа**; (4) тап/долгий тап. +- **Оффлайн-геокодер/поиск** из OSM-данных (адрес + POI); тяжёлый офлайн-индекс — на устройстве, фоном (#11); класс — §18. + Адрес **вне загруженных регионов** → честный статус «вне загруженных карт» (§4), не пустой «ничего не найдено». + Онлайн-геокодер/POI — опц. улучшение (#8). +- В движении ввод текста — блокируется distraction (C §7); приоритет голосу/пресетам (#6). + +## 7. Позиционирование (потребитель K) + +- **Основа — `Location` (K §2):** валидные `fix_2d/3d/augmented`; **`dead_reckoning` трактуем как ОТСУТСТВИЕ + доверенного фикса** (наравне с `no_fix`; K §2: не валиден для Nav) → не используем для snap/детекта схода, идём путём + GPS-loss. Zero-clamp скорости у нуля (K §2) уважаем. +- **GPS-loss при активном маршруте (тоннель):** **route-based экстраполяция** вдоль маршрута по последней скорости + (модест, БЕЗ заявки точности, помечено «оценка»). +- **GPS-loss без маршрута (free-drive):** route-опоры нет → маркер **замораживается** на последней валидной позиции с + пометкой «нет сигнала», НЕ уводится «живой» оценкой. +- **Ресинк по выходу:** первый(е) фикс(ы) после потери **не доверяем как off-route-триггеру** до стабилизации качества + (низкий HDOP, K §2) — окно подавления rerouting; визуальный скачок маркера **сглаживаем**; при устойчивом расхождении + (пропущенный съезд в слепой зоне) — честный reroute, не «доведение» по устаревшей ветке. +- **Джиттер при валидном фиксе (urban-canyon, multipath):** позиция дрожит, но zero-clamp (K §2) лечит только скорость + → детект схода HDOP-гейтится (§4), не вызывает reroute-шторм. +- **Полноценный sensor-fusion DR (IMU+GPS) — открытый вопрос K §10** (IMU опц./часто нет, K §4) — I НЕ закладывается. +- **Cold-start окно (K §2):** после `battery-cutoff` поездка может стартовать без фикса — ведение деградирует штатно (#3,#4), не висит. + +## 8. Трафик *(онлайн/задел)* + +- **Offline — нет live-трафика;** роутинг работает без него. **ETA offline — оценка по costing БЕЗ трафика/заторов**, + в UI помечается «оценка» (как позиция при no-fix §7), чтобы не давать ложной уверенности (#1). +- **TMC через RDS** (FM-радио, **H §7 задел** — RDS живёт в медиа-тракте H, FM-тюнера ещё нет, hardware §4/H §15) — later. +- **Онлайн-трафик** — опц. провайдер (#8), при `Connectivity` online (G §2); кормит costing (§4). Later. + +## 9. Ассистент-интеграция (D) + +- **Интенты:** «проложи до X», «поехали домой/на работу», «сколько ехать» (ETA), «перестрой», «отмени». **Быстрый + локальный матч фразы** (без LLM, латентно-критично) — у ассистента **D §6**; **резолв места** (дом/работа/избранное + §6, геокодер) **и исполнение** — **Nav-IntentHandler** (`assistant_intents`). Nav-обработчик появляется с **v4** + (вместе с избранным §11); до Nav (v1–v3) нав-фразы → graceful «навигация недоступна» (снимает кажущийся конфликт с + D §6, где «домой» = домашний экран, не навигация). +- **Nav-context → ассистент:** ETA/следующий манёвр/остаток — в контекст (как vehicle-context D §4), по запросу. +- Промпты ведения и ассистент делят аудио по лестнице H §3 (`assistant_tts` > `nav_guidance`). + +## 10. Driver-distraction (#6, владелец — C) + +- В движении: упрощённая карта, **блок ввода текста/сложного**; приоритет голосу/пресетам. Руль-ввод — uinput (K §3); + часть действий гейтится distraction (**C §7** / K §3). Правило едино через Shell/SDK. + +## 11. Приватность (дом/работа/избранное/история — PII) + +- **Места и история — персональные данные локации (152-ФЗ, высокочувствительно):** дом/работа/избранное/недавние + назначения/**last-parked** (+ опц. трек, K §2 «Nav — v4»). **On-device, fscrypt-поддерево** (a-base §3, в + `/data/apps/