Files
shturman/docs/domains/i-navigation.md
T
kk0t9 2eaa561892 docs(domain I): v2 — навигация (offline OSM/роутинг/turn-by-turn), после adversarial-ревью (24 находки) + кросс-док
Последний домен. 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 <noreply@anthropic.com>
2026-06-23 14:23:34 +03:00

27 KiB
Raw Blame History

Домен I — Навигация

Офлайн-навигация: карты OSM, оффлайн-роутинг, turn-by-turn, поиск/POI, связка с ассистентом. Offline-first (#3 — карта не теряется в тоннеле/глуши). First-party ап на SDK; богатая карта-поверхность. Не safety/ADAS (#1). Поздний слой — v4 (vision-лестница: нав+образ+ретрофит).

Статус: v2 (на ревью). v2 — после adversarial-ревью (24 находки). Связано с: tech-stack.md (Карты: MapLibre + Valhalla/OSRM) · architecture.md (§3 Nav — first-party, §6 boot Stage 2) · ipc.md (Nav, Location) · 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 (§3 location, §5 while-in-use, §7 приватность) · 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), NavigateToRouteNotFound/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 (v1v3) нав-фразы → 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/<nav>/); factory-reset-wipe (a-base §12); доступ — audit-log; location while-in-use (K §2, sec-priv §5).
  • Отдельный чувствительный store, исключённый из дефолтного Settings-синка L: нав-избранное/дом/работа синкаются только по явному отзываемому consent (как память D §7 / контакты G §5 / точная локация L §5) — не автоматически с обычными настройками; не в LLM-промпт без согласия (sec-priv §7).

12. Отказ-пути (fail-safe, симметрично J §3/§4 · H §5 · L §7)

  • No-route-found (§4) → видимая неблокирующая индикация «маршрут не найден», ведение не стартует, RouteActive=false; не зависание/пустой экран.
  • Сбой/пустой геокодер (битый индекс / ничего не найдено) → «ничего не найдено» + фолбэк (тап по карте §6), не крэш поиска.
  • Битые/отсутствующие тайлы региона (рендер/роутинг) → видимая пометка деградации, не белый экран и не крэш GPU-рендера.
  • ENOSPC при загрузке региона (единицы–десятки ГБ, §2) → отказ ДО записи с видимой индикацией, без частичного тайл-набора (проверка места — как L §7); недоступный источник карт → отложить (#3).

13. Lifecycle (шов с B)

  • Boot-Stage: Nav-сервис — Stage 2 (фоном; architecture §6 перечисляет Nav в Stage 2); карта-поверхность — в слот Shell после Stage 1.
  • Resume маршрута: на ShutdownImminent (B §4) durable-save состояния. Валидность resume: (а) тайлы региона назначения присутствуют той же версии (иначе не пересобирать молча — §2/§18, предложить скачать/отменить); (б) до первого фикса (cold-start §7) — показать сохранённое назначение, но НЕ вести по устаревшему прогрессу (§5); (в) после фикса — если позиция вне коридора, штатный сход → rerouting (§4/§7), не слепое продолжение.
  • Прибытие: на Arrived (§14) — завершение ведения у точки; захват last-parked (позиция, fscrypt §11); парковочный «последние метры» — опц./later.
  • Не держит wake (B §7, #5); ведение — в running/accessory.
  • Память (a-base §8): рендер-буферы/тайл-кэш — потребитель; throttleable под UI-приоритет (#11).

14. IPC / интерфейсы

  • ru.shturman.Nav (ipc §4, домен I): NavigateTo(dest) (→ RouteNotFound если недостижимо/вне графа), CancelRoute()/RerouteNow(), Search(query) → [results] (статус «вне загруженных карт» §4), ListFavorites(); сигналы RouteChanged/ManeuverChanged(next)/Arrived; properties RouteActive (false при no-route), Eta (оценка без трафика §8), DistanceRemaining, NextManeuver.
  • Потребляет: Location (K — позиция/скорость/FixQuality), Connectivity (G — онлайн опц.), Power (B — тайминг), Settings (тема; нав-избранное — отдельный fscrypt-store §11, не Settings-namespace), TTS (D). Гейтинг: location (sec-priv §3/§5, while-in-use); network (онлайн).
  • UI: карта-поверхность + next-maneuver-карточка + поиск — слоты Shell (C §4); голос — PipeWire (nav_guidance).

15. Зависимости

  • Вниз: tech-stack (MapLibre/Valhalla), A (§3 хранилище/fscrypt, §10 износ, §12 reset), hardware (GPU Mesa/Panfrost RK3588), data-model (§4 единицы).
  • Вбок: K (§2 Location/FixQuality/zero-clamp/DR, §3 руль, §10 DR-открыт), H (§3 роль nav_guidance/ducking, §7 RDS-TMC), D (§6 интенты, §2 TTS), C (§4 слоты, §6 тема, §7 distraction), E (§2 OBD-скорость v2), G (§2 онлайн/metered), B (§4/§7 lifecycle), L (§5/§7 обновление карт/синк избранного с consent), security-privacy (§3/§5/§7 локация-приватность).
  • Вверх: nav-context (ETA/манёвр/остаток) → D (как vehicle-context); карта-поверхность → Shell (C); last-parked → потребитель L (§5 «где машина»); расширяемо плагинами.

16. Dev-симулятор (#13)

  • Fake-GPS-трек (NMEA-реплей K §2: маршрут/тоннель-no-fix/дрейф/cold-start), тест-регион (малый PMTiles + Valhalla-тайлы), мок-маршрут (rerouting/maneuver-тайминг/nav_guidance-ducking H §12). Краевые сценарии: дрейф в каньоне при валидном фиксе → НЕ reroute (анти-pumping §7), назначение вне региона (§4), no-route, stale-промпт под звонком (§5). Поверх fake-GPS/мок-сети. → dev-environment.

17. Функции

функция MVP/later зависит от фаза
Офлайн-карты (OSM/ODbL, PMTiles, version-coherent) MVP tech-stack, хранилище v4
Рендер карты (MapLibre GL Native BSD-2, GPU, поверхность) MVP C §4, Mesa/Panfrost v4
Офлайн-роутинг (Valhalla 🟡, ETA-оценка, rerouting+гистерезис) MVP движок v4
Покрытие/детект региона (вне загруженных тайлов) MVP §2, G §2 v4
Turn-by-turn + промпты (nav_guidance, stale-drop) MVP H §3, D v4
Map-matching + позиционирование (GPS-loss/free-drive/ресинк) MVP K §2 v4
Ввод назначения (голос/поиск/избранное/тап) MVP D §6, геокодер v4
Офлайн-геокодер/POI (статус «вне региона») MVP OSM-данные v4
Избранное/дом/работа/last-parked (fscrypt, consent-синк) MVP a-base §3, sec-priv, L v4
Отказ-пути (no-route/geocoder/битые-тайлы/ENOSPC) MVP §4/§6/§2, L §7 v4
Resume маршрута (валидность по тайлам/фиксу) MVP Settings, B, §2 v4
Speed-limit инфо-бейдж (пассивный, не предупреждение) later OSM maxspeed v4
Обновление карт (канал L / ручное, атомарно) later L §5/§7, G v4
Трафик: TMC/RDS (задел) later H §7 later
Трафик/поиск онлайн (опц. #8) later G §2 later
Sensor-fusion DR в тоннелях (IMU+GPS) later K §10 (открыто) later

18. Открытые вопросы

  • 🟡 ODbL (OSM): атрибуция обязательна; share-alike на производную базу — оформить (атрибуция в UI). → #12/legal.
  • 🟡 Движок роутинга Valhalla (рек.) vs OSRM — выбрать (вес/RAM/инкрементальность on-device). → tech-stack.
  • 🟡 Размещение карт-данных (отдельный раздел/носитель vs /data; износ a-base §10; размер региона). → a-base/hardware.
  • ◻️ Speed-limit display из OSM maxspeed — покрытие/достоверность неравномерны (риск ложного claim'а #1); включать ли пассивный бейдж и как позиционировать. → #1/legal.
  • ◻️ Визуальные нав-единицы (км/м vs mi/ft в карточке/ETA/DistanceRemaining) + формат/порядок адреса — из локали Settings (C), конвертация на презентации (data-model §4); RU-first метрический дефолт (#10).
  • ◻️ Канал обновления карт (через L-контент vs отдельный; атомарная замена региона + version-coherence пары; дельта). → L.
  • ◻️ Sensor-fusion DR в тоннелях (IMU+GPS) — нужен ли, где живёт (K-fusion/gpsd/Nav). → K §10 (парный).
  • ◻️ Офлайн-геокодер (Pelias/Nominatim-класс vs упрощённый индекс) — вес/качество на RK3588. → реализация.
  • ◻️ 3D/buildings/landmark-guidance — объём данных vs ценность. → later.
  • ◻️ Голосовые языки промптов (RU-first #10; озвучка названий улиц — TTS D). → D.

Журнал решений (домен I)

Решение Выбор Дата
Позиционирование offline-first нав; онлайн — опц. улучшение; не safety/ADAS (#1; speed-limit — пассивный бейдж, не предупреждение); v4 2026-06-23
Карты OSM (ODbL — атрибуция); PMTiles + Valhalla-тайлы когерентной парой, атомарная замена региона 2026-06-23
Рендер MapLibre GL Native (BSD-2-Clause), GPU Mesa/Panfrost, Wayland-поверхность слот C 2026-06-23
Роутинг offline, provider-agnostic (#8); Valhalla рек. (🟡); region-coverage-детект; no-route-found; reroute с гистерезисом 2026-06-23
Ведение turn-by-turn; nav_guidance (H §3) → TTS D; stale-промпт снимает продюсер I (H контент-агностичен) 2026-06-23
Позиция потребитель K Location; dead_reckoning=нет-фикса; route-based экстраполяция (с маршрутом) / freeze (free-drive); ресинк-дисциплина 2026-06-23
Приватность дом/работа/избранное/история/last-parked — PII: fscrypt, отдельный store (не Settings-синк), consent-only, reset-wipe 2026-06-23
Ассистент матч фразы — D §6; резолв+исполнение — Nav-handler (v4); до Nav — graceful «недоступна» 2026-06-23
Lifecycle Stage 2 (architecture §6); resume по валидности тайлов/фикса; last-parked на Arrived; не держит wake 2026-06-23
Отказ-пути no-route/geocoder-fail/битые-тайлы/ENOSPC — видимая индикация, не крэш (симметрично J/H/L) 2026-06-23