From 1eaa0b8896d2c1d5a085b95b6f5c4bf84c758590 Mon Sep 17 00:00:00 2001 From: Alexander Date: Tue, 23 Jun 2026 13:55:40 +0300 Subject: [PATCH] =?UTF-8?q?docs(domain=20L):=20v2=20=E2=80=94=20=D0=BE?= =?UTF-8?q?=D0=B1=D0=BB=D0=B0=D0=BA=D0=BE/=D0=BA=D0=BE=D0=BC=D0=BF=D0=B0?= =?UTF-8?q?=D0=BD=D1=8C=D0=BE=D0=BD=20(Companion+OTA-=D0=BA=D0=B0=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB+=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80?= =?UTF-8?q?=D0=B8=D1=8F),=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20adversarial-?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20(21=20=D0=BD=D0=B0=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=D0=BA=D0=B0)=20+=20=D0=BA=D1=80=D0=BE=D1=81=D1=81-=D0=B4?= =?UTF-8?q?=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Новый домен L: device-Companion-сервис + моб.приложение + опц.self-hostable облако. Облако опционально, local-first, никогда не управляет машиной. Многоагентный adversarial-ревью: 30 находок, 21 подтверждена (default-refute), все применены. Ключевое из ревью: - OTA untrusted-host неполон без anti-rollback → добавлена монотонность security-version (downgrade/replay-защита); подпись ≠ свежесть. Зеркально в a-base §5. - fscrypt-ключ eFuse-bound непереносим → честно: cross-device restore требует отдельного backup-ключа (открыто); убрана ложная «ключ у пользователя». - DOWNLOAD(L) ≠ APPLY(A): разведены фазы; download-fail-safe (ENOSPC/resume/отбраковка битого до RAUC) симметрично J/H. - Time-gate (a-base §7): холодный boot 1970 → TLS «not yet valid» — OTA/sync/телеметрия ждут вменяемых часов. - Captive-portal (G): egress только при State==online, не на portal/limited. - Телеметрия: consent/буфер стираются на factory-reset (инвариант «после reset все opt-in выкл»); не ретроспективна; отзыв → дроп буфера; облако: retention+удаление (152-ФЗ). - Поездки — из trip-плагина (app-storage), не из core E. - dashcam-бэкап: отдельный носитель + consent-гейт J §4. - Staged-rollout halt-петля + парадокс с opt-in телеметрией; push-доставка; модель аккаунта (recovery/multi-vehicle/multi-user); version-skew моб↔головблок — зафиксированы. Кросс-док: a-base §5 (anti-rollback + Журнал), §12 (telemetry-consent в wipe); architecture §3 (Companion first-party) + §5 (ребро Companion→Connectivity). Co-Authored-By: Claude Opus 4.8 --- docs/architecture.md | 2 + docs/domains/a-base-system.md | 8 +- docs/domains/l-cloud-companion.md | 235 ++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 docs/domains/l-cloud-companion.md diff --git a/docs/architecture.md b/docs/architecture.md index 80849b1..4eb3330 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -74,6 +74,7 @@ data-plane — см. §4. | **Media** | аудио, BT A2DP/AVRCP, радио, стриминг | владеет аудио-политикой (с PipeWire) | | **Nav** | офлайн-карты, роутинг | богатые поверхности (карта) | | **Phone** | BT HFP, контакты, звонки | аудио через PipeWire | +| **Companion** | моб.приложение-компаньон, синк/бэкап, OTA-канал, opt-in телеметрия | local-first; облако опц./self-hostable (домен L) | ### Сторонние плагины @@ -120,6 +121,7 @@ dashcam-фронтальная, surround), расширяемый плагина | все апы | Settings/State | D-Bus | чтение/запись настроек | | Vehicle-Data | CAN/OBD | драйвер | **только чтение** | | Power/Lifecycle | все | D-Bus сигналы | ACC-on/off, shutdown, sleep | +| Companion (L) | Connectivity → сеть | D-Bus/сеть | OTA-доставка, синк, opt-in телеметрия (облако опц.) | ```mermaid graph TD diff --git a/docs/domains/a-base-system.md b/docs/domains/a-base-system.md index 247f2ce..ffc0393 100644 --- a/docs/domains/a-base-system.md +++ b/docs/domains/a-base-system.md @@ -86,6 +86,10 @@ - **(рек.) RAUC**: атомарные **A/B**-обновления (юнит = kernel+dtb+initramfs+rootfs), **подписанные** bundle, **откат** при сбое. +- **Anti-rollback (downgrade-защита, v4):** подпись гарантирует аутентичность, **не свежесть** → A хранит + **монотонный security-version-счётчик** (eFuse-fuse / U-Boot env, модель AVB rollback-index) и отвергает + валидно-подписанный, но **downgrade/replay**-бандл. Иначе скомпрометированный OTA-хост (домен L) откатил бы + парк на подписанную дырявую прошивку. A/B-откат (ниже) — failure-recovery, **не** downgrade-защита (разные вещи). - **Handshake отката (обязателен, иначе откат не работает):** - В **U-Boot env на eMMC** (не в overlay/`/data`): активный слот, «try»-слот, счётчик попыток + `bootlimit`. @@ -177,7 +181,7 @@ ## 12. Factory reset (сброс к заводским) Атомарная очистка/реинициализация **только `/data`** (wipe поддеревьев apps-storage, -память водителя `.md`, **контакты/журнал (G, в apps-storage)**, токены, Settings, **dashcam-медиа +память водителя `.md`, **контакты/журнал (G, в apps-storage)**, токены, Settings, **telemetry-consent + буфер телеметрии + все opt-in-согласия (L §8)**, **dashcam-медиа (J §4 — на отдельном носителе/разделе)**; RO base-образ/BSP/device-identity сохраняются). Зачем: продажа/передача авто (стереть ПДн — security-privacy §7), recovery после порчи конфигурации, UX-выход из неработоспособности. Из recovery-режима + подтверждение @@ -247,7 +251,7 @@ reference-таргет — first-party**, остальное — порты. | Overlay | upper/work на volatile tmpfs; персист только через `/data` | 2026-06-16 | | ФС `/data` | f2fs (рек.) / ext4; power-safe mount-опции + atomic write (fsync/rename) (🟡) | 2026-06-16 | | Boot-фазы | splash в Stage 0, ядро в Stage 1 (по architecture §6) | 2026-06-16 | -| OTA | RAUC A/B + bootcount/bootlimit + mark-good (Shell-кадр); A=механизм/подпись, L=канал (🟡) | 2026-06-16 | +| OTA | RAUC A/B + bootcount/bootlimit + mark-good (Shell-кадр); A=механизм/подпись/**anti-rollback**, L=канал; downgrade-защита ≠ failure-откат (🟡) | 2026-06-16 | | Secure boot | OTP-eFuse, необратим; dev-ключи ≠ prod, на dev не жжём; v4 | 2026-06-16 | | Доверие | secure boot (анкор) + подписанный OTA; в dev — trust-by-build, полное — v4 | 2026-06-16 | | Watchdog | SoC WDT + MCU; вооружён в boot-окне; единственный userspace-владелец | 2026-06-16 | diff --git a/docs/domains/l-cloud-companion.md b/docs/domains/l-cloud-companion.md new file mode 100644 index 0000000..bac4e19 --- /dev/null +++ b/docs/domains/l-cloud-companion.md @@ -0,0 +1,235 @@ +# Домен L — Облако / компаньон + +> Апсайд-слой поверх локальной системы: мобильное приложение-компаньон, синхронизация/бэкап, +> **OTA-канал** (сборка/хостинг/доставка) и **opt-in телеметрия**. **Облако опционально и +> self-hostable** — система полноценна без него (vision: открыта в любом случае, #3). Никогда не +> управляет машиной. + +Статус: **v2 (на ревью).** v2 — после adversarial-ревью (21 находка). +Связано с: [a-base-system.md](a-base-system.md) (§5 OTA-механизм/подпись/anti-rollback, §3 fscrypt, §7 время/TLS-gate, §9 audit, §12 factory-reset) · [security-privacy.md](../contracts/security-privacy.md) (§5 грант, §7 телеметрия/152-ФЗ) · [ipc.md](../contracts/ipc.md) (`Settings`, `Power`, `Connectivity`) · [architecture.md](../architecture.md) (§3 Companion first-party, §5 карта связей) · домены **G** (Connectivity-транспорт: `State`/metered/portal), **D** (§7 память водителя — синк), **E** (live-данные/DTC — read-only), **F**/plugin-sdk (§8 trip-плагин — поездки), **J** (§4 dashcam-гейт), **B** (§4/§7 lifecycle OTA), **C** (consent/UI) · [principles.md](../principles.md) (#1,#2,#3,#7,#8,#12,#13) + +--- + +## 1. Назначение и границы + +- **Что делает:** (1) **компаньон** — моб.приложение, спаренное с головблоком (просмотр данных машины/DTC + и поездок, просмотр/правка памяти водителя, настройки, уведомления); (2) **синхронизация/бэкап** `/data`; + (3) **OTA-канал** — сборка/хостинг/доставка подписанных образов (применяет/верифицирует A); + (4) **телеметрия** — opt-in, выключена по умолчанию. +- **Облако опционально и self-hostable (#3):** все ключевые функции работают **локально device↔телефон** + (по близости, без облака); облако — лишь relay/хостинг для удалённого и OTA. Нет облака — система полноценна. +- **Границы (красные линии):** + - **Никогда не управляет машиной (#1/#2):** компаньон/облако — **read-only** к данным машины (через + головблок, сам read-only к CAN); удалённых actuator-команд нет, write-путь не существует. + - **Приватность (#7/152-ФЗ):** телеметрия opt-in; память водителя / контакты / точная локация / **dashcam-медиа** — + **не в облако без явного отзываемого согласия** (security-privacy §7, J §4); данные в РФ; облако — RU/self-hosted. + - **L — «первый продукт»/ретрофит-слой** (vision-лестница): созревает поздно (v3–v4), апсайд, не ядро. +- **Plane:** control/синк/телеметрия — поверх IP (Connectivity, G); локально device↔телефон — лок.сеть/BT. + +## 2. Архитектура L (три части, local-first) + +- **Device-side — `Companion`-сервис** (first-party ап на SDK, головблок; architecture §3): локальный API для + моб.приложения, координирует синк (Settings/State + память D §7), **триггерит OTA** (применяет A §5), собирает + opt-in телеметрию. Поднимается на **Stage 2** (фоном, как Connectivity; architecture §6) — boot-окно-поверхности нет. +- **Моб.приложение** (off-device артефакт): iOS/Android; стек — 🟡 (§3). +- **Опциональное облако** (self-hostable, RU): relay синка (когда нет близости), **хостинг OTA-бандлов** + (untrusted — A верифицирует подпись + anti-rollback, §7), приём opt-in телеметрии. Provider-agnostic (#8). +- **Local-first:** по близости device↔телефон общаются напрямую (лок.WiFi/BT), облако не нужно. + +## 3. Companion-приложение (моб.) + +- **Функции:** просмотр **данных машины/DTC** (read-only, из E) и **поездок** (из storage trip-плагина, + plugin-sdk §8 — не из core E), **просмотр/правка/чистка памяти водителя** (`.md`, D §7), управление + настройками (зеркало Settings), уведомления (§5), статус OTA. +- **Стек 🟡:** моб.приложение **off-device**, поэтому Rust-first-правило прода (tech-stack — про головблок) на + него не распространяется. Кандидаты: Flutter (один кодбейс) **или** Rust-core + native-UI. MIT (#12). → §15. +- **Фаза:** v3. + +## 4. Паринг и доверие + +- **Локальный якорь доверия:** головблок показывает pairing-код/QR → ввод/скан в приложении → **per-peer общий + ключ** (BT/Tailscale-стиль). **Аккаунт в облаке не обязателен** для локального паринга/синка. +- Спаренный телефон — доверенный peer; список спаренных, **отзыв — в Companion-сервисе** (с головблока, без + телефона; слот C §4). **Модель ролей между несколькими peer'ами** (владелец vs гость: что гость видит/правит, + особенно память водителя) и **адресация N головблоков одним аккаунтом** — открыты (§15). +- **Удалённый доступ (через облако-relay)** — опц., требует аккаунта; E2E-шифрование канала (trust-якорь — тот + же pairing-ключ); account-recovery — §15. **Фаза:** v3 (локально) / v4 (удалённо). + +## 5. Синхронизация, уведомления, удалённый статус + +- **Что синкается:** настройки (Settings namespace), **память водителя** (`.md`, D §7), история поездок + (trip-плагин, app-storage §6). **Local-first**, device↔телефон по близости; облако-relay — опц. для удалённого. +- **Конфликты:** per-key LWW для настроек; для `.md`-памяти — merge/LWW/версионирование (выбор — §15). +- **Что НЕ синкается без явного согласия:** память водителя в **облако** (D §7), контакты/журнал (G §5), + **dashcam-медиа** (J §4), точная локация. Согласие — отзываемое (security-privacy §7), UI — C. +- **Уведомления:** локально/по близости — прямой канал device↔телефон (in-app, сигналы §11). Удалённо (телефон + не рядом / приложение в фоне) — через self-hosted relay (long-poll/WebSocket) **либо** честное ограничение + «без облака удалённых push нет». **APNs/FCM** — внешние зависимости, конфликт с self-hostable/152-ФЗ (#8) → + не first-party (🟡 §15). Фаза: v3 локально / v4 удалённо. +- **Egress-гейт связности:** синк/relay-egress стартует только при Connectivity `State==online` (G §11), **не на + `portal`/`limited`** (ложный online — captive-portal, G §2) и **не до «вменяемых часов»** (§9). +- **Удалённый статус машины (read-only, later):** «где машина / напряжение / есть ли DTC» — только данные, + которые головблок уже имеет (никакого нового доступа к CAN, #2); **локация в облако — opt-in + consent**; + свежесть/last-known vs live + порог согласия — §15. Фаза: later/v4. +- **Фаза:** синк v3; уведомления v3/v4; удалённый статус v4. + +## 6. Бэкап / восстановление + +- **Бэкап `/data`** (настройки, память `.md`, app-storage); опц. — **отдельный поток dashcam-медиа** (на + отдельном носителе/разделе, J §4 / A §12 — НЕ в `/data`): только по capability + **явному отзываемому + согласию**, факт — в audit-log (J §4 / security-privacy §7); по умолчанию нет. +- **Шифрование бэкапа:** fscrypt-ключ `/data` привязан к **eFuse конкретной платы и headless** (a-base §3) — у + пользователя его НЕТ и он непереносим. Поэтому: (а) restore **на том же устройстве** (после factory-reset) — + ок; (б) **cross-device restore** требует ОТДЕЛЬНОГО backup-ключа/парольной фразы (не из eFuse) + re-encrypt при + экспорте — **схема открыта (§15, расширить a-base §3)**; до резолва cross-device-restore зашифрованного не гарантируется. +- **Восстановление:** настройки/память на новом устройстве/после factory-reset; **device-identity/`machine-id` + не переносится** (a-base §11). **Совместимость:** бэкап несёт версию base-образа/схемы Settings/BSP-профиля; + при несовпадении BSP/vehicle-профиля (a-base §11/§13) BSP-зависимые ключи **не применяются молча** (видимая + индикация / миграция схемы), переносится BSP-независимое (память `.md` — безопасна; расхождение сигналов + штатно покрыто `Unavailable`, data-model §3). Детали миграции — §15. +- **Фаза:** v3/v4. + +## 7. OTA-канал *(L владеет доставкой; A — применением)* + +- **Шов с A (a-base §5):** **A** — механизм применения (RAUC A/B), подпись/keyring/верификация + **anti-rollback**, + откат (bootcount+mark-good). **L** — **сборка** (CI → подписанный бандл + метаданные min-version), **хостинг** + (сервер/CDN), **доставка** (device-side update-клиент: проверка/скачивание). +- **Untrusted-host (с anti-rollback):** бандл подписан ключом из OTP/eFuse (a-base §4) → подмену вредоноса хост + не протолкнёт. Но подпись гарантирует аутентичность/целостность, **НЕ свежесть** → A дополнительно проверяет + **монотонность security-version** (rollback-index в eFuse/U-Boot env, по модели AVB) и отвергает downgrade/replay + даже при валидной подписи. **Только с anti-rollback** тезис «хосту не нужно доверие, лишь TLS+доступность» + корректен — иначе скомпрометированный CDN откатит парк на подписанную дырявую прошивку. +- **Фазы DOWNLOAD (L) vs APPLY (A) — разведены:** скачивание (L) идёт в **staging-область**, ДО RAUC, и **не + трогает A/B-слоты**; применение (A) — атомарно (a-base §5). Прерывание питанием на DOWNLOAD теряет максимум + прогресс докачки (слоты целы); на APPLY — RAUC откат. +- **Отказ-пути доставки (симметрично J §4 / H §5):** проверка свободного места ДО скачивания (ENOSPC → отказ с + видимой индикацией, без частичной записи, не крэш); прерванная загрузка — **range-resume** или чистый + перезапуск; **обрезанный/битый бандл отвергается на стороне L** (ожидаемый размер+хэш из подписанного манифеста) + ДО передачи в RAUC, не полагаясь на подпись A как единственный backstop; недоступный CDN → отложить (#3). +- **Связность:** скачивание — только при `State==online` (G §11), не на `portal`/`limited` (G §2); metered-aware + (крупный бандл не по дорогой LTE без согласия, G §2); и не до «вменяемых часов» (§9, иначе TLS «not yet valid»). +- **Каналы релизов:** stable / beta (opt-in); **staged rollout** (% парка), delta — позже (§15). +- **Сигнал здоровья когорты + auto-halt:** staged rollout требует обратного канала о доле mark-good/откатов; + при пороге откатов — автоостановка раскатки на остальной парк. **Парадокс:** телеметрия (§8) opt-in и по + умолчанию молчит → единственный обратный канал ненадёжен. Резолв — §15 (мин. неотключаемый health-сигнал + результата OTA vs консервативная ручная раскатка). Без него плохой бандл (откатившийся локально, A) идёт дальше. +- **До secure boot (v0–v3):** trust-by-build / ручной флеш (security-privacy §5); полноценный подписанный + OTA-канал + anti-rollback созревают с secure boot — **v4** (a-base §2/§4/§5). +- **Фаза:** v4. + +## 8. Телеметрия *(opt-in, выключена по умолчанию)* + +- **По умолчанию ВЫКЛЮЧЕНА** (security-privacy §7, #7); включается явным **отзываемым** согласием. +- **Что собирается (при opt-in):** краши/паники, результат OTA, watchdog-ресеты (источник — критичные события + a-base §9), агрегатная статистика использования (какие функции, без контента), perf/ошибки. +- **Что НИКОГДА (без отдельного явного согласия):** голос, контент данных машины, контакты, память водителя, + точная локация, dashcam. +- **Граница согласия:** **не ретроспективно** (собираем только события ПОСЛЕ согласия; ранее осевшие в audit-log/ + pstore критичные события a-base §9 в egress не идут); **отзыв** → немедленно прекратить сбор + **дропнуть + локальный буфер** ещё-не-отправленного (строгая трактовка #7); системный audit-log/pstore (a-base §9) ведётся + независимо для recovery, телеметрии не равен. +- **Factory-reset (a-base §12):** стирает telemetry-consent (возврат к выкл-по-умолчанию #7) И буфер + несобранной/неотправленной телеметрии (мог содержать события прошлого владельца — кейс продажи авто). + **Инвариант:** после factory-reset **все opt-in-согласия = выкл** (синк памяти, локация — тоже). +- **Облачная сторона:** ingest имеет retention; **отзыв согласия → удаление в ingest**; factory-reset стирает + только локальное — облачная копия удаляется отдельным запросом (право 152-ФЗ; self-hosted — у владельца инстанса). Детали — §15. +- **Анонимизация** (без device-identity/VIN/локации), **RU/self-hosted** ingest, provider-agnostic (#8); факт + egress — в audit-log (security-privacy §7 / a-base §9). +- **Фаза:** v2/v3. + +## 9. Lifecycle (шов с B) + +- **OTA-тайминг:** применение (A) — **не на ходу**; предпочтительно на стоянке/`accessory` или по явному запросу + (Companion проверяет `Power`-тайминг, делегирует A); скачивание — фоном, metered/portal/online-aware (§7). +- **Time-gate (a-base §7 / B §8):** OTA-download, sync-relay и telemetry-egress подчиняются гейту «вменяемых + часов» — откладываются до валидного времени (fake-hwclock/NTP/GPS-фикс), иначе TLS к CDN/облаку/ingest падает + «cert not yet valid» (плата без RTC → холодный boot с epoch 1970). Без сети ≠ без валидного времени. +- **Sync/телеметрия:** фоновые, неблокирующие (#11); деградируют без сети (#3); **не инициируют/не продлевают + wake** — согласуется с энергобюджетом АКБ (B §7 battery-cutoff, #5). +- **На `ShutdownImminent` (B §4):** прервать фоновую загрузку/синк gracefully (staging цел, §7); доделать позже. + +## 10. Приватность и безопасность (#1, #2, #7, #12) + +- **Read-only к машине, без удалённого управления** (#1/#2): write-путь к CAN не существует ни локально, ни через облако. +- **Local-first, облако опционально**: память/контакты/локация/**dashcam** не в облако без явного согласия (D §7, G §5, J §4, security-privacy §7). +- **Untrusted OTA-host** (§7): доверие — в подписи **+ anti-rollback** (A/eFuse), не в хосте. +- **152-ФЗ:** телеметрия opt-in, данные в РФ, **право на экспорт/удаление из облака** (синк + egress-нувшая + телеметрия), оператор/основание ПДн — legal-трек; self-hostable снимает зависимость от чужого облака. +- **Лицензии (#12):** моб.стек и облако — MIT-совместимо; self-hostable reference. + +## 11. IPC / интерфейсы + +- **`ru.shturman.Companion`** (домен L; контракт — §15): локальный API для моб.приложения (через Connectivity/ + лок.сеть, не публичная D-Bus); методы синка/бэкапа; `TriggerUpdateCheck()`, статус OTA; сигналы + `UpdateAvailable`/`SyncStateChanged`. Применение OTA — делегируется A (RAUC). +- **Потребляет:** `Settings` (зеркало/синк), память D (`.md`), **E (live-данные/DTC — read; поездки — + app-storage trip-плагина, plugin-sdk §8)**, `Connectivity` (G — транспорт/`State`/metered), `Power` (B — + тайминг). **Гейтинг:** `network` (security-privacy §3/§5); память/контакты — только по явному согласию (§5/§10). +- **UI:** consent/паринг/уведомления-на-головблоке — слот Shell (C §4); consent-UI — владелец C (security-privacy §7). + +## 12. Dev-симулятор (#13) + +- **Мок-облако/OTA-сервер** (раздаёт подписанные / намеренно-битые / **downgrade**-бандлы — тест верификации+ + anti-rollback A и отказа L по размеру/хэшу), **фейковый companion-peer** (паринг/синк/конфликты/мульти-peer без + реального телефона), **мок-телеметрия-sink** (проверка opt-in-гейта: по умолчанию ноль egress; дроп буфера на + отзыв/reset). Поверх мок-сети G (включая `portal`/невалидное-время). → dev-environment. + +## 13. Функции + +| функция | MVP/later | зависит от | фаза | +|---------|-----------|------------|------| +| Companion-сервис (device-side, локальный API, Stage 2) | later | G (транспорт), Settings | v3 | +| Паринг device↔телефон (локальный якорь, per-peer ключ) | later | — | v3 | +| Моб.приложение: данные машины/DTC (read-only) + поездки | later | E, trip-плагин, стек 🟡 | v3 | +| Моб.приложение: просмотр/правка памяти водителя | later | D §7 | v3 | +| Синхронизация (настройки/память/поездки, local-first) | later | Settings, D, trip-плагин | v3 | +| Уведомления (local in-app / remote-relay) | later | relay (§5) | v3/v4 | +| Телеметрия (opt-in, выключена; consent-wipe на reset) | later | security-privacy §7, a-base §12 | v2/v3 | +| Бэкап/восстановление `/data` (+ совместимость BSP/схемы) | later | a-base §3/§11/§12 | v3/v4 | +| OTA-канал: сборка/хостинг/доставка + fail-safe + anti-rollback | later | a-base §5, secure boot | v4 | +| Каналы релизов (stable/beta) + staged rollout + halt-петля | later | OTA-канал | v4 | +| Опциональное облако (relay/хостинг, self-hostable) | later | — | v4 | +| Удалённый статус машины (read-only, opt-in локация) | later | E, consent | v4 | +| Удалённый доступ через облако-relay (E2E) | later | паринг, облако | v4 | + +## 14. Зависимости + +- **Вниз/вбок:** **A** (§5 OTA-механизм/подпись/**anti-rollback**/откат — L только канал; §3 fscrypt+backup-ключ; + §7 время/TLS-gate; §9 audit/критичные события — источник телеметрии; §11/§12 restore/wipe), **G** (Connectivity: + `State`/metered/portal — транспорт-гейт), **D** (§7 память — синк-цель), **E** (live-данные/DTC — read-only; + **поездки — app-storage trip-плагина, plugin-sdk §8**), **J** (§4 dashcam-гейт), **B** (§4/§7 OTA/sync-тайминг), + **C** (consent/паринг/уведомления-UI), security-privacy (§5/§7 гранты/телеметрия/152-ФЗ). +- **Вверх:** удалённый просмотр/настройки для пользователя; OTA-доставка для всего парка. + +## 15. Открытые вопросы + +- 🟡 **Стек моб.приложения** (Flutter vs Rust-core+native) — off-device, MIT. → реализация. +- 🟡 **Push-транспорт удалённых уведомлений** (self-hosted relay vs APNs/FCM vs только-локально; 152-ФЗ/#8). → §5 + реализация. +- ◻️ **Cross-device backup-ключ** (passphrase/user-held, не из eFuse; re-encrypt при экспорте) — restore зашифрованного на новой плате. → a-base §3. +- ◻️ **Совместимость restore** (версия схемы Settings + BSP/vehicle-профиль; миграция vs отказ). → реализация + a-base §11/§13. +- ◻️ **Модель аккаунта:** account-recovery (потеря пароля/устройства, для relay); multi-vehicle (один аккаунт — N головблоков, адресация); multi-user роли (владелец/гость, доступ к памяти водителя). → реализация/legal. +- ◻️ **Право на экспорт/удаление из облака** (синк + egress-нувшая телеметрия) + retention в ingest; factory-reset не трогает облачную копию. → security-privacy §7 + legal. +- ◻️ **`ru.shturman.Companion` контракт** — методы синка/OTA-trigger **+ версионный handshake моб↔головблок** (min-version, graceful-degrade при skew; on-device конвенция ipc §2/plugin-sdk §7 к off-device без манифеста неприменима). → ipc. +- ◻️ **Staged rollout: halt-петля + развязка с opt-in телеметрией** (мин. health-сигнал результата OTA vs ручной gate) + механика %-парка/delta. → a-base §5 + L. +- ◻️ **Разрешение конфликтов синка** памяти `.md` (merge vs LWW vs версионирование). → реализация. +- ◻️ **152-ФЗ роли** (оператор/обработчик ПДн для синка/телеметрии/удалённого) — legal-трек (как BYO-LLM). +- ◻️ **Download-staging бандла** (область, resume/cleanup-политика; вне durable-write контракта a-base §3, если в `/data`). → реализация. + +--- + +## Журнал решений (домен L) + +| Решение | Выбор | Дата | +|---------|-------|------| +| Позиционирование | апсайд-слой; облако **опционально и self-hostable**; система полноценна без него (#3) | 2026-06-23 | +| Архитектура | device-Companion-сервис (Stage 2) + моб.приложение + опц.облако; **local-first** device↔телефон | 2026-06-23 | +| Красные линии | read-only к машине, без удалённого управления (#1/#2); память/контакты/локация/dashcam — не в облако без согласия | 2026-06-23 | +| Паринг | локальный per-peer якорь (код/QR), аккаунт не обязателен; роли peer'ов / multi-vehicle / recovery — открыты | 2026-06-23 | +| OTA | A — механизм/подпись/**anti-rollback**/откат; L — сборка/хостинг/доставка; untrusted-host корректен ТОЛЬКО с anti-rollback; DOWNLOAD(L)≠APPLY(A) | 2026-06-23 | +| OTA fail-safe | проверка места/ENOSPC, range-resume, отбраковка битого бандла на L до RAUC; гейт `State==online`+время | 2026-06-23 | +| Телеметрия | **opt-in, выключена**; не ретроспективно; отзыв/reset → дроп буфера + consent выкл; облако: retention+удаление; анонимизация; RU/self-hosted | 2026-06-23 | +| Синк | local-first (настройки/память/**поездки из trip-плагина, не E**); конфликты `.md` — открыто; не в облако без согласия | 2026-06-23 | +| Бэкап-шифрование | fscrypt eFuse-bound непереносим → cross-device restore требует отдельного backup-ключа (открыто, a-base §3) | 2026-06-23 | +| Lifecycle | OTA не на ходу; time-gate (a-base §7); фоновые синк/телеметрия не держат wake; staging цел на shutdown | 2026-06-23 | +| Моб.стек | 🟡 off-device (Flutter / Rust-core+native), MIT; Rust-first-правило прода — про головблок, не сюда | 2026-06-23 | +| Фазы | телеметрия v2/v3; компаньон/синк/бэкап v3; OTA-канал/облако/удалённое v4 | 2026-06-23 |