Двунаправленные швы (спека v0.3 §10) после реализации Плана 7: - domain B: banner «Реализация (v0.3)» (B01–B07, VM-модель abort/PONR=stop+umount+remount); §12 — MCU/supercap (B08/B09) → v0.4. - ipc.md §3: Power оживлён из FSM (не mock); Sleep/Wake/RequestSleep зарезервированы. - foundation §5.2: «Power-стаб» → реальный PowerFsm (проекции state/ignition/source из FSM); dev-mock кормит входы FSM. - CLAUDE.md: статус v0.3 ГОТОВО; «Следующее» → v0.5 shell / v0.4 MCU-thermal. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Alexander <akotenev2003@gmail.com>
18 KiB
Контракт: IPC (D-Bus)
Backbone связей: реестр D-Bus-сервисов, их интерфейсов и соглашений. Формализует карту связей из architecture.md §5 в конкретные контракты. К нему цепляются data-model, plugin-sdk и все домены.
Статус: v2 (на ревью). v2 — после ретро-ревью (10 находок). Связано с: architecture.md (§4–5) · data-model.md · plugin-sdk.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.<Service> (напр. ru.shturman.VehicleData) |
| Путь объекта | /ru/shturman/<Service> |
| Интерфейс | ru.shturman.<Service>N — N = мажорная версия (напр. …VehicleData1) |
| Версионирование | аддитивно внутри версии; ломающее → добавляется …2 рядом со старым …1; оба сосуществуют в окне поддержки (старые плагины работают без правок; EOL мажора синхронизируется с shturman_api в манифесте) |
| Ошибки | ru.shturman.Error.<Name>: PermissionDenied, NotAvailable (PID не поддержан машиной — постоянно), Stale/Timeout (транзиентно: таймаут/устарело), ReadOnly, InvalidArgument, Unsupported |
| Действие | метод |
| Изменение состояния | сигнал |
| Текущее состояние | property (+ стандартный PropertiesChanged) |
| Асинхронность | всё async (zbus + tokio); долгие операции не блокируют |
| Стандартные интерфейсы | org.freedesktop.DBus.{Properties,Introspectable,Peer} |
| Идентичность вызывающего | по аутентифицированному соединению (sender → PID/cgroup → манифест, привязка App-Host'ом), НЕ по аргументу метода; подменить нельзя |
| Жизненный цикл клиент-состояния | серверное состояние клиента (подписки, регистрации тайлов/интентов) снимается автоматически при исчезновении владельца имени (NameOwnerChanged) — крэш/рестарт не оставляет мусора |
Полные сигнатуры (XML-интроспекция) фиксируются при реализации; здесь — реестр и ключевые члены.
3. Реестр сервисов — ядро (привилегированные)
ru.shturman.VehicleData — данные машины (READ-ONLY)
- Методы (только чтение):
ListSignals() → [(name, availability)],GetSignal(name) → (value, unit, ts, quality),Subscribe(names, desired_max_hz)/Unsubscribe(names),GetDtcs() → [(code, status, desc)]. - Авторизация по имени сигнала — в самом сервисе: прокси (§5) не видит payload, поэтому
vehicle_read:[…]enforce-ит VehicleData по идентичности вызывающего (sender→ манифест), отвергая незаявленные именаPermissionDenied. Сигналы адресные:SignalChanged(name, value, ts, quality)шлётся только подписчику и только поSubscribe ∩ манифест;DtcsChanged([...]). - Частота:
desired_max_hz— верхняя граница, которую готов принять подписчик, и вход в агрегатный опрос: фактический опрос PID =max()запрошенных, ограничен потолком шины (~10–20 Гц) и источником. Доставка индивидуально не троттлится — слабый клиент (приборка) прореживает сам. Имяdesired_подчёркивает: не гарантия «моей частоты». - Подписки привязаны к владельцу соединения — снимаются автоматически при крэше/рестарте; агрегатный опрос пересчитывается, опрос PID останавливается без живых подписчиков (бережёт скудный ELM327).
- Таймаут/staleness:
GetSignalимеет таймаут →Stale/Timeout(или stale-flag вquality), не виснет на медленном ELM327-PID.NotAvailable= PID не поддержан машиной (постоянно);Stale= транзиентно (двигатель заглушен/таймаут). - Properties (горячие):
Speed,Rpm,CoolantTemp,ModuleVoltage(питание ЭБУ ≈ бортсеть, не клеммы АКБ),Online. - ⛔ Методов записи нет — ни
SetSignal, ни actuator-команд, ни clear-DTC. Архитектурная гарантия read-only (принцип #2). Типы — data-model.md.
ru.shturman.Power — питание и жизненный цикл (домен B)
- Методы:
GetPowerState() → state(enumoff/accessory/running/shutting_down/sleep/battery_cutoff),RequestSleep()(внутр.). - Сигналы:
AccChanged(on),ShutdownImminent(seconds, reason)(reason ∈ acc_off|under_voltage|thermal|battery_cutoff),ShutdownAborted()(re-power до PONR),Sleep(),Wake(). - Properties:
IgnitionState(off/accessory/running — канон; E зеркалит, не дублирует),Uptime(монотонные часы),PowerSource(vehicle_12v/holdup_cap/sleep_rail/low_battery). - Реализация (v0.3): состояние/сигналы оживлены из FSM (
PowerFsmвshturman-power, не mock);ShutdownImminent/ShutdownAborted— из реальных переходов (abort до PONR + grace-таймер).Sleep/Wake/RequestSleepобъявлены, но зарезервированы (v1/v2, B §7). Источник событий (ACC/voltage/thermal через MCU) → v0.4; в v0.3 кормит dev-mock.
ru.shturman.Settings — конфигурация и состояние
- Методы:
Get(key) → value,Set(key, value),List(prefix) → [key],Reset(key). - Сигналы:
Changed(key, value). - Namespace изолирует сам сервис Settings по идентичности вызывающего (
sender→ app-id): Get/Set/List/Reset вне своего namespace →PermissionDenied(прокси этого не делает — не инспектирует строкуkey). Свой namespace — read/write по умолчанию (ambient, без отдельной capability).
ru.shturman.PermBroker — политика разрешений (привратник)
- Идентичность — только из соединения (
sender→ манифест), никогда из аргумента (иначе спуфинг/проверка за чужой ап). - Методы:
CheckCapability(cap) → bool(sender-scoped — ап спрашивает про СЕБЯ; кросс-ап форма доступна только привилегированным core по D-Bus-политике),RequestRuntimeGrant(cap) → granted(рантайм-промпт; целевой ап =sender). - Сигналы:
GrantChanged(cap, granted)— адресно владельцу гранта (чужие не получают). - Статическая фильтрация — прокси + sandbox (§5, владеет App-Host); broker — политика и рантайм-согласия.
ru.shturman.AppHost — запуск/супервизия апов и плагинов
- Методы:
ListApps() → [(id, status)],LoadApp(id)(читает манифест/data/apps/<id>/, конфигурит sandbox+прокси+sender→манифест; затем доступенStartApp),StartApp(id),StopApp(id),UnloadApp(id)(снести sandbox/прокси/identity-binding),GetStatus(id) → status. - Сигналы:
AppStarted(id),AppStopped(id),AppCrashed(id, reason),AppLoaded(id). - Установка/жизненный цикл плагинов —
ru.shturman.PluginManager(ниже, домен F): зовётLoadApp/UnloadAppпосле install/remove/update.
ru.shturman.PluginManager — установка/жизненный цикл плагинов (домен F)
- Методы:
InstallPlugin(pkg),RemovePlugin(id),UpdatePlugin(id),ListPlugins() → [(id, version, status)]. - Сигналы:
PluginInstalled(id),PluginRemoved(id),PluginUpdated(id)(+ эмит нормативных audit-записей, A §9). - Привилегированная операция — недоступна самим плагинам через прокси. Контракт детально — домен F.
ru.shturman.Connectivity — сеть (обёртка NM/MM)
- Методы:
GetStatus() → status,ListNetworks() → [...],Connect(id),Disconnect(). - Сигналы:
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(enumno_fix/fix_2d/fix_3d/augmented/dead_reckoning),HDOP,satellites,ts; per-property quality дляSpeed/Heading(зануление у нуля — domain K §2). - Сигналы:
LocationChanged(...),FixChanged(quality). - Источник — NMEA/gpsd (hardware §4); гейтится capability
location. GPS-скорость — ОТСЮДА (не из VehicleData/E). До домена K — мок-стаб (dev fake-GPS).
4. Реестр сервисов — апы (на SDK)
ru.shturman.Assistant
- Методы:
SendText(query) → reply,StartListening(),StopListening(),RegisterIntents(handler_path)— привязывает handler к фразам из манифестаassistant_intents(фразы НЕ передаются в рантайме, иначе обходится install-ревью). - Сигналы:
StateChanged(idle|listening|thinking|speaking),TranscriptUpdated(text),ReplyUpdated(text). - Контекст машины подмешивается ассистентом из
VehicleData(см. architecture §5).
ru.shturman.Shell — UX-host (слот-модель, решение №6)
- Методы:
RegisterTile(decl),RegisterScreen(decl) → slot_token(для поверхности клиент предъявляет slot-token в Wayland slot-протоколеru.shturman.shell_slot, не передаётwl_surfaceпо D-Bus — см. c-shell §4),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; здесь — только факт регистрации на шине.
ru.shturman.Camera — камеры/виды (владелец — домен J)
- Методы:
ListSources(),SelectView(id). - Сигналы:
ReverseEngaged(on)(источник —Power/GPIO, см. J §3). - Properties:
SignalStateper-source (live/no_signal/acquiring). - Видео — НЕ здесь (PipeWire/V4L2, data-plane); гейтится
camera_in(security-privacy). До домена J — мок-стаб. Детали — domains/j-cameras-video.md.
5. Брокеринг доступа песочных апов (портал-паттерн)
- Манифест плагина декларирует capabilities (
vehicle_read:[speed],network,assistant_intents…). - App-Host поднимает плагин в bubblewrap и даёт ему фильтрующий D-Bus-прокси, сконфигурированный под эти capabilities.
- Прокси даёт грубую изоляцию — сервис/интерфейс/метод/сигнал (payload/аргументы НЕ инспектирует). Пример:
vehicle_read:[speed]→VehicleData(read) достижим, аPower, чужие апы и write-методы — нет. Тонкую авторизацию по конкретному имени сигнала / ключу настроек делает сам сервис по идентичностиsender(см. VehicleData, Settings). - Рантайм-согласия (сеть «сейчас») — через
PermBroker.RequestRuntimeGrant.
Итог: плагин физически не может дотянуться до того, чего нет в манифесте. Детали модели — security-privacy.md.
6. Точки расширения через IPC
- Интенты ассистента: плагин реализует
ru.shturman.IntentHandler1.HandleIntent(intent_id, slots) → resultи регистрируется черезAssistant.RegisterIntents. Латентно-критичные интенты (громче, домой) ассистент обрабатывает локально без LLM. - Вклад в UI: плагин зовёт
Shell.RegisterTile/RegisterScreen(декларативно или поверхностью).
Полные контракты SDK (манифест, биндинги, точки расширения) — plugin-sdk.md.
Открытые вопросы (найдено на self-review → роутинг в нужные доки)
Не теряем; решается в указанных документах.
- ✅ Гейтинг data-plane, не только D-Bus. → решено в security-privacy.md §4 (PipeWire/Wayland гейтятся capability'ями через bubblewrap-сокеты). API-часть — в plugin-sdk.
- ✅ Экспорт объектов из песочницы. → решено в security-privacy.md §4
(плагин OWN под префиксом
ru.shturman.plugin.<id>.*). - ✅ Приватное хранилище апа. → решено в security-privacy.md §4
(
storage→ mount/data/apps/<id>/). - ✅ Коллизия интентов. → решено в plugin-sdk.md §5 (слоистая политика разрешения); тонкости LLM-роутинга — домен D.
- 🟡 Целостность манифеста. Модель доверия — security-privacy.md §6; подпись/стор — задел домена F.
- ◻️ Быстрый канал для приборки. → architecture.md §4 + домен E (открыто).
Журнал решений (ipc)
| Решение | Выбор | Дата |
|---|---|---|
| Топология шины | системная шина устройства + фильтрующий прокси на ап (🟡 на подтверждение) | 2026-06-16 |
| Изоляция доступа апов | портал-паттерн: per-app dbus-proxy из манифеста | 2026-06-16 |
| Соглашения имён/версий | ru.shturman.*, версия в имени интерфейса; мажоры сосуществуют в окне поддержки (аддитивно) |
2026-06-16 |
| Enforcement | грубо — прокси (сервис/метод); тонко (per-signal/per-key) — сам сервис по sender |
2026-06-16 |
| Идентичность | только из аутентиф. соединения, не из аргумента; клиент-состояние снимается по NameOwnerChanged |
2026-06-16 |
| Location/GPS | отдельный сервис ru.shturman.Location (домен K); GPS-скорость не через E |
2026-06-16 |