docs(roadmap): детальный план исполнения (вехи v0.1–v4.5 + риск-реестр + критпуть) + интерактивный roadmap.html

Каждая фаза разложена на упорядоченные вехи (что заработало / ID / зависит / тест без машины / готово-когда); биекция 170↔170 в md и html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 19:58:02 +03:00
parent 9604ce1248
commit cf04b05097
2 changed files with 359 additions and 135 deletions
+215
View File
@@ -0,0 +1,215 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Штурман — роадмапа</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@3.6.0/dist/tabler-icons.min.css">
<style>
:root{
--bg0:#ffffff; --bg1:#f6f6f4; --bg2:#ececea; --tx0:#1a1a18; --tx1:#67675f; --tx2:#9a9a92;
--bd0:rgba(0,0,0,.13); --bd1:rgba(0,0,0,.24); --rmd:8px; --rlg:12px;
--v0:#6b7280; --v1:#2f6fd0; --v2b:#c2790a; --v3:#0d8a80; --v4:#7c54d0;
--font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
@media(prefers-color-scheme:dark){:root{
--bg0:#1f1f1d; --bg1:#272724; --bg2:#161614; --tx0:#ececea; --tx1:#a6a69f; --tx2:#74746e;
--bd0:rgba(255,255,255,.14); --bd1:rgba(255,255,255,.26);
--v0:#9aa3b2; --v1:#6ea2f0; --v2b:#e0a64a; --v3:#3bb9ad; --v4:#a98ae8;
}}
*{box-sizing:border-box}
body{margin:0;background:var(--bg2);color:var(--tx0);font-family:var(--font);line-height:1.55;font-size:15px;
-webkit-font-smoothing:antialiased}
.wrap{max-width:1080px;margin:0 auto;padding:28px 20px 64px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
h1{font-size:22px;font-weight:600;margin:0 0 2px}
.sub{color:var(--tx1);font-size:14px;margin:0 0 18px}
.tabs{display:flex;gap:8px;margin:0 0 18px;flex-wrap:wrap}
.tab{appearance:none;border:.5px solid var(--bd1);background:var(--bg0);color:var(--tx0);font:inherit;font-size:14px;
padding:7px 14px;border-radius:var(--rmd);cursor:pointer;display:flex;align-items:center;gap:7px;transition:.12s}
.tab:hover{background:var(--bg1)}
.tab.on{background:var(--tx0);color:var(--bg0);border-color:var(--tx0)}
.view{display:none} .view.on{display:block}
.legend{display:flex;gap:14px;flex-wrap:wrap;color:var(--tx1);font-size:13px;margin:0 0 16px}
.legend i{font-style:normal;display:inline-flex;align-items:center;gap:5px}
.dot{width:10px;height:10px;border-radius:3px;display:inline-block}
.phase{background:var(--bg0);border:.5px solid var(--bd0);border-left:3px solid var(--ac);border-radius:var(--rlg);
margin:0 0 12px;overflow:hidden}
.phead{display:flex;align-items:center;gap:12px;padding:14px 16px;cursor:pointer;user-select:none}
.phead:hover{background:var(--bg1)}
.badge{font-weight:600;font-size:13px;color:var(--bg0);background:var(--ac);border-radius:6px;padding:3px 9px;flex:none}
.ptitle{font-weight:500;font-size:16px} .pdemo{color:var(--tx1);font-size:13px;margin-top:2px}
.pmeta{flex:1;min-width:0} .chev{color:var(--tx2);transition:.15s;flex:none}
.phase.open .chev{transform:rotate(90deg)}
.crit{font-size:12px;color:var(--ac);border:.5px solid var(--ac);border-radius:20px;padding:2px 9px;flex:none;white-space:nowrap}
.body{display:none;padding:4px 16px 16px;border-top:.5px solid var(--bd0)}
.phase.open .body{display:block}
.ms{border:.5px solid var(--bd0);border-radius:var(--rmd);margin-top:10px;background:var(--bg1)}
.mhead{display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer}
.mhead:hover{background:var(--bg2)}
.mid{font-weight:600;font-size:13px;color:var(--ac);flex:none;font-variant-numeric:tabular-nums}
.mname{font-weight:500;font-size:14px;flex:1}
.killer{font-size:11px;font-weight:600;background:var(--v2b);color:#000;border-radius:5px;padding:2px 7px;flex:none}
.mdet{display:none;padding:2px 12px 13px 12px;font-size:13.5px}
.ms.open .mdet{display:block}
.row{display:flex;gap:8px;padding:5px 0;border-top:.5px solid var(--bd0)}
.row:first-child{border-top:none}
.k{color:var(--tx2);flex:none;width:104px;font-size:12.5px;padding-top:1px}
.v{color:var(--tx0)}
.ids{display:flex;flex-wrap:wrap;gap:4px}
.id{font-family:ui-monospace,Menlo,monospace;font-size:12px;background:var(--bg0);border:.5px solid var(--bd0);
border-radius:5px;padding:1px 6px;color:var(--tx0)}
.gates{margin-top:12px;font-size:13px;color:var(--tx1)}
.gates b{color:var(--tx0);font-weight:500}
.flow{display:flex;flex-direction:column;gap:6px}
.fstep{display:flex;align-items:center;gap:12px;background:var(--bg0);border:.5px solid var(--bd0);border-left:3px solid var(--ac);
border-radius:var(--rmd);padding:11px 14px}
.fb{font-weight:600;font-size:13px;color:var(--bg0);background:var(--ac);border-radius:6px;padding:3px 9px;flex:none}
.fchain{font-size:13.5px;color:var(--tx0)} .fchain b{color:var(--ac);font-weight:600}
.arrow{color:var(--tx2);text-align:center;font-size:18px;line-height:.7}
.note{color:var(--tx1);font-size:13px;margin-top:14px;padding:12px 14px;background:var(--bg0);border:.5px solid var(--bd0);border-radius:var(--rmd)}
.rk{width:100%;border-collapse:collapse;font-size:13.5px}
.rk th{text-align:left;font-weight:500;color:var(--tx1);font-size:12.5px;padding:8px 10px;border-bottom:.5px solid var(--bd1)}
.rk td{padding:9px 10px;border-bottom:.5px solid var(--bd0);vertical-align:top}
.rk tr:hover td{background:var(--bg1)}
.rg{font-family:ui-monospace,Menlo,monospace;font-size:12px;color:var(--tx0)}
.by{font-weight:600;color:var(--ac2);white-space:nowrap}
.hg{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:12px}
.hcard{background:var(--bg0);border:.5px solid var(--bd0);border-radius:var(--rlg);padding:14px 16px}
.hcard h3{font-size:14px;font-weight:500;margin:0 0 8px;color:var(--tx1)}
.hitem{display:flex;gap:8px;align-items:baseline;padding:4px 0;font-size:13.5px}
.hitem .id{flex:none}
</style>
</head>
<body>
<div class="wrap">
<h2 class="sr">Интерактивная роадмапа проекта Штурман: пять фаз v0–v4, разложенных на вехи с зависимостями, тестом без машины и критериями готовности, критический путь и реестр рисков.</h2>
<h1>Штурман — роадмапа</h1>
<p class="sub">Лестница v0–v4: каждая фаза → вехи с зависимостями, тестом без машины и критерием готовности. 170 функций, источник правды — <span class="rg">docs/roadmap.md</span>.</p>
<div class="tabs" id="tabs">
<button class="tab on" data-v="ladder"><i class="ti ti-stairs-up" aria-hidden="true"></i>Лестница</button>
<button class="tab" data-v="crit"><i class="ti ti-route" aria-hidden="true"></i>Критпуть</button>
<button class="tab" data-v="risk"><i class="ti ti-alert-triangle" aria-hidden="true"></i>Риски</button>
<button class="tab" data-v="horizon"><i class="ti ti-telescope" aria-hidden="true"></i>Горизонт</button>
</div>
<div class="view on" id="ladder">
<div class="legend" id="legend"></div>
<div id="phases"></div>
</div>
<div class="view" id="crit"><div class="flow" id="flow"></div>
<div class="note">Параллельно (не на критпути): телефон/медиа/камера (v2.4v2.6), companion (v3.4), расширения (v3.5); нав- и OTA-ветки v4 идут одновременно. Сквозной enabling-трек — dev-environment.</div>
</div>
<div class="view" id="risk"><table class="rk"><thead><tr><th>Гейт</th><th>Выбор между</th><th>Решить к</th><th>Док</th></tr></thead><tbody id="risks"></tbody></table></div>
<div class="view" id="horizon"><p class="sub" style="margin-bottom:14px">За горизонтом v4 — доразвитие из тех же доменов по мере спроса (20 функций, вне лестницы v0–v4).</p><div class="hg" id="hgrid"></div></div>
</div>
<script>
const AC={v0:'var(--v0)',v1:'var(--v1)',v2:'var(--v2b)',v3:'var(--v3)',v4:'var(--v4)'};
const P=[
{id:'v0',t:'База + Shell',demo:'вкл/выкл в машине → мгновенный красивый UI, переживает срыв питания',crit:'образ → power-safe → shell',
gates:'A01 (Armbian/Debian vs Yocto) · A02 (f2fs vs ext4) · B08/B09 (MCU vs supercap)',
ms:[
{id:'v0.1',n:'Образ-болванка',ids:'A01 A02 A06 A17',dep:'hardware/BSP',test:'Lima-VM',done:'init поднялся; RO-rootfs A/B + overlay + /data монтируются'},
{id:'v0.2',n:'Boot-конвейер',ids:'A04 A05 A15',dep:'v0.1',test:'VM boot',done:'Stage 0/1/2 разделены; splash мгновенно'},
{id:'v0.3',n:'Power-safe ядро',ids:'B01 B03 B04 B02 B06 B07 A14 B05',dep:'v0.2, hold-up (hw §3)',test:'fake-ACC + power-cut в VM',done:'N циклов зажигания без потери /data; abort до PONR'},
{id:'v0.4',n:'MCU/thermal fail-safe',ids:'B08 B09 B10 A12',dep:'v0.3, мок-MCU',test:'мок-MCU/sensor',done:'thermal-trip → graceful; MCU-таймер режет питание при зависании SoC'},
{id:'v0.5',n:'Shell первый кадр',ids:'C03 C04 C01 C05 C02 C07 C09 C10',dep:'v0.2',test:'нативный Slint + VM',done:'до интерактива < бюджет (perf §3); авто день/ночь'},
{id:'v0.6',n:'База-доводка + dev-харнесс',ids:'A09 A10 A11 A07 A16 F01 F02 F03 F04 J06',dep:'параллельно',test:'сам harness',done:'dev-итерация без железа; память/лог/eMMC в бюджете'}]},
{id:'v1',t:'Ассистент онлайн + связь + аудио + Location',demo:'«Штурман, …» → устный RU-ответ; аудио с ducking; distraction по GPS',crit:'ассистент-онлайн',
gates:'K05 (маппинг руля/ADC) · B08/B09 (если MCU не закрыт) · distraction-числа (safety §4)',
ms:[
{id:'v1.1',n:'Аудио-плоскость',ids:'H01 H02 H05 H04',dep:'v0 (PipeWire/WirePlumber)',test:'fake-аудио (H §12)',done:'ducking-лестница; громкость с руля; ducking ≤150 ms'},
{id:'v1.2',n:'Location / датчики',ids:'K01 K02 K03 K04 A08',dep:'v0, fake-GPS',test:'NMEA-реплей',done:'Location публикует zero-clamp-скорость; time-sync от GPS'},
{id:'v1.3',n:'Связь-core',ids:'G01 G02 G03',dep:'v0, NM/MM',test:'мок-сеть',done:'portal/limited не врёт «online»; статус в баре'},
{id:'v1.4',n:'Ассистент-пайплайн (офлайн-узлы)',ids:'D01 D02 D03 D04 D05 H03',dep:'v1.1, mic',test:'моки STT(текст)/TTS(лог)',done:'wake→STT→TTS офлайн; AEC держит wake во время медиа; wake ≤400 ms'},
{id:'v1.5',n:'Интенты + онлайн-LLM',ids:'D06 D07 D08 D09 D11',dep:'v1.4, v1.3',test:'мок-LLM (canned) + мок-сеть',done:'голос→ответ; «нет сети» graceful; локальный интент ≤300 ms без LLM'},
{id:'v1.6',n:'Distraction + руль',ids:'C11 C12 D12 C13 K05',dep:'v1.2, v1.4, safety §4',test:'fake-GPS speed + мок-руль',done:'distraction по порогам safety §4; навигация/громкость рулём'},
{id:'v1.7',n:'База-доводка v1',ids:'A13 B11 B12 B13',dep:'v0.4',test:'мок',done:'wake-word гейтится состояниями; sleep/wake базово'}]},
{id:'v2',t:'Контекст машины (killer) + телефон + медиа + камера',demo:'«прочитай ошибки / что значит лампочка» → live OBD+DTC по-человечески',crit:'контекст машины (killer)',
gates:'E03 (DTC-база своя RU vs готовая) · H06 (декодер/AAC-патент) · J01 (DRM-handoff Stage 0→1)',
ms:[
{id:'v2.1',n:'CAN-транспорт',ids:'E01 E04 E06 E05',dep:'v0/v1, data-model, hw(CAN), ISO-TP',test:'Vehicle Simulator (ELM327-emu + vcan)',done:'live-сигналы rate-cap ~1020 Гц; engine_running (не дублирует Power)'},
{id:'v2.2',n:'DTC + диагностика',ids:'E02 E03 E07 E08',dep:'v2.1, DTC-база',test:'симулятор инжектит P0420',done:'читает реальные DTC + RU-расшифровка'},
{id:'v2.3',n:'Vehicle-context',killer:1,ids:'D10 C08',dep:'v2.2, v1-ассистент (D06/D08)',test:'симулятор P0420 → объяснение по-русски',done:'killer-demo: голос «что за ошибка» → live OBD+DTC → человеческое объяснение'},
{id:'v2.4',n:'Телефон',ids:'G04 G05 G06 G07 G08 G09 G10',dep:'v1.1, v1.6, BT, D §6',test:'fake-BT-стек (G §12)',done:'звонок руль/тач; контакты PBAP; входящий-оверлей vs реверс'},
{id:'v2.5',n:'Медиа',ids:'H06 H07 H08 H09 H10 C06',dep:'v2.4, v1.1, storage',test:'синтет-медиа + fake-A2DP',done:'локальный трек + BT-музыка; now-playing — первая Wayland-поверхность'},
{id:'v2.6',n:'Камера',ids:'A18 J01 J02 J03 J04 J05 K06 B14',dep:'v2.1, C06, A §4/B §7',test:'fake-камера (паттерн/no-signal/реверс)',done:'реверс→камера приоритетно; парктроник; fail-safe «нет сигнала»'},
{id:'v2.7',n:'Телеметрия-задел',ids:'L07',dep:'security-privacy §7, consent',test:'мок-телеметрия-sink',done:'по умолчанию ноль egress; consent-гейт'}]},
{id:'v3',t:'Офлайн-фолбэк + Plugin API + companion',demo:'ответ без сети + установка стороннего плагина + companion-телефон',crit:'офлайн + Plugin API',
gates:'D13 (офлайн-модель) · D14 (память/consent) · F11 (подпись) · L03 (моб-стек) · L06 (push) · H11 (FM-тюнер)',
ms:[
{id:'v3.1',n:'Plugin host',ids:'F05 F06 F07 F08 F09 F10 C14',dep:'v0 (App-Host, a-base §3), plugin-sdk',test:'plugin-host-харнесс (F)',done:'плагин install/update/remove в песочнице; ревью разрешений (perm-UI)'},
{id:'v3.2',n:'Plugin-интенты + подпись',ids:'D15 F11',dep:'v3.1, v1-ассистент',test:'тест-плагин с intent',done:'плагин регистрирует интент; подпись манифеста'},
{id:'v3.3',n:'Офлайн-ассистент',ids:'D13 D14',dep:'v1-пайплайн, storage',test:'мок-сеть off + локальная модель',done:'сеть выключена → локальный ответ; память водителя (.md)'},
{id:'v3.4',n:'Companion',ids:'L01 L02 L03 L04 L05 L06 L08',dep:'v1.3, v2 (E/trip-плагин)',test:'фейк-companion-peer + мок-облако',done:'паринг; синк настроек/памяти/поездок local-first; бэкап'},
{id:'v3.5',n:'Связь + медиа-расширения',ids:'G11 G12 H11 H12 H13 H14',dep:'v1.3, v3.1, network',test:'моки сети/медиа',done:'WiFi-hotspot; SMS-чтение; media-source через плагин'}]},
{id:'v4',t:'Навигация + OTA + прод-образ + ретрофит',demo:'офлайн-навигация + OTA + документированный ретрофит на реальное авто',crit:'первый «продукт»',
gates:'I03 (Valhalla vs OSRM) · I01 (карты + ODbL + размещение) · G13 (проекция scope/legal)',
ms:[
{id:'v4.1',n:'Карты + рендер',ids:'I01 I02 I04 I08',dep:'tech-stack, хранилище, C §4, G §2',test:'нав-сим (тест-регион PMTiles)',done:'карта рендерится офлайн (GPU); детект «вне региона»; геокодер'},
{id:'v4.2',n:'Роутинг + ведение',ids:'I03 I05 I06 I07 I09 I10 I11 I12 I13 K09',dep:'v4.1, v1.2, v1.1, D §6',test:'мок-маршрут (rerouting/maneuver)',done:'turn-by-turn-ведение; map-matching; назначение голосом; resume'},
{id:'v4.3',n:'Прод-образ + secure boot',ids:'A03 A20 A21 A22',dep:'v0-образ, hardware',test:'флеш на железо (HW-in-the-loop)',done:'релиз-образ прошивается; verified boot; /data шифрован; factory reset'},
{id:'v4.4',n:'OTA-канал',ids:'A19 L09 L10 L11 L12 L13',dep:'v4.3 (trust-anchor), v3.4, F11',test:'мок-облако/OTA (подписанные/битые/downgrade)',done:'OTA доставляет/применяет/откатывает; anti-rollback; каналы stable/beta'},
{id:'v4.5',n:'Ретрофит + опц.',ids:'G13',dep:'всё v0–v4 на реальном авто',test:'реальная установка',done:'документированный ретрофит на одну машину (BSP/калибровка/гайд)'}]}
];
const CRIT=[
{p:'v0',c:'<b>v0.1</b> образ → <b>v0.2</b> boot → <b>v0.3</b> power-safe → <b>v0.5</b> shell'},
{p:'v1',c:'<b>v1.1</b> аудио + <b>v1.2</b> Location + <b>v1.3</b> сеть → <b>v1.4</b> пайплайн → <b>v1.5</b> онлайн-LLM'},
{p:'v2',c:'<b>v2.1</b> CAN → <b>v2.2</b> DTC → <b>v2.3</b> контекст (KILLER)'},
{p:'v3',c:'<b>v3.1</b> plugin-host → <b>v3.3</b> офлайн-LLM'},
{p:'v4',c:'<b>v4.1</b> карты → <b>v4.2</b> роутинг ‖ <b>v4.3</b> secure boot → <b>v4.4</b> OTA → <b>v4.5</b> ретрофит'}
];
const RISK=[
['A01','Armbian/Debian vs Yocto','v0','a-base §2'],['A02','f2fs vs ext4','v0','a-base §3'],
['B08/B09','MCU-копилот vs supercap-only','v0','b-power §5, hw §3'],
['distraction','числа км/ч + список блокируемого','v1','safety §4'],
['perf','латентные числа (кадр/голос/ввод)','по фазам','performance §3'],
['K05','маппинг кнопок / ADC-калибровка','v1/v2','k-sensors §3'],
['E03','своя RU DTC-база vs готовая','v2','e-vehicle-data §5'],
['H06','symphonia + AAC-патент (юр)','v2','h-media §5'],
['J01','DRM-master handoff Stage 0→1','v2','j-cameras §3'],
['D13','YandexGPT Lite / T-lite / Qwen','v3','d-assistant §5'],
['D14','что авто-запоминать / схема / consent','v3','d-assistant §7'],
['F11','формат / keyring / ревокация','v3','f-plugin §3, sec-priv §6'],
['L03','Flutter vs Rust-core+native','v3','l-cloud §3'],
['L06','self-relay vs APNs/FCM vs локально','v3','l-cloud §5'],
['H11','FM-тюнер: добавить vs отказаться','v3','h-media §7, hw §4'],
['A19','RAUC vs Mender/swupdate/OSTree','v4','a-base §5'],
['I03','Valhalla vs OSRM','v4','i-nav §4'],
['I01','ODbL-атрибуция + размещение данных','v4','i-nav §2'],
['G13','not-first-party / плагин / вне скоупа','v4','g-conn §8']
];
const esc=s=>s.replace(/&/g,'&amp;').replace(/</g,'&lt;');
function ph(p){
const m=p.ms.map(x=>`<div class="ms" style="--ac:${AC[p.id]}"><div class="mhead"><span class="mid">${x.id}</span><span class="mname">${esc(x.n)}</span>${x.killer?'<span class="killer">killer</span>':''}<i class="ti ti-chevron-down chev" aria-hidden="true"></i></div><div class="mdet"><div class="row"><span class="k">ID каталога</span><span class="v ids">${x.ids.split(' ').map(i=>`<span class="id">${i}</span>`).join('')}</span></div><div class="row"><span class="k">Зависит от</span><span class="v">${esc(x.dep)}</span></div><div class="row"><span class="k">Тест без машины</span><span class="v">${esc(x.test)}</span></div><div class="row"><span class="k">Готово, когда</span><span class="v">${esc(x.done)}</span></div></div></div>`).join('');
return `<div class="phase" style="--ac:${AC[p.id]}"><div class="phead"><span class="badge">${p.id}</span><div class="pmeta"><div class="ptitle">${esc(p.t)}</div><div class="pdemo">${esc(p.demo)}</div></div><span class="crit">${esc(p.crit)}</span><i class="ti ti-chevron-right chev" aria-hidden="true"></i></div><div class="body">${m}<div class="gates"><b><i class="ti ti-alert-triangle" aria-hidden="true"></i> Гейты фазы:</b> ${esc(p.gates)}</div></div></div>`;
}
document.getElementById('phases').innerHTML=P.map(ph).join('');
document.getElementById('legend').innerHTML=P.map(p=>`<i><span class="dot" style="background:${AC[p.id]}"></span>${p.id}${esc(p.crit)}</i>`).join('');
document.getElementById('flow').innerHTML=CRIT.map((s,i)=>`<div class="fstep" style="--ac:${AC[s.p]}"><span class="fb">${s.p}</span><span class="fchain">${s.c}</span></div>${i<CRIT.length-1?'<div class="arrow">↓</div>':''}`).join('');
const acFor=s=>{const m=(s||'').match(/v[0-4]/);return AC[m?m[0]:'v0'];};
document.getElementById('risks').innerHTML=RISK.map(r=>`<tr style="--ac2:${acFor(r[2])}"><td class="rg">${esc(r[0])}</td><td>${esc(r[1])}</td><td class="by">${esc(r[2])}</td><td class="rg">${esc(r[3])}</td></tr>`).join('');
const HORIZON=[
{g:'База',items:[['A23','мульти-BSP'],['A24','kernel/dtb-тюнинг (ongoing)']]},
{g:'Shell / ассистент',items:[['C15','мультидисплей / профили / виджеты'],['D16','barge-in']]},
{g:'Vehicle-Data',items:[['E09','trip-производные (у плагина)'],['E10','fuel-trim'],['E11','VIN'],['E12','DBC-сниффинг'],['E13','vendor-DTC'],['E14','лог поездок']]},
{g:'Экосистема / медиа',items:[['F12','курируемый стор'],['H15','мульти-зона / EQ / A2DP-source']]},
{g:'Навигация',items:[['I14','трафик TMC/RDS'],['I15','онлайн-трафик / поиск'],['I16','DR в тоннелях']]},
{g:'Камеры / датчики',items:[['J07','0..N источников'],['J08','dashcam'],['J09','surround / 360°'],['K07','IMU'],['K08','выделенные не-CAN датчики']]}
];
document.getElementById('hgrid').innerHTML=HORIZON.map(g=>`<div class="hcard"><h3>${esc(g.g)}</h3>${g.items.map(it=>`<div class="hitem"><span class="id">${it[0]}</span><span>${esc(it[1])}</span></div>`).join('')}</div>`).join('');
document.addEventListener('click',e=>{
const t=e.target.closest('.tab'); if(t){document.querySelectorAll('.tab').forEach(x=>x.classList.toggle('on',x===t));document.querySelectorAll('.view').forEach(v=>v.classList.toggle('on',v.id===t.dataset.v));return;}
const mh=e.target.closest('.mhead'); if(mh){mh.parentElement.classList.toggle('open');return;}
const phd=e.target.closest('.phead'); if(phd){phd.parentElement.classList.toggle('open');}
});
document.querySelector('.phase').classList.add('open');
</script>
</body>
</html>
+144 -135
View File
@@ -1,176 +1,185 @@
# Роадмапа
# Роадмапа (детальный план исполнения)
> Фазы реализации лестницей: каждая ступень — законченный, **демонстрируемый**
> артефакт. Порядок диктуется зависимостями из [architecture.md](architecture.md)
> и [capability-catalog.md](capability-catalog.md).
> Фазы реализации лестницей: каждая ступень — законченный **демонстрируемый** артефакт.
> Каждая фаза разложена на **упорядоченные вехи** с зависимостями, способом теста **без
> машины** (принцип #13) и проверяемым критерием готовности. Порядок диктуется
> зависимостями из [architecture.md](architecture.md) и [capability-catalog.md](capability-catalog.md).
## Как читать
- **ID** (`A01`, `D10`, …) ссылаются на строки [capability-catalog.md](capability-catalog.md).
Фазы там — источник; роадмапа их **секвенирует и группирует в треки**, не переопределяет.
- Каждая фаза = **ступень-демо**, по шаблону: **Цель/демо · Входит** (ID по параллельным
трекам) **· Зависимости/порядок · Готово, когда · 🟡 гейты**.
- **Составные фазы каталога** (`vN/vM`) размещены по **старту**; завершение/доводка —
пометкой в поздней фазе.
- **dev-environment проектируется рано** (до v0-реализации) и идёт сквозным треком —
не на критическом пути, но разблокирует каждую фазу.
- Учтены все **170** функций: 150 в v0v4 + 20 «[за горизонтом v4](#за-горизонтом-v4-laterongoing)».
- **ID** (`A01`, `D10`…) строки [capability-catalog.md](capability-catalog.md); фазы оттуда, roadmap их **секвенирует**.
- **Веха** `vN.k` — атомарный шаг внутри фазы: *что заработало · ID · зависит-от · тест без машины · готово-когда (acceptance)*.
- **Тест без машины** ссылается на dev-симуляторы ([dev-environment.md](dev-environment.md)): Vehicle Simulator, fake-GPS/аудио/BT/камера, plugin-host-харнесс, нав-сим, мок-облако/OTA.
- Все **170** функций: 150 в вехах v0–v4 + 20 «[за горизонтом](#за-горизонтом-v4.
- Числа-бюджеты (латентность/пороги) — из [performance.md](contracts/performance.md) и [safety.md](contracts/safety.md) (помечены 🟡, финал на железе/HMI).
## Сводная лестница
| Фаза | Демо (killer-артефакт) | Вехи | Критпуть-звено |
|------|------------------------|------|----------------|
| **v0** | вкл/выкл в машине → мгновенный красивый UI, переживает срыв питания | v0.1–v0.6 | образ → power-safe → shell |
| **v1** | «Штурман, …» → устный RU-ответ; аудио с ducking; distraction по GPS | v1.1v1.7 | ассистент-онлайн |
| **v2** | «прочитай ошибки / что значит лампочка» → live OBD+DTC по-человечески | v2.1–v2.7 | **контекст машины (killer)** |
| **v3** | ответ **без сети** + установка стороннего **плагина** + companion-телефон | v3.1v3.5 | офлайн + Plugin API |
| **v4** | офлайн-навигация + OTA + **документированный ретрофит на реальное авто** | v4.1–v4.5 | первый «продукт» |
---
## v0 — База + Shell · *критпуть: образ/power-safe → UI*
## v0 — База + Shell · *критпуть: образpower-safe → UI*
- **Цель/демо:** RK3588 стартует **< 10 c** в красивый Slint-лаунчер (день/ночь, крупные
тайлы) и переживает отключение зажигания без повреждения eMMC. Демо: вкл/выкл в машине →
мгновенный UI, без fsck-боли.
- **Входит:**
- *Образ / ФС / boot (A):* `A01 A02 A04 A05 A06 A07 A09 A10 A11 A12 A14 A15 A16 A17`
- *Power / lifecycle (B):* `B01 B02 B03 B04 B05 B06 B07 B08 B09` + старт thermal `B10`
- *Shell (C):* `C01 C02 C03 C04 C05 C07 C09` + зародыш настроек `C10`
- *Dev-enabling (F/J, параллельно):* `F01 F02 F03 F04` + камера-сим `J06`
- **Зависимости/порядок:** hardware HAL/BSP → образ `A` → power `B` (graceful shutdown требует
hold-up, hardware §3) → shell `C` (первый кадр Stage 1 поверх boot Stage 0). Power-safe — гейт демо.
- **Готово, когда:** холодный boot < 10 c до интерактивного home · N циклов зажигания без
потери `/data` · автопереключение день/ночь.
- **🟡 гейты:** `A01` (Armbian/Debian vs Yocto), `A02` (f2fs vs ext4), `B08/B09`
(**MCU vs supercap-only** — определяет архитектуру питания). Фундамент — закрыть в v0.
**Демо:** подаём питание → RK3588 за **< 10 c** (потолок; цель — быстрее) в красивый Slint-лаунчер
(день/ночь, крупные тайлы); глушим зажигание → graceful shutdown без повреждения eMMC; повторяем цикл.
| Веха | Заработало | ID | Зависит | Тест без машины | Готово, когда |
|------|-----------|----|---------|-----------------|---------------|
| **v0.1** Образ-болванка | грузится, `/data` монтируется | A01 A02 A06 A17 | hardware/BSP | Lima-VM | init поднялся; RO-rootfs A/B + overlay + `/data` ок |
| **v0.2** Boot-конвейер | splash → таргет фазами | A04 A05 A15 | v0.1 | VM boot | Stage 0/1/2 разделены; splash мгновенно |
| **v0.3** Power-safe ядро | переживает срыв питания | B01 B03 B04 B02 B06 B07 A14 B05 | v0.2, hold-up (hw §3) | fake-ACC + power-cut в VM | N циклов зажигания без потери `/data`; abort до PONR |
| **v0.4** MCU/thermal fail-safe | аппаратный фундамент питания/тепла | B08 B09 B10 A12 | v0.3, мок-MCU | мок-MCU/sensor | thermal-trip → graceful; MCU-таймер режет питание, если SoC завис |
| **v0.5** Shell первый кадр | красивый home, день/ночь | C03 C04 C01 C05 C02 C07 C09 C10 | v0.2 | нативный Slint + VM | до интерактива < бюджет (perf §3); авто день/ночь |
| **v0.6** База-доводка + dev-харнесс | память/лог/eMMC + dev-цикл | A09 A10 A11 A07 A16 F01 F02 F03 F04 J06 | паралл. v0.1v0.5 | сам harness | dev-итерация без железа работает; память/лог/eMMC в бюджете |
**Порядок/параллелизм:** v0.1→v0.2 строго; затем v0.3 (power) и v0.5 (shell) **параллельно** поверх v0.2;
v0.4 после v0.3; v0.6 — сквозной enabling-трек (нужен для разработки всех остальных).
**🟡 гейты:** `A01` (Armbian/Debian vs Yocto) · `A02` (f2fs vs ext4) · `B08/B09` (**MCU vs supercap-only** — определяет v0.4). Закрыть в v0: это фундамент.
---
## v1 — Ассистент онлайн + связь + аудио + Location · *критпуть: ассистент-онлайн*
- **Цель/демо:** «Штурман, …» → корректный устный RU-ответ через online-LLM; аудио-арбитр
жив (TTS с ducking); статус сети в баре; громкость с руля; distraction по GPS-скорости.
Демо: голосовой Q&A в машине.
- **Входит:**
- *Ассистент (D):* `D01 D02 D03 D04 D05 D06 D07 D08 D09 D11` + distraction `D12`
- *Связь — core (G):* `G01 G02 G03`
- *Аудио-плоскость — core (H):* `H01 H02 H03 H04 H05`
- *Location / датчики (K):* `K01 K02 K03 K04` + старт мультируль-ADC `K05`
- *Shell-интеграция (C):* `C11` (PTT+лог) + старт distraction `C12` + старт мультируль `C13`
- *База-доводка (A/B):* `A08` (GPS-время) `A13` (thermal-тюнинг) `B11` (MCU firmware)
`B12` (старт sleep/wake) `B13` (гейт wake-word)
- **Зависимости/порядок:** `G01`(сеть) → `D08`(online-LLM); `H01`(аудио-плоскость) → `D04`(TTS);
`K01`(Location) → `C12`/`D12`(distraction по GPS-скорости); `B13``D` (гейт wake-word по lifecycle).
Всё поверх v0-базы/shell.
- **Готово, когда:** голосовой вопрос → устный RU-ответ при сети · «нет сети» graceful (`D11`) ·
громкость с руля (`K05`) · distraction-режим по GPS-скорости.
- **🟡 гейты:** `B08/B09` (если MCU не закрыт в v0 — гейтит `B11`/`B12`); `K05` (маппинг кнопок
руля / калибровка ADC — per-BSP). Офлайн-LLM ещё НЕ здесь (→ v3).
**Демо:** «Штурман, …» → корректный устный RU-ответ через online-LLM; аудио-арбитр (TTS с ducking);
сеть в статус-баре; громкость с руля; distraction-режим по GPS-скорости.
| Веха | Заработало | ID | Зависит | Тест без машины | Готово, когда |
|------|-----------|----|---------|-----------------|---------------|
| **v1.1** Аудио-плоскость | роли + ducking + вывод | H01 H02 H05 H04 | v0 (PipeWire/WirePlumber) | fake-аудио (H §12) | ducking-лестница работает; громкость с руля (perf: ducking ≤150 ms) |
| **v1.2** Location/датчики | валидная скорость/курс | K01 K02 K03 K04 A08 | v0, fake-GPS | NMEA-реплей | `ru.shturman.Location` публикует zero-clamp-скорость; time-sync от GPS |
| **v1.3** Связь-core | online/portal/offline | G01 G02 G03 | v0, NM/MM | мок-сеть (управляемые состояния) | portal/limited не врёт «online»; статус в баре (C07) |
| **v1.4** Ассистент-пайплайн (офлайн-узлы) | wake→STT→TTS локально | D01 D02 D03 D04 D05 H03 | v1.1, mic | моки STT(текст)/TTS(лог) | «Штурман»→STT→TTS офлайн; AEC держит wake во время медиа (wake ≤400 ms) |
| **v1.5** Интенты + онлайн-LLM | устный ответ при сети | D06 D07 D08 D09 D11 | v1.4, v1.3 (для D08) | мок-LLM (canned) + мок-сеть | голос→ответ; «нет сети» graceful; локальный интент ≤300 ms без LLM |
| **v1.6** Distraction + руль | безопасный UI на ходу | C11 C12 D12 C13 K05 | v1.2 (скорость), v1.4, safety §4 | fake-GPS speed + мок-руль | distraction по порогам safety §4; навигация/громкость рулём |
| **v1.7** База-доводка v1 | lifecycle-гейты | A13 B11 B12 B13 | v0.4 | мок | wake-word гейтится состояниями; sleep/wake базово |
**Порядок/параллелизм:** v1.1/v1.2/v1.3 — **параллельно** поверх v0; v1.4 после v1.1 (аудио); v1.5 после v1.4+v1.3;
v1.6 после v1.2+v1.4; v1.7 параллельно.
**🟡 гейты:** `K05` (маппинг руля / ADC-калибровка — per-BSP) · `B08/B09` (если MCU не закрыт в v0). distraction-числа (safety §4) — подтвердить на HMI. *Офлайн-LLM — НЕ здесь (v3).*
---
## v2 — Контекст машины (killer) + телефон + медиа + камера · *критпуть: контекст машины*
- **Цель/демо:** «Штурман, прочитай ошибки» / «что значит эта лампочка» → ассистент читает
live-OBD + DTC и объясняет по-человечески (**vehicle-context injection**). **Killer-демо.**
Плюс: hands-free звонки, локальная/BT-музыка с now-playing, задняя камера с парктроником.
- **Входит:**
- *Vehicle-Data (E):* `E01 E02 E03 E04 E05 E06` + `E07` (pending/permanent) + старт расход `E08`
- *Контекст-ассистент (D):* `D10` (**vehicle-context injection**)
- *Телефон (G):* `G04 G05 G06 G07 G08 G09` + старт tethering `G10`
- *Медиа (H):* `H06 H07 H08 H09 H10` + первый Wayland-surface `C06` (now-playing)
- *Камера (J):* `J01 J02 J03 J04 J05` + Stage 0 boot-инфра `A18`
- *Прочее:* статус машины в баре `C08` · CAN-кнопки руля `K06` · старт реверс-wake `B14` ·
старт телеметрии (opt-in, выключена) `L07`
- **Зависимости/порядок:** `E`(CAN-транспорт)+data-model → `D10`(контекст), поверх v1-ассистента
(`D06`/`D08`). BT-адаптер `G04``H08`(A2DP) и `G05`(HFP). `A18`(Stage 0) → `J01`(ранний путь
камеры). `C06`(полный композитор) → первая поверхность `H07`/`J04`.
- **Готово, когда:** ассистент по голосу читает реальные DTC и объясняет · hands-free звонок
(руль/тач) · локальный трек и BT-музыка с now-playing · задняя камера с парктроник-оверлеем
и fail-safe «нет сигнала».
- **🟡 гейты:** `E03` (DTC-база: своя RU vs готовая), `H06` (декодер / AAC-патент — legal),
`J01` (DRM-master handoff Stage 0→1).
**Демо:** «Штурман, прочитай ошибки» / «что значит эта лампочка» → ассистент читает live-OBD + DTC и
объясняет по-человечески (**vehicle-context injection**). Плюс hands-free звонки, локальная/BT-музыка, задняя камера.
| Веха | Заработало | ID | Зависит | Тест без машины | Готово, когда |
|------|-----------|----|---------|-----------------|---------------|
| **v2.1** CAN-транспорт | live-сигналы | E01 E04 E06 E05 | v0/v1, data-model, hw(CAN), ISO-TP | Vehicle Simulator (ELM327-emu + vcan) | live-сигналы с rate-cap ~1020 Гц; `engine_running` (не дублирует Power) |
| **v2.2** DTC + диагностика | чтение ошибок | E02 E03 E07 E08 | v2.1, DTC-база | симулятор инжектит `P0420` | читает реальные DTC + RU-расшифровка |
| **v2.3** Vehicle-context (**KILLER**) | объяснение по голосу | D10 C08 | v2.2, v1-ассистент (D06/D08) | симулятор `P0420` → объяснение по-русски | **killer-demo**: голос «что за ошибка» → live OBD+DTC → человеческое объяснение |
| **v2.4** Телефон | hands-free | G04 G05 G06 G07 G08 G09 G10 | v1.1 (phone_call), v1.6 (руль), BT, D §6 | fake-BT-стек (G §12) | звонок руль/тач; контакты PBAP; входящий-оверлей vs реверс |
| **v2.5** Медиа | музыка + now-playing | H06 H07 H08 H09 H10 C06 | v2.4 (BT-адаптер), v1.1, storage | синтет-медиа + fake-A2DP | локальный трек + BT-музыка; now-playing как первая Wayland-поверхность |
| **v2.6** Камера | задняя камера + парктроник | A18 J01 J02 J03 J04 J05 K06 B14 | v2.1 (E), C06 (surface), A §4/B §7 | fake-камера (паттерн/no-signal/реверс) | реверс→камера приоритетно; парктроник-оверлей; fail-safe «нет сигнала» |
| **v2.7** Телеметрия-задел | opt-in, выключена | L07 | security-privacy §7, consent | мок-телеметрия-sink | по умолчанию ноль egress; consent-гейт |
**Порядок/параллелизм:** v2.1→v2.2→v2.3 (killer-цепочка, критпуть); v2.4→v2.5 (BT-адаптер раньше A2DP);
v2.6 после v2.1+C06; v2.4/v2.5/v2.6/v2.7 — параллельно killer-цепочке.
**🟡 гейты:** `E03` (DTC-база: своя RU vs готовая) · `H06` (декодер/AAC-патент — legal) · `J01` (DRM-master handoff Stage 0→1).
---
## v3 — Офлайн-фолбэк + Plugin API + companion · *критпуть: офлайн + расширяемость*
- **Цель/демо:** ассистент отвечает **без сети** (локальная модель); сторонний **плагин**
(intent/tile) ставится в песочнице с ревью разрешений; **companion**-приложение на телефоне
видит данные машины/поездки. Демо: офлайн + экосистема.
- **Входит:**
- *Офлайн-ассистент (D):* `D13` (provider-switch + офлайн-фолбэк llama.cpp) `D14` (память
водителя) `D15` (plugin-интенты)
- *Plugin host (F):* `F05 F06 F07 F08 F09 F10` + старт подписи `F11`
- *Связь — later (G):* `G11` (WiFi-hotspot) `G12` (SMS/MAP + чтение вслух)
- *Медиа-расширения (H):* `H11` (FM-радио) `H12` (стриминг) `H13` (интернет-радио)
`H14` (media-source-плагины)
- *Companion (L):* `L01 L02 L03 L04 L05` + старт уведомлений `L06` + старт бэкапа `L08`
- *Shell:* `C14` (UI управления разрешениями)
- **Зависимости/порядок:** `F`(lifecycle плагина) поверх App-Host + atomic-install (a-base §3);
`D15`(plugin-интенты) `F` + plugin-sdk; `L01`(companion) `G`(транспорт) + паринг `L02`;
`C14`(perm-UI) → `F10`(capability-review) + security-privacy. Офлайн-LLM поверх v1-пайплайна;
companion читает `E`(v2) / trip-плагин.
- **Готово, когда:** сеть выключена → ассистент локально отвечает (`D13`) · сторонний плагин
ставится/песочница/ревью разрешений · телефон-companion синкает настройки/память/поездки
(local-first).
- **🟡 гейты:** `D13` (выбор офлайн-модели — бенч на железе), `D14` (схема памяти / consent),
`F11` (схема подписи / keyring / ревокация), `H11` (FM-тюнер: аппаратно добавить vs отказаться —
нет в hardware §4), `L03` (моб.стек: Flutter vs Rust-core+native),
`L06` (push-транспорт: relay vs APNs/FCM vs локально).
**Демо:** ассистент отвечает **без сети** (локальная модель); сторонний **плагин** (intent/tile) ставится в
песочнице с ревью разрешений; **companion**-приложение на телефоне видит данные машины/поездки.
| Веха | Заработало | ID | Зависит | Тест без машины | Готово, когда |
|------|-----------|----|---------|-----------------|---------------|
| **v3.1** Plugin host | песочница + lifecycle | F05 F06 F07 F08 F09 F10 C14 | v0 (App-Host, a-base §3), plugin-sdk, sec-priv | plugin-host-харнесс (F) | сторонний плагин install/update/remove в песочнице; ревью разрешений (perm-UI C14) |
| **v3.2** Plugin-интенты + подпись | расширение ассистента | D15 F11 | v3.1, v1-ассистент (D06) | тест-плагин с intent | плагин регистрирует интент, ассистент его зовёт; подпись манифеста |
| **v3.3** Офлайн-ассистент | работает без сети | D13 D14 | v1-пайплайн, storage | мок-сеть off + локальная мелкая модель | сеть выключена → локальный ответ; память водителя (`.md`) |
| **v3.4** Companion | телефон видит машину | L01 L02 L03 L04 L05 L06 L08 | v1.3 (G), v2 (E/trip-плагин) | фейк-companion-peer + мок-облако | паринг; синк настроек/памяти/поездок local-first; бэкап |
| **v3.5** Связь+медиа-расширения | hotspot/SMS/радио/стриминг | G11 G12 H11 H12 H13 H14 | v1.3, v3.1 (для H14), network | моки сети/медиа | WiFi-hotspot; SMS-чтение; media-source через плагин |
**Порядок/параллелизм:** v3.1→v3.2 (host перед интентами/подписью); v3.3 поверх v1-пайплайна (независимо);
v3.4 после v3.1+v2; v3.5 после v3.1.
**🟡 гейты:** `D13` (офлайн-модель) · `D14` (схема памяти/consent) · `F11` (схема подписи) · `L03` (моб-стек) · `L06` (push-транспорт) · `H11` (FM-тюнер: аппаратно vs отказаться).
---
## v4 — Навигация + OTA + прод-образ + ретрофит · *критпуть: первый «продукт»*
- **Цель/демо:** офлайн-навигация OSM с голосовым turn-by-turn; **флешируемый релиз-образ**;
**OTA** A/B с откатом; **документированный ретрофит на одну реальную машину**. Демо: первый продукт.
*(«образ» здесь = флешируемый прод-релиз, отличать от bring-up/base-образа v0 —
см. [a-base-system](domains/a-base-system.md) §2.)*
- **Входит:**
- *Навигация (I):* `I01 I02 I03 I04 I05 I06 I07 I08 I09 I10 I11 I12 I13` + nav-позиционирование `K09`
- *OTA / прод-образ / безопасность (A):* `A03` (флеш-образ RAUC) `A19` (OTA) `A20` (secure boot)
`A21` (at-rest шифрование) `A22` (factory reset)
- *OTA-канал / облако (L):* `L09 L10 L11 L12 L13`
- *Проекция (опционально):* `G13` (CarPlay/Android Auto — вне скоупа / плагин / неопр.)
- **Зависимости/порядок:** `I`(роутинг) → движок (🟡); `I`(карты) → хранилище + покрытие;
`I06`(map-matching) → `K`(Location, v1); `I05`(turn-by-turn) → аудио (H §3) + `D`. OTA:
`A19`(механизм/применение) ↔ `L09`(канал/доставка); `A20`(secure boot) → `A21`(at-rest) →
trust-anchor для `F11`(подпись, v3). Nav поверх `K`/`H`/`D` (v1).
- **Готово, когда:** маршрут офлайн с голосовым ведением в загруженном регионе · релиз-образ
прошивается · OTA доставляет/применяет/откатывает (anti-rollback) · **ретрофит на одну машину
задокументирован** (BSP / калибровка / гайд).
- **🟡 гейты:** `I03` (Valhalla vs OSRM), `I01` (карты + ODbL-атрибуция + размещение данных),
`G13` (проекция — решить scope/legal).
**Демо:** офлайн-навигация OSM с голосовым turn-by-turn; **флешируемый релиз-образ**; **OTA** A/B с откатом;
**документированный ретрофит на одну реальную машину**.
*(«образ» здесь = флешируемый прод-релиз, отличать от bring-up base-образа v0 — [a-base §2](domains/a-base-system.md).)*
| Веха | Заработало | ID | Зависит | Тест без машины | Готово, когда |
|------|-----------|----|---------|-----------------|---------------|
| **v4.1** Карты + рендер | карта офлайн | I01 I02 I04 I08 | tech-stack, хранилище, C §4, G §2 | нав-сим (тест-регион PMTiles) | карта рендерится офлайн (GPU); детект «вне региона»; геокодер |
| **v4.2** Роутинг + ведение | маршрут с голосом | I03 I05 I06 I07 I09 I10 I11 I12 I13 K09 | v4.1, v1.2 (Location), v1.1 (аудио), D §6 | мок-маршрут (rerouting/maneuver) | turn-by-turn-ведение; map-matching; назначение голосом; resume |
| **v4.3** Прод-образ + secure boot | флешируемый релиз | A03 A20 A21 A22 | v0-образ, hardware | флеш на железо (HW-in-the-loop) | релиз-образ прошивается; verified boot; `/data` шифрован; factory reset |
| **v4.4** OTA-канал | обновления с откатом | A19 L09 L10 L11 L12 L13 | v4.3 (trust-anchor), v3.4 (паринг), F11 | мок-облако/OTA (подписанные/битые/downgrade) | OTA доставляет/применяет/откатывает; anti-rollback; каналы stable/beta |
| **v4.5** Ретрофит + опц. | первый продукт на авто | G13 | всё v0–v4 на реальном авто | реальная установка | **документированный ретрофит на одну машину** (BSP/калибровка/гайд) |
**Порядок/параллелизм:** v4.1→v4.2 (карты перед роутингом); v4.3→v4.4 (secure boot trust-anchor перед signed OTA);
нав-ветка (v4.1/v4.2) и OTA-ветка (v4.3/v4.4) **параллельны**; v4.5 — финал, требует всего.
**🟡 гейты:** `I03` (Valhalla vs OSRM) · `I01` (карты + ODbL-атрибуция + размещение данных) · `G13` (проекция — scope/legal).
---
## Сквозные треки (не привязаны к одной фазе)
- **Dev-environment + моки** *(проектируется до v0, параллельно всем фазам).* Разблокирует
разработку без железа: fake-аудио/BT/камера/plugin-host (внесены) + **хвост:** L мок-облако/OTA
и I нав-сим (тест-регион/мок-маршрут). ID: `F02 F03 F04 J06` + доменные dev-симуляторы
(G/H/I/L §«Dev-симулятор»). Не на критпути.
- **Security/privacy-гейтинг** *(растёт по фазам).* Capability-модель (security-privacy §3)
включается с первого чувствительного ресурса: `audio_in` (v1) → `camera_in`/location-consent
(v2) → plugin-capability-review + perm-UI `C14` (v3) → secure-boot/at-rest/trust-anchor (v4).
- **Цепочка доверия OTA.** Подпись плагинов `F11` (v3) → secure boot `A20` + signed OTA
`A19`/`L09` (v4) образуют единую trust-цепочку с anti-rollback.
## Критический путь (узким списком)
## Сквозной критический путь (по вехам)
```
hardware/BSP → A(образ) → B(power-safe) → C(shell) ⟶ v0
→ G01(сеть) + H01(аудио) → D(ассистент) ⟶ v1
∟ K01(Location) → distraction (C12/D12) — параллельно
E(CAN read) → D10(контекст — killer) ⟶ v2
D13(офлайн-LLM) + F(Plugin API) ⟶ v3
I(навигация) + A19/L09(OTA) + ретрофит ⟶ v4
hardware/BSP → v0.1(образ) → v0.2(boot) → v0.3(power-safe) v0.5(shell) ⟶ v0
└→ v0.4(MCU/thermal)
→ v1.1(аудио)+v1.2(Location)+v1.3(сеть) → v1.4(пайплайн) → v1.5(LLM онлайн) ⟶ v1
v2.1(CAN) → v2.2(DTC) → v2.3(контекст — KILLER) ⟶ v2
v3.1(plugin-host) → v3.3(офлайн-LLM) ⟶ v3
v4.1(карты) → v4.2(роутинг) ‖ v4.3(secure boot) → v4.4(OTA) → v4.5(ретрофит) ⟶ v4
```
Параллельно (не на критпути): телефон/медиа/камера (v2-треки рядом с `E`), companion (v3),
dev-environment (сквозной).
Параллельно (не на критпути): телефон/медиа/камера (v2.4v2.6), companion (v3.4), расширения (v3.5),
нав- и OTA-ветки v4 идут одновременно. Сквозной enabling-трек — dev-environment (v0.6, далее везде).
## За горизонтом v4 (later/ongoing)
## Риск-реестр (🟡-гейты: что выбрать и к какой фазе)
Доразвитие из тех же доменов по мере спроса — не входит в лестницу v0–v4:
| Гейт | Выбор между | Решить к | Владелец-док |
|------|-------------|----------|--------------|
| `A01` база-образ | Armbian/Debian vs Yocto | **v0** | a-base §2 |
| `A02` ФС `/data` | f2fs vs ext4 | **v0** | a-base §3 |
| `B08/B09` питание | MCU-копилот vs supercap-only | **v0** | b-power §5, hardware §3 |
| distraction-пороги | числа км/ч + список блокируемого | **v1** (на HMI) | safety §4 |
| перф-бюджеты | латентные числа (кадр/голос/ввод…) | по фазам | performance §3 |
| `K05` мультируль | маппинг кнопок / ADC-калибровка | v1/v2 | k-sensors §3 |
| `E03` DTC-база | своя RU из открытых списков vs готовая | **v2** | e-vehicle-data §5 |
| `H06` декодер | `symphonia` + AAC-патент (юр-проверка) | **v2** | h-media §5 |
| `J01` камера | DRM-master handoff Stage 0→1 | **v2** | j-cameras §3 |
| `D13` офлайн-LLM | YandexGPT Lite / T-lite / Qwen + квантизация | **v3** | d-assistant §5 |
| `D14` память водителя | что авто-запоминать / схема / consent | **v3** | d-assistant §7 |
| `F11` подпись | формат / keyring / ревокация | **v3** | f-plugin §3, sec-priv §6 |
| `L03` моб-стек | Flutter vs Rust-core+native | **v3** | l-cloud §3 |
| `L06` push-транспорт | self-relay vs APNs/FCM vs локально | **v3** | l-cloud §5 |
| `H11` FM-тюнер | добавить аппаратно vs отказаться | **v3** | h-media §7, hardware §4 |
| `A19` OTA-тул | RAUC vs Mender/swupdate/OSTree | **v4** (раньше подтвердить) | a-base §5 |
| `I03` роутинг | Valhalla vs OSRM | **v4** | i-nav §4 |
| `I01` карты | ODbL-атрибуция + размещение данных | **v4** | i-nav §2 |
| `G13` проекция | not-first-party / плагин / вне скоупа | **v4** | g-conn §8 |
## Сквозные треки (вне одной фазы)
- **Dev-environment + моки** *(с v0.6, параллельно всему).* Разблокирует разработку без железа: Vehicle
Simulator (E), fake-аудио/BT/камера, plugin-host-харнесс, нав-сим, мок-облако/OTA. Не на критпути.
- **Security/privacy-гейтинг** *(растёт по фазам):* `audio_in` (v1) → `camera_in`/location-consent (v2) →
plugin-capability-review + perm-UI (v3) → secure-boot/at-rest/trust-anchor (v4). Контракт — [security-privacy.md](contracts/security-privacy.md).
- **Цепочка доверия OTA:** подпись плагинов `F11` (v3.2) → secure boot `A20` + signed OTA `A19`/`L09` (v4.3/v4.4) — единая trust-цепочка с anti-rollback.
- **Бюджеты/безопасность как gate:** [performance.md](contracts/performance.md) (CI perf-gate, регрессия = баг) и [safety.md](contracts/safety.md) (distraction, red-line-энфорсмент) — сквозные требования к каждой вехе.
## За горизонтом v4
Доразвитие из тех же доменов по мере спроса — не входит в лестницу v0–v4 (20 функций):
- **База:** `A23` (мульти-BSP) · `A24` (kernel/dtb-тюнинг — *ongoing*).
- **Shell/ассистент:** `C15` (мультидисплей / профили / виджеты) · `D16` (barge-in).
- **Vehicle-Data:** `E09` (trip-производные — *у плагина*) · `E10` (fuel-trim) `E11` (VIN)
`E12` (DBC-сниффинг) `E13` (vendor-DTC) `E14` (лог поездок).
- **Shell/ассистент:** `C15` (мультидисплей/профили/виджеты) · `D16` (barge-in).
- **Vehicle-Data:** `E09` (trip-производные — *у плагина*) · `E10` (fuel-trim) `E11` (VIN) `E12` (DBC-сниффинг) `E13` (vendor-DTC) `E14` (лог поездок).
- **Экосистема/медиа:** `F12` (курируемый стор) · `H15` (мульти-зона / EQ / A2DP-source).
- **Навигация:** `I14` (трафик TMC/RDS) `I15` (онлайн-трафик/поиск) `I16` (DR в тоннелях).
- **Камеры/датчики:** `J07` (0..N источников) `J08` (dashcam) `J09` (surround/360°) ·
`K07` (IMU) `K08` (выделенные не-CAN датчики).
- **Камеры/датчики:** `J07` (0..N источников) `J08` (dashcam) `J09` (surround/360°) · `K07` (IMU) `K08` (выделенные не-CAN датчики).