Files
shturman/docs/domains/g-connectivity-phone.md
T
kk0t9 fb4e585152 docs(domain G): v2 — связь/телефон (Connectivity+Phone), после adversarial-ревью (15 находок) + кросс-док
Новый домен G: Connectivity-core (WiFi/LTE/tethering + BT-адаптер/паринг) +
Phone-ап (HFP-звонки/контакты). Многоагентный adversarial-ревью: 24 находки,
15 подтверждено (default-refute; tech-измерение — 0, техника устояла), все применены.

Ключевое из ревью:
- BT-шов резолвнут двунаправленно: владелец BlueZ — Connectivity-core (G §3 ↔ H §6/§15 ).
- Граница голоса: только HFP спаренного телефона; встроенный модем — data-only (VoLTE/eCall вне скоупа).
- SIM PIN/PUK-флоу (sim_locked/no_sim) + captive-portal детект (portal/limited, не ложный online) — модем v1.
- Connectivity поднимается на Stage 2 (синхр. с architecture §6).
- Мультипаринг: ровно один active-телефон для HFP/PBAP (Dial/CallStateChanged однозначны).
- SCO-loss mid-call → CallState=audio_lost + снятие роли phone_call → H раскорчивает медиа (не залипает).
- Входящий-оверлей не перекрывает реверс-вид (z-order overlay-слота → C); tethering-петля AP+tether запрещена.
- PBAP-синк фоновый; отказ-пути паринга/no_service симметрично J/H.

Кросс-док: H §6/§15 (BlueZ ) + якоря D §147/§148→§10; architecture §3 (Connectivity+BT)
/§6 (Stage 2); ipc §3 (Type+tether, State enum, CallState=audio_lost); security-privacy §7
(контакты/журнал/SMS local-first); hardware §4 (Bluetooth); tech-stack (NM/MM/BlueZ);
C §11 (z-order overlay).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 19:08:52 +03:00

230 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Домен 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 |