From 3d13bb5827982c026b98db37b2decfcf09034fc1 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 20 Jun 2026 20:01:36 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20tech-stack=20+=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BA=D1=82=D1=8B=20ipc/data-model=20(+=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D1=8C=D1=8E-=D1=84=D0=B8=D0=BA=D1=81=D1=8B)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tech-stack: Rust-first (один прод-рантайм; Python — dev-only), полный стек, крейты - architecture: ассистент Python→Rust для консистентности; boot-порядок (Broker+App-Host до Shell); потолок частоты сигналов ~10–20 Гц - contracts/ipc: реестр D-Bus (сервисы ядра/апов, соглашения, портал-брокеринг) + открытые вопросы из self-review - contracts/data-model: VSS-aligned каталог сигналов, OBD-PID маппинг, DTC-модель; добавлен MIL-статус (PID 0x01) для killer-фичи, состояние машины, расход-estimate Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/README.md | 1 + docs/architecture.md | 11 +-- docs/contracts/data-model.md | 135 ++++++++++++++++++++++++++++++++ docs/contracts/ipc.md | 146 +++++++++++++++++++++++++++++++++++ docs/tech-stack.md | 85 ++++++++++++++++++++ 5 files changed, 373 insertions(+), 5 deletions(-) create mode 100644 docs/contracts/data-model.md create mode 100644 docs/contracts/ipc.md create mode 100644 docs/tech-stack.md diff --git a/docs/README.md b/docs/README.md index 3dadd20..39353b3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,6 +16,7 @@ - [glossary.md](glossary.md) — единый словарь терминов. - [principles.md](principles.md) — сквозные принципы и ограничения (правила для всех доменов). - [architecture.md](architecture.md) — слои, процессы, шина, **карта связей**. +- [tech-stack.md](tech-stack.md) — канонический технический стек (Rust-first) и крейты. ### Tier 1 — сквозные контракты (соединительная ткань) - [contracts/](contracts/README.md) — IPC, модель данных, plugin-SDK, безопасность, железо. diff --git a/docs/architecture.md b/docs/architecture.md index 35cc3b6..2c9b1cc 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -34,9 +34,9 @@ LINUX BASE read-only rootfs + overlay · Wayland · systemd · hardware watc TRUSTED CORE Power/Lifecycle · Vehicle-Data (CAN read-only) · Settings/State (привилегии) Security/Perm-Broker · Plugin/App-Host · Connectivity │ ──────────────── control plane: D-Bus ──────────────── -SDK единый API: D-Bus + биндинги (Rust, Python…) + манифест/capabilities +SDK единый API: D-Bus + Rust SDK (биндинги др. языков — для плагинов) + манифест │ -FIRST-PARTY Shell/UX-host · Assistant (Py) · Media · Nav · Phone ← расш. права +FIRST-PARTY Shell/UX-host · Assistant · Media · Nav · Phone ← расш. права APPS (на SDK) │ PLUGINS (3rd) плагин · плагин · … ← узкие права @@ -68,7 +68,7 @@ data-plane — см. §4. | Ап | Кратко | Особое | |----|--------|--------| | **Shell/UX-host** | лаунчер, экраны, тема, driver-distraction | ещё и Wayland-**хост** UI остальных (§8) | -| **Assistant** | wake→STT→LLM→TTS, контекст машины, память о водителе (`.md`) | на Python; провайдер-агностик LLM | +| **Assistant** | wake→STT→LLM→TTS, контекст машины, память о водителе (`.md`) | Rust (ONNX Runtime + биндинги); провайдер-агностик LLM | | **Media** | аудио, BT A2DP/AVRCP, радио, стриминг | владеет аудио-политикой (с PipeWire) | | **Nav** | офлайн-карты, роутинг | богатые поверхности (карта) | | **Phone** | BT HFP, контакты, звонки | аудио через PipeWire | @@ -93,7 +93,8 @@ data-plane — см. §4. | **Camera** | **PipeWire / V4L2 (DMABUF)** | видео-источники; самые латентные (задняя камера) — почти прямой путь | Нюанс: Vehicle-Data перемалывает сырой высокочастотный CAN **внутри себя** и -публикует на шину уже digested-сигналы в разумном темпе — шина остаётся лёгкой. +публикует на шину уже digested-сигналы с потолком частоты (~10–20 Гц) — шина +остаётся лёгкой. Детали — [contracts/ipc.md](contracts/ipc.md). Камеры спроектированы как **динамический набор 0..N источников** (задняя, dashcam-фронтальная, surround), расширяемый плагинами — см. задел в @@ -153,7 +154,7 @@ graph TD **Быстрый boot фазами (цель — < 10 c до интерактива):** - **Stage 0 (мгновенно):** загрузчик → splash. Низколатентный путь задней камеры/парктроника, если включена задняя. -- **Stage 1 (~3–5 c):** ядро-минимум (шина + Power + Settings) → **Shell с первым кадром** (home-тайлы кликабельны). +- **Stage 1 (~3–5 c):** ядро-минимум (шина + Power + Settings + **Perm-Broker + App-Host**) → **Shell с первым кадром** (home-тайлы кликабельны). Broker/App-Host нужны раньше Shell: Shell — тоже ап и поднимается/цепляется к шине через них. - **Stage 2 (фоном):** Vehicle-Data, Assistant, Media, Nav прогреваются после того, как UI интерактивен. **Завершение:** ACC-off → Power/Lifecycle инициирует graceful shutdown (systemd-таргет): апам сигнал «сохранись», Settings флашится в `/data`, размонтирование, снятие питания через supercap/MCU-копилот. Вместе с read-only rootfs это защита от corruption. diff --git a/docs/contracts/data-model.md b/docs/contracts/data-model.md new file mode 100644 index 0000000..269600b --- /dev/null +++ b/docs/contracts/data-model.md @@ -0,0 +1,135 @@ +# Контракт: модель данных машины (VSS-подобная) + +> Канонический каталог сигналов, которые публикует `VehicleData`. Наполняет +> конкретикой ipc-контракт, кормит контекст ассистента, домен E и killer-фичу. + +Статус: **v1 (на ревью).** +Связано с: [ipc.md](ipc.md) (`VehicleData`) · [domains/](../domains/README.md) (E: Vehicle-Data) · [hardware.md](hardware.md) · [principles.md](../principles.md) (#4) + +--- + +## 1. Подход: VSS-aligned, но лёгкий + +- Имена сигналов — в стиле **COVESA VSS** (иерархические пути), типы и единицы — по + VSS. Но держим **свой лёгкий каталог**, а не тащим полный VSS-тулинг (Franca/ + генераторы). Достаточно совместимости «по духу», чтобы говорить на общем языке и + легко расширяться. +- 🟡 *Выбор на подтверждение:* лёгкий VSS-aligned каталог (рекомендую) vs полное + принятие VSS-спеки с тулингом (тяжелее, избыточно на старте). + +## 2. Модель сигнала + +Каждый сигнал описывается: + +| Поле | Смысл | +|------|-------| +| `id` | канонический VSS-стиль путь (напр. `Vehicle.Speed`) | +| `alias` | короткое имя для эргономики (`speed`) | +| `type` | `float` / `int` / `bool` / `enum` | +| `unit` | каноническая единица (**SI-стиль**: km/h, rpm, °C, V, %, g/s, kPa) | +| `range` | допустимый диапазон | +| `source` | откуда читается: OBD-PID / native-CAN(DBC) / **computed** | +| `availability` | поддерживается ли данной машиной (динамически) | +| `ts` | метка времени значения (для свежести) | + +**Транспорт-агностичность (важно):** сигнал каноничен, а **источник — это +per-vehicle маппинг.** Один и тот же `Vehicle.Speed` может читаться через ELM327 +(OBD-PID `0x0D`) или нативный SocketCAN (сигнал из DBC). Это и есть мост «ELM327 на +старте → SocketCAN в проде» и основа портирования под разные авто (см. [hardware.md](hardware.md)). + +**Единицы и локаль:** в модели — каноническая SI; отображение (km vs miles) — +дело shell/настроек, конвертация на презентации, не в модели. + +## 3. Доступность сигналов (per-vehicle) + +Не все машины отдают все PID. `VehicleData` при старте **пробит поддерживаемые +PID** (Mode 01, PID `0x00/0x20/0x40/…` — битовые маски поддержки) и помечает +сигнал `Unavailable`, если его нет. Консьюмеры (ассистент, UI) обязаны это +учитывать — «нет данных», а не падение (принцип #4). + +## 4. Каталог стартовых сигналов (OBD-II Mode 01) + +> `id` — наш канонический путь (≈ VSS, **точные VSS-листы сверяем со спецификацией +> при реализации**). Базовый набор; расширяем по ходу домена E. +> +> **`mil_on` (PID 0x01) — ключевой для killer-фичи** «почему горит чек»: это сам +> факт горящей лампы + число ошибок, отдельно от их чтения (Mode 03). +> `module_voltage` (0x42) — напряжение питания ЭБУ ≈ бортсеть (близко, но не ровно клеммы АКБ). + +| alias | id (≈ VSS) | PID | type | unit | range | +|-------|-----------|-----|------|------|-------| +| `speed` | `Vehicle.Speed` | 0x0D | int | km/h | 0..255 | +| `rpm` | `Vehicle.Powertrain.CombustionEngine.Speed` | 0x0C | float | rpm | 0..16383 | +| `engine_load` | `…CombustionEngine.Load` | 0x04 | float | % | 0..100 | +| `coolant_temp` | `…CombustionEngine.ECT` | 0x05 | int | °C | -40..215 | +| `intake_temp` | `…CombustionEngine.IAT` | 0x0F | int | °C | -40..215 | +| `maf` | `…CombustionEngine.MAF` | 0x10 | float | g/s | 0..655 | +| `throttle` | `…CombustionEngine.TPS` | 0x11 | float | % | 0..100 | +| `intake_pressure` | `…CombustionEngine.MAP` | 0x0B | int | kPa | 0..255 | +| `fuel_level` | `Vehicle.Powertrain.FuelSystem.Level` | 0x2F | float | % | 0..100 | +| `module_voltage` | `Vehicle.LowVoltageBattery.Voltage` | 0x42 | float | V | 0..65.5 | +| `ambient_temp` | `Vehicle.Exterior.AirTemperature` | 0x46 | int | °C | -40..215 | +| `oil_temp` | `…CombustionEngine.EOT` | 0x5C | int | °C | -40..215 | +| `fuel_rate` | `…CombustionEngine.FuelRate` | 0x5E | float | L/h | 0..3212 | +| `run_time` | `…CombustionEngine.RunTime` | 0x1F | int | s | 0..65535 | +| `mil_on` | `Vehicle.OBD.IsMILOn` | 0x01 | bool | — | вкл/выкл | +| `dtc_count` | `Vehicle.OBD.DTCCount` | 0x01 | int | шт | 0..255 | +| `distance_mil` | `Vehicle.OBD.DistanceWithMIL` | 0x21 | int | km | 0..65535 | + +## 5. Производные (computed) сигналы + +Слой поверх сырых — считаются внутри VehicleData (или отдельного компонента): + +- **Мгновенный расход** — если есть прямой `fuel_rate` (0x5E), берём его; иначе + **оценка** из MAF (предполагает бензин/стехиометрию — помечаем как `estimate`, + зависит от типа топлива). +- **Пробег поездки / средний расход** (интеграл по времени; нужен trip-стейт). +- **Состояние машины** (`off` / `accessory` / `running`) — грубо из RPM/зажигания; + нужно ассистенту, чтобы отличать «двигатель заглушен» от «сигнал недоступен» от «ноль». +- Помечаются `source = computed`; зависят от наличия исходных сигналов. + +## 6. Модель DTC (диагностические коды) + +- **Формат кода:** буква (`P` powertrain / `C` chassis / `B` body / `U` network) + + 4 hex-цифры. Грубо: `0` — стандарт SAE/ISO, `1` — производитель (полная карта + сложнее: `P2xxx` тоже стандарт, `P3xxx` смешанные). +- **Статусы:** `confirmed` (Mode 03), `pending` (Mode 07), `permanent` (Mode 0A). +- **Чтение:** Modes 03/07/0A — это **чтение**, разрешено. + ⛔ **Сброс (Mode 04) — НЕТ.** Read-only (принцип #2). +- **Расшифровка двухслойная:** статическая база `код → стандартное описание` + (живёт в домене E, `vehicle/dtc/`) + **LLM** даёт человеческое объяснение + по-русски в контексте машины. Manufacturer-specific (`P1xxx`) требуют вендорской + базы (задел, §7). + +## 7. Расширение: вендорские сигналы и коды (задел) + +- Нативный CAN конкретного авто описывается **DBC-файлом** → даёт сигналы сверх + стандартного OBD и вендорские DTC. +- Это per-vehicle/per-OEM маппинг, ложится на **HAL/board-support** ([hardware.md](hardware.md)) + и на портирование силами автопроизводителей/энтузиастов (vision: «API под + конкретное железо/авто»). Плагин/порт может поставлять свой DBC + базу кодов. + +--- + +## Открытые вопросы (найдено на self-review → роутинг) + +- **Минимальный набор PID на простых авто.** Старые/простые машины (наша целевая + аудитория — Lada и т.п.) отдают мало Mode-01 PID. **MVP killer-фичи опирается на + универсальное:** `mil_on` + чтение DTC (Mode 03); богатые PID — best-effort. → домен E. +- **«Почему вырос расход».** Для этого кейса из vision полезны топливные коррекции + (Short/Long Term Fuel Trim, PID 0x06–0x09) и данные O2 — диагностическое расширение. → домен E. +- **Идентификация авто (VIN).** Mode 09 PID 0x02 — даёт привязку к конкретной машине + (память о водителе, вендорские базы кодов). Задел. → домен E + домен D. +- **DBC для нативного CAN часто проприетарны** или добываются реверсом + (community-DBC, opendbc). Учесть в портировании. → [hardware.md](hardware.md) + домен E. + +--- + +## Журнал решений (data-model) + +| Решение | Выбор | Дата | +|---------|-------|------| +| Глубина VSS | лёгкий VSS-aligned каталог (🟡 на подтверждение) | 2026-06-16 | +| Источник сигнала | транспорт-агностичен: канон + per-vehicle маппинг (PID / DBC / computed) | 2026-06-16 | +| Единицы | каноническая SI в модели; конвертация на презентации | 2026-06-16 | +| DTC | чтение Modes 03/07/0A; сброс (04) запрещён; расшифровка база + LLM | 2026-06-16 | diff --git a/docs/contracts/ipc.md b/docs/contracts/ipc.md new file mode 100644 index 0000000..7dc0cb2 --- /dev/null +++ b/docs/contracts/ipc.md @@ -0,0 +1,146 @@ +# Контракт: IPC (D-Bus) + +> Backbone связей: реестр D-Bus-сервисов, их интерфейсов и соглашений. +> Формализует карту связей из [architecture.md](../architecture.md) §5 в конкретные +> контракты. К нему цепляются data-model, plugin-sdk и все домены. + +Статус: **v1 (на ревью).** +Связано с: [architecture.md](../architecture.md) (§4–5) · [data-model.md](data-model.md) · [plugin-sdk.md](plugin-sdk.md) · [security-privacy.md](security-privacy.md) + +Область: **control plane** (D-Bus). Аудио/видео/графика — НЕ здесь (PipeWire/Wayland, см. architecture §4). + +--- + +## 1. Шина и топология + +- **Одна системная шина устройства** (Штурман — single-purpose appliance, системная шина *и есть* его шина) со строгой D-Bus-политикой. +- Ядро-сервисы общаются на ней напрямую. +- **Песочные апы/плагины напрямую шину НЕ видят** — каждому выдаётся + **фильтрующий D-Bus-прокси** (паттерн `xdg-dbus-proxy`), настроенный App-Host'ом + из capabilities манифеста (см. §5). Это реализация портал-модели из решения №5. + +> 🟡 *Мелкий выбор на подтверждение:* системная шина устройства (рекомендую, +> проще) vs выделенный экземпляр `dbus-daemon` только для Штурмана (чище изоляция +> от хост-сервисов, но лишний компонент). Прокси-фильтрация даёт изоляцию в обоих +> случаях. + +## 2. Соглашения + +| Аспект | Правило | +|--------|---------| +| Well-known имя | `ru.shturman.` (напр. `ru.shturman.VehicleData`) | +| Путь объекта | `/ru/shturman/` | +| Интерфейс | `ru.shturman.N` — `N` = мажорная версия (напр. `…VehicleData1`) | +| Версионирование | аддитивные изменения внутри версии; ломающие → новый интерфейс `…2` | +| Ошибки | `ru.shturman.Error.`: `PermissionDenied`, `NotAvailable`, `ReadOnly`, `InvalidArgument`, `Unsupported` | +| Действие | **метод** | +| Изменение состояния | **сигнал** | +| Текущее состояние | **property** (+ стандартный `PropertiesChanged`) | +| Асинхронность | всё async (zbus + tokio); долгие операции не блокируют | +| Стандартные интерфейсы | `org.freedesktop.DBus.{Properties,Introspectable,Peer}` | + +> Полные сигнатуры (XML-интроспекция) фиксируются при реализации; здесь — реестр и ключевые члены. + +--- + +## 3. Реестр сервисов — ядро (привилегированные) + +### `ru.shturman.VehicleData` — данные машины (**READ-ONLY**) +- **Методы (только чтение):** `ListSignals() → [name]`, `GetSignal(name) → (value, unit, ts)`, `Subscribe(names, max_hz)`/`Unsubscribe(names)`, `GetDtcs() → [(code, status, desc)]`. +- **Сигналы:** `SignalChanged(name, value, ts)` — **только подписчикам и только по подписанным** именам (не широковещательно «всё всем»), `DtcsChanged([...])`. +- **Политика частоты:** на шину сигналы идут **с потолком (~10–20 Гц)** — этого хватает для читаемых датчиков и держит control-plane лёгким. Сырой высокочастотный CAN остаётся внутри VehicleData. Цифровому приборному щитку, если нужна более плавная стрелка, — клиентская интерполяция или выделенный быстрый канал (не D-Bus); см. «Открытые вопросы». +- **Properties (горячие, текущее значение):** `Speed`, `Rpm`, `CoolantTemp`, `BatteryVoltage`, `Online`. +- ⛔ **Методов записи нет** — ни `SetSignal`, ни actuator-команд, ни clear-DTC. Архитектурная гарантия read-only (принцип #2). Типы — [data-model.md](data-model.md). + +### `ru.shturman.Power` — питание и жизненный цикл +- **Методы:** `GetPowerState() → state`, `RequestSleep()` (внутр.). +- **Сигналы:** `AccChanged(on)`, `ShutdownImminent(seconds)`, `Sleep()`, `Wake()`. +- **Properties:** `IgnitionState`, `Uptime`, `PowerSource`. + +### `ru.shturman.Settings` — конфигурация и состояние +- **Методы:** `Get(key) → value`, `Set(key, value)`, `List(prefix) → [key]`, `Reset(key)`. +- **Сигналы:** `Changed(key, value)`. +- Namespace на каждый ап изолирован (брокер не даёт читать чужой). + +### `ru.shturman.PermBroker` — выдача разрешений (привратник) +- **Методы:** `CheckCapability(app, cap) → bool`, `RequestRuntimeGrant(cap) → granted` (рантайм-промпт пользователю, напр. «ап X хочет сеть»). +- **Сигналы:** `GrantChanged(app, cap, granted)`. +- Основная фильтрация — на уровне прокси (§5); этот API для рантайм-согласий. + +### `ru.shturman.AppHost` — запуск/супервизия апов и плагинов +- **Методы:** `ListApps() → [(id, status)]`, `StartApp(id)`, `StopApp(id)`, `GetStatus(id) → status`. +- **Сигналы:** `AppStarted(id)`, `AppStopped(id)`, `AppCrashed(id, reason)`. +- (Установка/дистрибуция плагинов — домен F, не здесь.) + +### `ru.shturman.Connectivity` — сеть (обёртка NM/MM) +- **Методы:** `GetStatus() → status`, `ListNetworks() → [...]`, `Connect(id)`, `Disconnect()`. +- **Сигналы:** `ConnectivityChanged(online)`, `NetworkChanged(...)`. +- **Properties:** `Online`, `Type` (wifi/modem), `SignalStrength`. + +--- + +## 4. Реестр сервисов — апы (на SDK) + +### `ru.shturman.Assistant` +- **Методы:** `SendText(query) → reply`, `StartListening()`, `StopListening()`, `RegisterIntents(handler_path, [pattern])` (для плагинов с capability `assistant_intents`). +- **Сигналы:** `StateChanged(idle|listening|thinking|speaking)`, `TranscriptUpdated(text)`, `ReplyUpdated(text)`. +- Контекст машины подмешивается ассистентом из `VehicleData` (см. architecture §5). + +### `ru.shturman.Shell` — UX-host (слот-модель, решение №6) +- **Методы:** `RegisterTile(decl)`, `RegisterScreen(decl | surface_handle)`, `RequestForeground(slot)`, `ShowOverlay(decl)`. +- **Сигналы:** `ForegroundChanged(app)`, `NavigatedTo(screen)`, `DistractionModeChanged(level)`. +- Декларативный вклад = данные (рендерит shell); богатый = Wayland-поверхность. + +### `ru.shturman.Media` / `…Nav` / `…Phone` +- Свои интерфейсы (play/pause/route; navigateTo/cancel; dial/answer/hangup). **Детали — в спеках доменов** H/I/G; здесь — только факт регистрации на шине. + +--- + +## 5. Брокеринг доступа песочных апов (портал-паттерн) + +1. Манифест плагина декларирует capabilities (`vehicle_read:[speed]`, `network`, `assistant_intents`…). +2. App-Host поднимает плагин в bubblewrap и даёт ему **фильтрующий D-Bus-прокси**, сконфигурированный под эти capabilities. +3. Прокси пропускает только разрешённые сервисы/интерфейсы/методы/сигналы. Пример: `vehicle_read:[speed]` → виден `VehicleData.GetSignal("speed")` и `SignalChanged` по speed; **не виден** `Power`, чужие апы, любые write-методы. +4. Рантайм-согласия (сеть «сейчас») — через `PermBroker.RequestRuntimeGrant`. + +Итог: плагин физически не может дотянуться до того, чего нет в манифесте. Детали модели — [security-privacy.md](security-privacy.md). + +--- + +## 6. Точки расширения через IPC + +- **Интенты ассистента:** плагин реализует `ru.shturman.IntentHandler1.HandleIntent(intent_id, slots) → result` и регистрируется через `Assistant.RegisterIntents`. Латентно-критичные интенты (громче, домой) ассистент обрабатывает локально без LLM. +- **Вклад в UI:** плагин зовёт `Shell.RegisterTile/RegisterScreen` (декларативно или поверхностью). + +Полные контракты SDK (манифест, биндинги, точки расширения) — [plugin-sdk.md](plugin-sdk.md). + +--- + +## Открытые вопросы (найдено на self-review → роутинг в нужные доки) + +Не теряем; решается в указанных документах. + +- **Гейтинг data-plane, не только D-Bus.** Портал-прокси (§5) фильтрует D-Bus, но + доступ к **PipeWire (аудио)** и **Wayland (графика)** тоже надо гейтить + capability'ями (через bubblewrap-сокеты). → [security-privacy.md](security-privacy.md) + [plugin-sdk.md](plugin-sdk.md). +- **Экспорт объектов из песочницы.** Чтобы Assistant/Shell звали `IntentHandler`/UI + плагина, прокси должен разрешать плагину **OWN/экспорт** своих объектов под + ограниченным префиксом. → [security-privacy.md](security-privacy.md). +- **Приватное хранилище апа.** Capability `storage` должна давать апу приватную + writable-директорию в `/data` (монтирует bubblewrap). → [security-privacy.md](security-privacy.md). +- **Коллизия интентов.** Два плагина регистрируют пересекающиеся фразы — нужна + политика разрешения (приоритет / namespace / выбор пользователя). → [plugin-sdk.md](plugin-sdk.md) + домен D. +- **Целостность манифеста.** Для сторонней дистрибуции — подпись/верификация + манифеста (защита от подмены capabilities). → домен F + [security-privacy.md](security-privacy.md). +- **Быстрый канал для приборки.** Если цифровой щиток требует плавнее, чем потолок + шины — спроектировать выделенный канал. → [architecture.md](../architecture.md) §4 + домен E. + +--- + +## Журнал решений (ipc) + +| Решение | Выбор | Дата | +|---------|-------|------| +| Топология шины | системная шина устройства + фильтрующий прокси на ап (🟡 на подтверждение) | 2026-06-16 | +| Изоляция доступа апов | портал-паттерн: per-app dbus-proxy из манифеста | 2026-06-16 | +| Соглашения имён/версий | `ru.shturman.*`, версия в имени интерфейса | 2026-06-16 | diff --git a/docs/tech-stack.md b/docs/tech-stack.md new file mode 100644 index 0000000..8eb945e --- /dev/null +++ b/docs/tech-stack.md @@ -0,0 +1,85 @@ +# Технический стек + +> Канонический список технологий Штурмана с обоснованием — источник правды по +> «на чём пишем». Архитектурные *решения* — в [architecture.md](architecture.md); +> здесь — конкретные технологии и крейты. + +Статус: **v1 (на ревью).** +Связано с: [architecture.md](architecture.md) · [principles.md](principles.md) (#11 отзывчивость, #12 лицензии) · [dev-environment.md](dev-environment.md) + +--- + +## Язык: Rust-first, один прод-рантайм + +**Всё, что мы шипим, — на Rust.** Core, SDK, shell и весь прикладной слой, +включая ассистента. + +- **Почему:** один тулчейн, минимальный footprint (важно на RK3588 и 16 ГБ-dev), + единый sandbox-профиль, безопасность памяти, перформанс (принцип #11 — отзывчивость). +- **ML без Python в проде:** STT/TTS/VAD — через **ONNX Runtime** (крейт `ort`) и + нативные биндинги (Vosk, llama.cpp); облачные LLM — обычный HTTP. PyTorch в прод + не тащим. +- **Python — только в dev:** прототипы, Vehicle Simulator, скрипты, CI-утилиты. +- **Escape-hatch:** если у конкретной ML-возможности нет вменяемого Rust-пути — + она шипится **изолированным Python-sidecar процессом** (архитектура позволяет: + всё и так отдельные процессы на D-Bus + sandbox). Это исключение, не правило. +- **SDK язык-агностичен для плагинов:** транспорт — D-Bus, поэтому сторонний + плагин можно писать на любом языке. Биндинги: **Rust — first-class**, другие + (Python…) — по мере нужды экосистемы. + +--- + +## Полный стек + +| Слой / концерн | Выбор | Примечание | +|----------------|-------|------------| +| **Языки (прод)** | **Rust** | единственный шипимый рантайм | +| **Языки (dev)** | Python | прототипы, Vehicle Simulator, скрипты — не в проде | +| **UI** | **Slint** | декларативный, GPU-ускоренный, Rust-native | +| **Графика** | **Wayland** (`cage` kiosk) · Panfrost/Mesa | один композитор — shell | +| **Аудио/видео plane** | **PipeWire** + WirePlumber | микрофон, TTS, медиа, BT-аудио | +| **IPC (control plane)** | **D-Bus** | низкополосное управление и события | +| **Песочница** | **bubblewrap** + systemd-hardening | апы/плагины; WASM-тир — позже | +| **OS base** | Armbian/Debian (RK3588), ядро ближе к mainline | read-only rootfs + overlay | +| **Init / lifecycle** | **systemd** | ядро; апы/плагины — App-Host | +| **CAN/OBD (read-only)** | **SocketCAN** (крейт `socketcan`) | ELM327 на старте; `python-OBD` — только в симуляторе | +| **Wake-word** | openWakeWord / Porcupine | кастомная RU-фраза | +| **VAD** | Silero VAD | через ONNX Runtime | +| **STT** | Vosk · Silero | офлайн, RU; через биндинги / `ort` | +| **TTS** | Silero | офлайн, RU | +| **LLM онлайн** | GigaChat · YandexGPT | HTTP, provider-agnostic, 152-ФЗ | +| **LLM офлайн** | llama.cpp / Ollama | квантованная мелкая модель | +| **Карты (фаза 2)** | MapLibre + Valhalla/OSRM | офлайн | +| **Dev VM** | Lima (vz-backend) | ARM64, нативная виртуализация | +| **CI** | GitHub Actions, ARM64-Linux | совпадает с таргетом | +| **Сборка / оркестрация** | Cargo (workspace) + `justfile` | | +| **Лицензия / гигиена** | **MIT** · `cargo-deny` | без AGPL-заразы (принцип #12) | + +--- + +## Ключевые крейты (Rust) + +| Концерн | Крейт | +|---------|-------| +| D-Bus | `zbus` | +| UI | `slint` | +| Async-рантайм | `tokio` | +| SocketCAN | `socketcan` | +| ONNX-инференс (STT/TTS/VAD) | `ort` (ONNX Runtime) | +| Локальная LLM | биндинги `llama.cpp` | +| STT (Vosk) | `vosk` | +| HTTP (облачные LLM) | `reqwest` | +| Сериализация | `serde` | +| Логи/трейсинг | `tracing` | + +> Список крейтов уточняется при проектировании доменов; здесь — опорные. + +--- + +## Журнал решений (stack) + +| Решение | Выбор | Дата | +|---------|-------|------| +| Язык прод-рантайма | **Rust-first, один рантайм** (Python — dev-only; sidecar как escape-hatch) | 2026-06-16 | +| ML в проде | ONNX Runtime (`ort`) + нативные биндинги, без PyTorch | 2026-06-16 | +| SDK для плагинов | язык-агностичен (D-Bus); Rust — first-class | 2026-06-16 |