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>
This commit is contained in:
2026-06-22 19:08:52 +03:00
parent 77d9a5a0ee
commit fb4e585152
8 changed files with 245 additions and 12 deletions
+2 -2
View File
@@ -63,7 +63,7 @@ data-plane — см. §4.
| **Settings/State** | центральная конфигурация и состояние, пишет в `/data` | общий источник правды; единственный писатель в `/data`-конфиг |
| **Security/Perm-Broker** | выдаёт/режет capabilities по манифесту | привратник всех привилегий |
| **Plugin/App-Host** | запуск, супервизия, песочница апов и плагинов | посредник доступа к шине; владеет sandbox-механизмом |
| **Connectivity** | обёртка ModemManager/NetworkManager, статус сети | управляет сетевым железом |
| **Connectivity** | обёртка ModemManager/NetworkManager **+ BlueZ-адаптер/паринг**, статус сети | управляет сетевым и BT-железом (общий радиоресурс) |
### First-party апы (отдельные процессы на SDK, расширенные права)
@@ -158,7 +158,7 @@ graph TD
**Быстрый boot фазами (цель — < 10 c до интерактива):**
- **Stage 0 (мгновенно):** загрузчик → splash. Низколатентный путь задней камеры/парктроника, если включена задняя.
- **Stage 1 (~35 c):** ядро-минимум (шина + Power + Settings + **Perm-Broker + App-Host**) → **Shell с первым кадром** (home-тайлы кликабельны). Broker/App-Host нужны раньше Shell: Shell — тоже ап и поднимается/цепляется к шине через них.
- **Stage 2 (фоном):** Vehicle-Data, Assistant, Media, Nav прогреваются после того, как UI интерактивен.
- **Stage 2 (фоном):** Vehicle-Data, Assistant, Media, Nav, **Connectivity** прогреваются после того, как UI интерактивен.
**Завершение:** ACC-off → Power/Lifecycle инициирует graceful shutdown (systemd-таргет): апам сигнал «сохранись», Settings флашится в `/data`, размонтирование, снятие питания через supercap/MCU-копилот. Вместе с read-only rootfs это защита от corruption.
+1 -1
View File
@@ -82,7 +82,7 @@ fail-safe при отказе/зависании самого MCU** (незав
| **Дисплей** | HDMI + USB-тачскрин | MIPI-DSI / LVDS панель |
| **CAN/OBD** | ELM327 (USB/BT) | нативный CAN-трансивер → **SocketCAN** |
| **GPS** | USB/UART, NMEA | **внешняя/активная антенна** (LNA); 1PPS — опц. (PPS-точность времени; на USB-донглах обычно нет) |
| **Связь** | USB-модем (ModemManager) / Wi-Fi | — |
| **Связь** | USB-модем (ModemManager) / Wi-Fi / **Bluetooth** (BlueZ: HFP/A2DP/PBAP) | — |
| **Аудио** | I2S codec + усилитель (+ mute/enable-GPIO — anti-pop) | — |
| **Микрофон** | USB **mic-массив** (wake-word, шумоподавление) | — |
| **Радио** *(later)* | — | FM-тюнер (Si47xx-класс) — нужен для радио (домен H §7); 🟡 добавить или отказаться |
+2 -2
View File
@@ -86,8 +86,8 @@
### `ru.shturman.Connectivity` — сеть (обёртка NM/MM)
- **Методы:** `GetStatus() → status`, `ListNetworks() → [...]`, `Connect(id)`, `Disconnect()`.
- **Сигналы:** `ConnectivityChanged(online)`, `NetworkChanged(...)`.
- **Properties:** `Online` (bool — «сервис ещё не поднят» ≠ «offline»), `Type` (wifi/modem), `SignalStrength`.
- **Сигналы:** `ConnectivityChanged(state)`, `NetworkChanged(...)`.
- **Properties:** `Online` (bool — «сервис ещё не поднят» ≠ «offline»), `Type` (wifi/modem/tether), `State` (offline/portal/limited/online + модем sim_locked/no_sim/no_service — домен G), `SignalStrength`.
### `ru.shturman.Location` — GPS/положение (владелец — домен K)
- **Properties:** `Latitude`, `Longitude`, `Heading`, `Speed`, `FixQuality` (enum `no_fix`/`fix_2d`/`fix_3d`/`augmented`/`dead_reckoning`), `HDOP`, `satellites`, `ts`; per-property quality для `Speed`/`Heading` (зануление у нуля — domain K §2).
+1
View File
@@ -133,6 +133,7 @@ PipeWire-capture/location). Для `audio_in`/`location` — **while-in-use**:
| Текст запроса | локально → онлайн-LLM при необходимости | только текст, только в онлайн-режиме |
| Данные машины (OBD/DTC) | локально | **в промпт онлайн-LLM** — только онлайн, по запросу **И при явном (отзываемом) согласии** на весь исходящий промпт; офлайн — не уходит |
| Память о водителе (`.md`) | локально | нет (без явного согласия) |
| Контакты/журнал/SMS (PBAP/MAP, домен G) | локально (fscrypt) | нет (без явного согласия) |
| Телеметрия | локально | **opt-in**, по умолчанию выключена |
- Онлайн-LLM — только **RU-провайдеры** (GigaChat/YandexGPT), данные в РФ (152-ФЗ).
+1
View File
@@ -123,6 +123,7 @@ Shell** (его пробрасывает bubblewrap при `ui_*`, security-priv
- ◻️ **Мультидисплей, профили** — later.
-**Контракт Location/GPS** — в [k-sensors §2](k-sensors-peripherals.md) (QoS, FixQuality, zero-clamp скорости у нуля; C потребляет занулённую `Speed`). Арбитраж GPS-vs-OBD (v2) — открыт.
- ◻️ **Какие руль-действия гейтятся в distraction** — парный с K §10.
- ◻️ **Z-order overlay-слота** (входящий-вызов G §6 vs реверс-вид J §6 vs ассистент/уведомления) — правило «вид манёвра > уведомление». → §4 + G/J.
- 🟡 **Slot-протокол поверхностей** (`ru.shturman.shell_slot`: surface→слот, slot-token, peer-creds) — спроектировать (§4).
---
+229
View File
@@ -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 |
+8 -7
View File
@@ -78,7 +78,7 @@ capture-нода не «дакает» вывод; дакает медиа им
intra-role, состояние для UI) — компонент Media-апа, подписан на `Assistant.StateChanged`/`Phone`/`Nav`/
`Power` (ipc §34). До Media-апа (v1) хватает статической политики + ролей ассистента.
## 4. AEC и loopback-референс *(резолв D §147)*
## 4. AEC и loopback-референс *(резолв D §10)*
- H **публикует monitor/loopback-tap смешанного выхода** как референс для эхоподавления (без него
wake-word во время воспроизведения и barge-in невозможны).
@@ -86,8 +86,8 @@ capture-нода не «дакает» вывод; дакает медиа им
пути capture микрофона; референс — monitor-порты выхода. **Не внутри ассистента** (D потребляет уже
очищенную capture-ноду). *(`module-echo-cancel` — отдельный модуль PipeWire, не `module-filter-chain`:
последний — иной механизм (граф LADSPA/LV2/builtin), пригоден лишь для опц. кастомного денойза.)*
→ закрывает «место AEC (в audio-plane vs внутри ассистента)» из D §147 в пользу audio-plane.
- Beamforming/денойз салона (D §148) — отдельно (mic-массив, hardware); AEC ≠ денойз.
→ закрывает «место AEC (в audio-plane vs внутри ассистента)» из D §10 в пользу audio-plane.
- Beamforming/денойз салона (D §10) — отдельно (mic-массив, hardware); AEC ≠ денойз.
## 5. Локальное аудио
@@ -113,7 +113,8 @@ capture-нода не «дакает» вывод; дакает медиа им
**cork/пауза транспорта + auto-resume по реконнекту**, не крэш, видимая индикация.
- **Шов с G/Connectivity:** BT-адаптер, паринг и профиль **HFP** (звонок) — **не H** (домен G/Connectivity).
H цепляет A2DP/AVRCP к уже спаренному устройству. Сосуществование A2DP↔HFP на одном устройстве — через
политику (§3): входящий `phone_call` корчит A2DP-`media`. Владелец BlueZ — ◻️ (§15, с G).
политику (§3): входящий `phone_call` корчит A2DP-`media`. Владелец BlueZ-адаптера/паринга —
Connectivity-core (домен G, резолв G §3); сосуществование A2DP↔HFP — политика §3.
- **Проекция (CarPlay/Android Auto)** несёт свои медиа+звонок — её аудио идёт ролями `projection`/`phone_call`;
контроль/протокол проекции — **G**. H лишь маршрутизирует звук по политике.
@@ -223,10 +224,10 @@ capture-нода не «дакает» вывод; дакает медиа им
- 🟡 **Декодер/кодеки:** `symphonia` (рек.) + **AAC-патент** (роялти) — юр-проверка; Opus → `audiopus`; SBC/AAC
по BT, **aptX/LDAC исключены** (#12). → tech-stack.
- 🟡 **FM-тюнер:** добавить в hardware §4 периферию **или** отказаться от радио. → hardware.
- 🟡 **Владелец BlueZ/паринга** (Connectivity vs G vs shared) + сосуществование A2DP↔HFP. → G/Connectivity.
- **Владелец BlueZ/паринга** Connectivity-core (резолв в G §3); сосуществование A2DP↔HFP — политика §3. → G.
- 🟡 **enable/mute-секвенс усилителя (anti-pop):** owner GPIO — hardware §4 (mute-GPIO), owner порядка — B §4. → hardware + B.
-**AEC** — узел audio-plane (`module-echo-cancel`/WebRTC APM), референс = output-monitor, не в ассистенте;
loopback-tap — §4. → резолв §4 (D §147; синхронизировано в d-assistant §10).
loopback-tap — §4. → резолв §4 (синхронизировано в d-assistant §10).
- ◻️ **Ранний звук на Stage-0-реверсе** (park-beep до поднятия аудио-плоскости) — нужен ли отдельный путь. → J/E/B.
- ◻️ **Split политики:** сколько в статическом WirePlumber vs Rust-координаторе (+ crash-safety проактивного
cork, тайминги гистерезиса/фейда дакинга). → реализация.
@@ -247,7 +248,7 @@ capture-нода не «дакает» вывод; дакает медиа им
| Ducking | cork (звонок) vs duck (ассистент/нав); duck — относительный аттенюатор; гистерезис/фейд (анти-pumping) | 2026-06-22 |
| Crash-safe | две оси: source (жизнь ноды + проактивный cork по `NameOwnerChanged`/watchdog) + sink (пересчёт при возврате output) | 2026-06-22 |
| Где политика | статика — конфиг WirePlumber (Stage 1, переживает крэш); динамика — координатор Media-апа | 2026-06-22 |
| AEC | `module-echo-cancel` (WebRTC APM) в audio-plane (не в ассистенте); H даёт loopback-референс — **резолв D §147** | 2026-06-22 |
| AEC | `module-echo-cancel` (WebRTC APM) в audio-plane (не в ассистенте); H даёт loopback-референс — **резолв D §10** | 2026-06-22 |
| Декодер | `symphonia` (Rust, MPL-2.0; AAC-патент на юр-проверку; Opus НЕ поддержан → `audiopus`); aptX/LDAC исключены (#12) | 2026-06-22 |
| BT-аудио | A2DP sink (SBC/AAC) + AVRCP; обрыв → cork+auto-resume; паринг/HFP — G/Connectivity (шов) | 2026-06-22 |
| Радио/стриминг | later (v3); FM требует тюнера (нет в hardware); стриминг — креды юзера, провайдер-агностик | 2026-06-22 |
+1
View File
@@ -43,6 +43,7 @@
| **OS base** | Armbian/Debian (RK3588), ядро ближе к mainline | read-only rootfs + overlay |
| **Init / lifecycle** | **systemd** | ядро; апы/плагины — App-Host |
| **CAN/OBD (read-only)** | **SocketCAN** (`socketcan`) + **ISO-TP** (`can-isotp`/`CAN_ISOTP`) для нативного OBD | ELM327 (мульти-протокол, прячет ISO-TP) на старте; `python-OBD` — в симуляторе |
| **Связь / BT** | NetworkManager · ModemManager · BlueZ (+ obexd; опц. oFono) | GPL-демоны через D-Bus (изолированы, #12); HFP-аудио — PipeWire bluez5 |
| **Wake-word** | **openWakeWord** | RU-фраза «Штурман»; Porcupine отвергнут (проприетарный, #12) |
| **VAD** | Silero VAD | через ONNX Runtime |
| **STT** | Vosk · Silero | офлайн, RU; через биндинги / `ort` |