@@ -0,0 +1,229 @@
# Домен G — Связь / телефон
> Сетевой слой (WiFi/LTE-модем/tethering) **и** телефония (BT-паринг, HFP-звонки, контакты,
> проекция). Две сущности: **Connectivity** — привилегированный core-сервис (владеет сетевым/BT-
> железом); **Phone** — first-party ап на SDK (звонки/контакты). Транспорт для онлайн-ассистента
> (D), OTA/телеметрии (L) и стриминга (H).
Статус: **v2 (на ревью). ** v2 — после adversarial-ревью (15 находок).
Связано с : [architecture.md ](../architecture.md ) (§3 Connectivity/Phone, §5 карта связей, §6 boot-Stage) · [ipc.md ](../contracts/ipc.md ) (`Connectivity` , `Phone` ) · [security-privacy.md ](../contracts/security-privacy.md ) (§3 `network` , §5 runtime-грант, §7 приватность/152-ФЗ) · [hardware.md ](../contracts/hardware.md ) (§4 модем/WiFi/BT/mic/amp, §3 load-shed) · [tech-stack.md ](../tech-stack.md ) (NM/MM/BlueZ) · домены **H ** (§3 `phone_call` , §6 BT-аудио-шов), **D ** (§3 online-LLM, §5 креды, §6/§10 интенты/AEC), **C ** (§4 слоты, §7 distraction, §9 ввод), **K ** (§3 руль-кнопки), **B ** (§4 load-shed, §7 sleep/wake), **L ** (облако/компаньон), **I ** (нав/TMC) · [principles.md ](../principles.md ) (#1 ,#2 ,#3 ,#6 ,#7 ,#8 ,#11 ,#12 ,#13 )
---
## 1. Назначение и границы
- **Connectivity (core):** IP-связность для companion-слоя — WiFi-клиент, LTE-модем, tethering от
телефона; приоритет/failover путей, статус сети; владелец сетевого и **BT-адаптера ** (§3).
- **Phone (first-party ап):** BT-паринг UX, **HFP-звонки ** (hands-free), контакты/журнал (PBAP),
опц. сообщения (MAP); звук звонка — роль `phone_call` в арбитре H (§4).
- **Границы (красные линии):**
- **Не safety-critical (#1 ):** **eCall / экстренный вызов — вне скоупа ** (регулируемая safety-система).
- **Голос — только HFP спаренного телефона; встроенный LTE-модем — data-only** (CS-voice / VoLTE — вне
скоупа: отдельный крупный стек; усиливает границу eCall — головблок физически не голосовой узел сети).
- **Модем — НЕ шлюз к машине (#2 ):** Connectivity даёт IP только companion-слою; **никакого моста
модем↔CAN**, никакого удалённого управления узлами. Удалённый доступ к данным машины (если будет, через
L) — **read-only + opt-in ** , не через G.
- **Проекция (CarPlay/Android Auto)** — тяжёлые лицензионные ограничения, не first-party, later (§8).
- **Plane:** control/состояние — D-Bus (`Connectivity` /`Phone` ); **звук звонка — PipeWire ** (роль
`phone_call` , политика — H §3); сам IP-трафик — вне D-Bus.
## 2. Connectivity (core-сервис)
- **Пути данных (провайдер-агностично #8 ):** (1) **WiFi-клиент ** (домашняя/известная сеть на стоянке);
(2) **LTE-модем ** (USB, SIM/APN — ModemManager); (3) **tethering ** от телефона (BT-PAN / WiFi-hotspot телефона).
- **Приоритет/failover:** политика выбора активного пути (напр. WiFi > tethering > metered-LTE), бесшовное
переключение; **metered-aware ** (крупные загрузки — OTA L/A — не тянуть по дорогой LTE без согласия).
- **Состояние связности — НЕ бинарно на уровне источника правды:** NM connectivity-check различает
`portal` /`limited` (ассоциация + IP есть, реального интернета нет — публичный WiFi за captive-portal) от
настоящего `online` . **Портал не рапортуется как online ** — иначе D (online-LLM) / L (OTA) ломаются на
ложном «online». Прохождение портала — UX вне MVP, но детект обязателен (инвариант «не маскировать»).
- **SIM/модем-стейты:** PIN-locked SIM на boot/вставке → состояние * * `sim_locked` ** (и `no_sim` /`no_service` ),
отличное от `offline` (как «сервис не поднят» ≠ offline); запрос **PIN — через слот Shell ** (C §4, как
входящий-оверлей §6), **PUK ** -fallback после исчерпания попыток (ModemManager `Sim.SendPin` /`SendPuk` ).
- **Обёртка NetworkManager/ModemManager** (hardware §4); статус/состояния — `ru.shturman.Connectivity` (§11).
- **Boot-Stage:** Connectivity поднимается на **Stage 2 ** (фоном, как Vehicle-Data/Assistant; architecture §6),
не в Stage 1 → статус-бар C §3 до первого ответа = «unknown»; online-LLM (D §3, v1) до прихода Connectivity
деградирует по #3 (offline-first), не виснет.
- **Offline-first (#3 ):** сеть в движении нестабильна → потребители (D, H, L) **деградируют, не виснут ** ;
Connectivity лишь честно сообщает состояние, не маскирует. Безопасность: модем — отдельный процесс (net-ns).
- **Фаза:** WiFi-клиент + LTE-данные (+ SIM-unlock) — **v1 ** (нужно online-ассистенту D §3); hotspot/AP — later (§7).
## 3. Bluetooth (core: адаптер + паринг) *(резолв BT-шва H §6; синхронизировано в H §6/§15)*
- **Владелец BlueZ-адаптера и паринга — Connectivity-core** (общий аппаратный радиоресурс → один привилегированный
владелец, как сеть). 🟡 может выделиться в отдельный BT-сервис, если разрастётся (§15).
- **Паринг:** BlueZ-Agent (PIN/just-works) — механизм в core; **UX выбора устройства/подтверждения — в
Phone-апе/Shell** (слот C §4). Список спаренных, доверие, реконнект — здесь. **Сбой паринга ** (неверный
PIN / timeout / reject устройства) → видимая неблокирующая индикация + откат к списку устройств, без зависания.
- **Активное устройство (мультипаринг):** одновременно активен **ровно один телефон для телефонии (HFP/PBAP) ** ;
при нескольких спаренных — выбор active-устройства (last-connected / явный выбор в Phone-апе, слот C). A2DP-медиа
может жить на **другом ** устройстве (координация H §6). Это делает `Dial` /`CallStateChanged` (§11) однозначными.
- **Диспетчеризация профилей** к потребителям спаренного устройства:
- **HFP** (звонок) → **Phone-ап (G) ** , §4;
- **A2DP/AVRCP** (медиа) → **Media-ап (H §6) ** ;
- **PBAP/MAP** (контакты/сообщения) → **Phone-ап (G) ** , §5.
- **HFP-аудио** идёт через PipeWire (bluez5-модуль, mSBC/CVSD) — H маршрутизирует по роли `phone_call` .
- **Фаза:** v2 (вместе с Phone и A2DP H).
## 4. Телефония — HFP-звонки (Phone-ап)
- **Состояния вызова:** `idle` /`incoming` /`dialing` /`active` /`held` (опц.)/**`audio_lost` ** — публикуются на
шине (§11), чтобы H проактивно корчил медиа (H §3 crash-safe: сигнал `Phone` → cork ДО появления аудио-ноды).
- **Аудио:** downlink (голос собеседника) → усилитель; uplink — **салонный mic-массив ** (hardware §4),
тот же, что у ассистента → во время звонка mic отдан HFP-аплинку (политика арбитража H §3), ассистент
подавлен. AEC/денойз на uplink — желателен (тот же тракт, что H §4 / D §10).
- **Звонок — это телефона, не наш:** головблок — hands-free-периферия.
- **Потеря HFP-аудио-линка в середине звонка** (SCO рвётся — телефон вышел из зоны, — но вызов жив на AG):
**отдельное событие от hangup. ** Phone эмитит `CallStateChanged → audio_lost` (§11), **синхронно снимая
заявку роли `phone_call` ** → H гарантированно опускает проактивный cork (медиа не залипает; H §3), mic
освобождается, подавление ассистента снято. **Инвариант: ** проактивный cork снят ⇔ оверлей не показывает
hands-free-разговор (одно событие на обе оси). UI (§6) → «звонок продолжается на телефоне».
- **Фаза:** v2.
## 5. Контакты / журнал / сообщения (PBAP/MAP) + приватность
- **PBAP:** синхронизация контактов и журнала вызовов с телефона (имя вместо номера, набор по имени §6).
**Синхронизация — фоновая/ленивая (#11) ** , не блокирует UI и не задерживает доступность HFP; на общем
BT-линке **голос (HFP) приоритетнее ** фоновой PBAP-синхронизации. **MAP ** (SMS) — later (чтение вслух §6).
- **Приватность (#7 , 152-ФЗ — высокочувствительно):** контакты, журнал, тексты SMS — **персональные данные ** .
**On-device, local-first ** ; **никогда ** в облако/онлайн-LLM без явного согласия (как память водителя D §7).
Доступ — audit-log (security-privacy §7 / a-base §9); at-rest — fscrypt-поддерево (a-base §3). Чистка —
factory-reset (a-base §12) + при отвязке устройства.
- **Фаза:** контакты v2; SMS/MAP v3.
## 6. Управление вызовом и distraction (#6)
- **Ответ/сброс — аппаратно, не голосом:** кнопки **мультируля ** (answer/hangup) и тач (C §9, K §3,
uinput→Wayland-input) — крупная single-tap-аффорданс, доступна и на скорости (distraction блокирует
* сложное * , не одно-действие; C §7). **Во время звонка mic занят HFP ** → голосового «положи трубку» нет
(явное решение, не пробел).
- **Набор — голосом (до звонка):** «позвони <контакт>» — **assistant-интент ** (Phone — first-party,
регистрирует `assistant_intents` ; роутинг/коллизии D §6 + plugin-sdk §5), резолв имени по PBAP active-устройства (§3/§5).
- **Входящий вызов — оверлей** в слоте Shell (C §4), упрощённый на скорости (distraction — владелец C §7);
`phone_call` прерывает ассистента (лестница H §3). **При активном реверс/парктроник-виде (J §6) входящий-
оверлей НЕ перекрывает live-вид камеры** — деградирует до компактной формы (полоса/PiP), сохраняя
answer/decline; z-order overlay-слота — у C (§15 → C).
- **Имя не синхронизировано** по PBAP (реконнект/большая книга §5) → оверлей показывает **номер ** (#3 graceful),
имя подтянется позже.
- **Фаза:** v2.
## 7. WiFi-hotspot / tethering *(later)*
- **Головблок как AP** (раздать **текущий активный uplink ** §2 — не обязательно LTE) и/или приём tethering
от телефона (§2). NM-управление.
- **Инвариант радио:** AP-раздача и приём WiFi-tether делят **одно WiFi-радио ** → взаимоисключающие, если
железо не поддерживает concurrent STA+AP (зависимость от hardware §4); конфигурация «AP-uplink = тот же
телефон, что и tether-источник» — **запрещена (петля) ** .
- Энергобюджет/нагрев (hotspot тянет) — с B/hardware. **Фаза: ** v3.
## 8. Проекция — CarPlay / Android Auto *(later, лицензионно-ограничено)*
- 🟡 **Серьёзные ограничения (#12, юр.): ** **CarPlay ** требует Apple MFi-чип + лицензию (NDA, несовместимо с
open-source); **Android Auto ** -проекция — проприетарный протокол Google; открытые реализации
(OpenAuto-класс) — реверс-инжиниринг, юридически серо, часто GPL. → **не first-party ** ; реалистично —
community-плагин под ответственность интегратора **или ** вне скоупа.
- Если появится: аудио/видео проекции — роли `projection` /`phone_call` в арбитре H (§3); поверхность — слот C.
- **Фаза:** v4/неопределённо; решение — отдельно (§15).
## 9. Lifecycle (шов с B)
- **Load-shedding:** при power-loss модем/WiFi — среди сбрасываемых нагрузок (hardware §3, B §4) → Connectivity
отрабатывает пропажу транспорта как обычный offline (#3 ), потребители деградируют (in-flight HTTP D — таймаут
D §5; teardown через `ShutdownImminent` →`StopApp` оркестрирует B §4).
- **Sleep/wake (B §7):** модем/радио выключены в `sleep` /`battery_cutoff` (бюджет АКБ #5 ); опц. wake по сети — later.
- **Звонок при ACC-off:** головблок — лишь hands-free; на shutdown HFP-аудио прекращается, **звонок продолжается
на телефоне** (как при потере SCO §4) — активный звонок shutdown не блокирует.
- **Реконнект:** на boot/`accessory` Connectivity переподнимает известные WiFi/спаренные BT (resume медиа H §9
зависит от этого).
## 10. Приватность и безопасность (#7, #1, #2, #12)
- **Local-first ПДн:** контакты/журнал/SMS — §5; никаких автоматических выгрузок.
- **Модем ≠ шлюз к CAN (#2 ):** изоляция companion-IP от шины машины — нет пути модем→Vehicle-Data→CAN-write
(его не существует). Удалённое — только read-only/opt-in через L.
- **eCall/экстренный — вне скоупа (#1 ).**
- **Лицензии (#12 ):** **BlueZ / ModemManager / NetworkManager ** (и obexd для PBAP/MAP) — **GPL-2.0 ** ; используем
как **отдельные системные демоны через D-Bus ** (не линкуем в наши Rust-бинари) → copyleft изолирован
процессом (#12 -допустимо). Наш код (`zbus` -обёртки) — MIT.
## 11. IPC / интерфейсы
- **`ru.shturman.Connectivity` ** (ipc §3, ядро): `GetStatus()` /`ListNetworks()` /`Connect(id)` /`Disconnect()` ;
сигналы `ConnectivityChanged(state)` /`NetworkChanged(...)` ; properties `Online` (bool), * * `State` **
(`offline` /`portal` /`limited` /`online` + модем `sim_locked` /`no_sim` /`no_service` ), `Type`
(`wifi` /`modem` /**`tether` **), `SignalStrength` . Расширение enum `Type` (`tether` ) + `State` + BT-устройства/
выбор active — **расширить ipc §3 (хвост) ** .
- **`ru.shturman.Phone` ** (ipc §4, домен G): `Dial(number|contact)` /`Answer()` /`Hangup()` (адресуют active-
устройство §3); сигнал * * `CallStateChanged(state, peer)` ** (`idle` /`incoming` /`dialing` /`active` /`held` /
* * `audio_lost` ** — SCO потерян, вызов на телефоне §4) — на него H проактивно корчит/раскорчивает медиа
(H §3); property `CallState` , `Contacts` (read). Закрывает ipc §4-делегацию H/I/**G**.
- **Гейтинг:** `network` (security-privacy §3/§5, runtime-грант); HFP-аудио — PipeWire-нода роли `phone_call`
(H §3); контакты стороннему — **не отдаём ** без явного грана (приватность §5/§10).
- **UI:** входящий-оверлей/набор/PIN-запрос — слот Shell (C §4); статус сети — статус-бар (C §3).
## 12. Dev-симулятор (#13)
- **Сеть/модем — управляемые состояния** (уже в dev-environment: online/offline/слабый сигнал/**portal**/
**sim_locked ** , для offline-first тестов D/H/L). Добавить: **фейковый BT-стек ** (паринг + **сбой паринга ** ,
профили HFP/A2DP/PBAP, мульти-устройство), **сценарии вызова ** (incoming/active/hangup/**SCO-loss** → проверка
cork/un-cork медиа H §3), **мок-контакты ** (PBAP без реального телефона). → dev-environment.
## 13. Функции
| функция | MVP/later | зависит от | фаза |
|---------|-----------|------------|------|
| Connectivity-сервис (WiFi-клиент + LTE-данные + статус + SIM-unlock) | **MVP ** | hardware §4, NM/MM | v1 |
| Состояние связности (portal/limited детект, не ложный online) | **MVP ** | NM connectivity-check | v1 |
| Приоритет/failover путей + metered-aware | **MVP ** | — | v1 |
| BT-адаптер + паринг (core) + диспетчер профилей + active-устройство | **MVP ** | hardware (BT), BlueZ | v2 |
| HFP-звонки (состояния + аудио `phone_call` + SCO-loss) | **MVP ** | H §3, mic/amp | v2 |
| Отказ-пути (сбой паринга, no_sim/no_service) | **MVP ** | — | v2 |
| Контакты/журнал (PBAP, фоновый синк) + privacy | **MVP ** | security-privacy, a-base §3 | v2 |
| Управление вызовом (руль/тач) + входящий-оверлей (vs реверс) | **MVP ** | C §4/§7/§9, K §3 | v2 |
| Голосовой набор «позвони X» (assistant-интент) | later | D §6 | v2 |
| tethering от телефона (BT-PAN / hotspot) | later | — | v2/v3 |
| WiFi-hotspot (AP, раздача uplink) | later | hardware/B | v3 |
| SMS/сообщения (MAP) + чтение вслух | later | D (TTS) | v3 |
| Проекция (CarPlay/Android Auto) | later | лицензии (§8) | v4/неопр. |
## 14. Зависимости
- **Вниз:** hardware (§4 модем/WiFi/**BT-адаптер**/mic/amp, §3 load-shed), NM/MM/BlueZ/obexd (tech-stack), PipeWire
(HFP-аудио через H), a-base (§3 fscrypt контактов, §9 audit, §12 reset).
- **Вбок:** **H ** (роль `phone_call` , BT-аудио A2DP/AVRCP — H цепляет к нашему адаптеру; arbiter ducking),
**D ** (online-LLM поверх Connectivity; интенты «позвони»/«прочитай SMS»; AEC-тракт §10), **C ** (слоты входящего/
набора/PIN, distraction, мультируль-ввод, z-order overlay), **K ** (руль-кнопки answer/hangup), **B ** (load-shed,
sleep/wake), **L ** (Connectivity — транспорт OTA/телеметрии/компаньона), **I ** (RDS-TMC — задел H §7).
- **Вверх:** статус сети/звонка для Shell; `network` — потребляют апы/плагины (гейтинг security-privacy).
## 15. Открытые вопросы
- 🟡 **BT-адаптер в hardware §4: ** добавить Bluetooth в периферию (резолвится этим коммитом). → hardware.
- 🟡 **Владелец BlueZ: ** Connectivity-core (рек., §3) vs выделенный BT-сервис — подтвердить.
- 🟡 **Телефонный стек HFP: ** PipeWire-bluez5 (аудио) + BlueZ-D-Bus (управление) — достаточно, или нужен
**oFono ** (richer call control: held/swap, call-waiting, 3-way, DTMF — тоже GPL-демон)? → реализация/tech-stack.
- 🟡 **Проекция (CarPlay/Android Auto): ** не-first-party / плагин / вне скоупа — решить (лицензии §8). → отдельно.
- ◻️ **Z-order overlay-слота ** (входящий-вызов vs реверс-вид vs ассистент vs уведомления) — общее правило
«вид манёвра > уведомление». → C (§4 слот-модель) + J §6.
- ◻️ **Политика приоритета путей ** (WiFi/tether/LTE, metered-пороги, failover-гистерезис, пороги SIM-ретраев) — числа. → реализация.
- ◻️ **Контакты/журнал/SMS в security-privacy §7 ** (потоки данных) — добавить строку local-first (резолвится этим коммитом). → security-privacy.
- ◻️ **152-ФЗ для контактов/звонков ** (оператор ПДн, основание) — legal-трек (как BYO-LLM, security-privacy §7).
- ◻️ **Wake-on-network / входящий в sleep ** — нужен ли, бюджет АКБ. → B.
- ◻️ **tethering vs встроенный модем ** — оба или приоритет одного (стоимость SIM vs зависимость от телефона). → later.
---
## Журнал решений (домен G)
| Решение | Выбор | Дата |
|---------|-------|------|
| Структура | Connectivity (core, сетевое+BT-железо, Stage 2) + Phone (first-party ап); оба в домене G | 2026-06-22 |
| Пути данных | провайдер-агностично: WiFi/LTE/tethering, приоритет+failover, metered-aware; связность не бинарна (portal/limited) | 2026-06-22 |
| Голос | **только HFP спаренного телефона; встроенный модем — data-only ** (VoLTE/CS вне скоупа); eCall вне скоупа (#1 ) | 2026-06-22 |
| BlueZ | владелец — Connectivity-core; active-устройство = ровно один телефон для HFP/PBAP; профили HFP→Phone, A2DP/AVRCP→H, PBAP/MAP→Phone (**резолв H §6**) | 2026-06-22 |
| Звонок | HFP hands-free; звук — роль `phone_call` ; SCO-loss → `audio_lost` + снятие роли (раскорчивает H); звонок «телефона» | 2026-06-22 |
| Управление | ответ/сброс — руль/тач single-tap (mic занят HFP → нет голос-hangup); набор — голосом (assistant-интент) | 2026-06-22 |
| Приватность | контакты/журнал/SMS — local-first, fscrypt, не в облако без согласия (152-ФЗ); PBAP-синк фоновый | 2026-06-22 |
| Красные линии | модем ≠ шлюз к CAN (#2 ); GPL-демоны (BlueZ/NM/MM/obexd) изолированы процессом (#12 ) | 2026-06-22 |
| Проекция | CarPlay/AA — лицензионно тяжело → не-first-party/плагин/вне скоупа, v4-неопр. | 2026-06-22 |
| Фазы | Connectivity-данные+SIM v1; BT/HFP/контакты v2; hotspot/SMS v3; проекция v4 | 2026-06-22 |