# Спека реализации: v0.2 — Boot-конвейер (Stage 0/1/2 + splash) > Веха `v0.2` роадмапа: «splash → таргет фазами»; capabilities **A04** (быстрый boot Stage 0/1/2, <10 c), > **A05** (splash, Stage 0), **A15** (systemd-таргеты/оркестрация). Поверх **v0.1** (образ + `/data` + `shturman.target`). > Источники: `docs/architecture.md` §6 (boot), `docs/domains/a-base-system.md` §4, `docs/roadmap.md` §v0. > Приёмка роадмапа: **«Stage 0/1/2 разделены; splash мгновенно»**. --- ## 1. Цель и первый артефакт Превратить плоский `shturman.target` (v0.1: один critical set) в **фазовый boot-конвейер** из трёх явных стадий, с **мгновенным splash** до первого кадра Shell и **деферредом фоновой нагрузки** после интерактива. **Первый артефакт:** на boot VM рендерится `/run/shturman/splash.png` (Stage 0) **раньше**, чем `/run/shturman/frame.png` (Stage 1, Shell), а Stage 2 (warmup) стартует **после** кадра. Все три стадии — отдельные systemd-таргеты, достижимые и упорядоченные; boot-тайминг логируется. **Не цель v0.2:** перфоманс-вердикт (<10 c — на RK3588, performance §2; в VM — функционально); красивый визуальный язык splash/Shell (язык — гейт v0.5); реальные Stage-2-сервисы (Vehicle-Data/Assistant/… — v1+). --- ## 2. Скоуп и границы ### 2.1 В скоупе (делаем сейчас) - **Splash (A05):** новый `shturman-splash` — Slint software-render брендового splash-кадра → PNG (headless, без дисплея/композитора; зеркалит механику shell-кадра v0.1). Стартует максимально рано (Stage 0, минимум зависимостей), **до** первого кадра Shell. - **Фазовые таргеты (A15):** `shturman-stage0/1/2.target` + рефактор `shturman.target` в **зонтик**. Члены нынешнего critical set переезжают в `shturman-stage1.target`. - **Деферред Stage 2:** `shturman-stage2-warmup.service` — oneshot-плейсхолдер (лог+маркер), `After` первого кадра. Каркас для реальных фоновых сервисов v1+. - **Boot-тайминг (A04):** E2E логирует `systemd-analyze` + Δ(splash→frame); **функционально, не гейт**. Жёстко ассертим **порядок фаз** (splash → frame → warmup) и **достижимость** трёх таргетов. - **Общий рендер-хелпер:** headless Slint-software-render → PNG выделяется из `shturman-shell` в переиспользуемый модуль (используют shell + splash). Точное место — план реализации. ### 2.2 Явно НЕ в скоупе (отложено, с указателем «куда») - **U-Boot splash (Stage 0 на железе):** framebuffer-картинка загрузчика до ядра — **HW** (a-base §4, §1). В VM U-Boot'а нет → splash моделируем systemd-сервисом (шов §10). - **Splash→Shell handoff на реальном дисплее** (без чёрного мелькания, передача поверхности композитору) — **v0.5** (Shell/композитор smithay). В VM обе стадии — отдельные PNG. - **Ранний низколатентный путь задней камеры/парктроника в Stage 0** (a-base §1 шов с J/B) — **домен J / v1+**. - **A/B boot-select, bootlimit, mark-good, secure/verified boot, security-version rollback** (a-base §2, §4) — **HW/v4** (нет U-Boot/eFuse в VM). - **Перф-вердикт <10 c** — **RK3588** (performance §2). В VM — функциональный замер с пометкой «не вердикт». - **Реальные Stage-2-сервисы** (Vehicle-Data, Assistant, Media, Nav, Connectivity) — **v1+** (домены E/D/H/I/G). ### 2.3 Частично в скоупе (каркас сейчас, тело — позже) - **Stage 2** — только структура (таргет + один warmup-плейсхолдер); приоритеты/oomd-жертвы фона проверяются на реальной нагрузке позже (performance §5). - **Параллельный быстрый boot** (минимальный initramfs, ленивые сервисы, a-base §4) — в VM моделируем systemd-фазами; тюнинг initramfs/ядра — HW. ### 2.4 Трассируемость ID → статус | ID | Веха | Статус в v0.2 | |----|------|----------------| | A04 | Быстрый boot Stage 0/1/2 <10 c | фазы разделены + тайминг логируется (вердикт — HW) | | A05 | Splash (Stage 0) | splash-сервис рендерит PNG до первого кадра (U-Boot framebuffer — HW) | | A15 | systemd-таргеты/оркестрация | зонтик + 3 фазовых таргета + splash/warmup юниты | --- ## 3. Красные линии, безопасность, лицензии - **#1/#2 (нерушимы):** boot-оркестрация + read-only splash — **нет** CAN/actuator/safety-путей. Splash не читает шину (статичный бренд-кадр), Shell-кадр — read-only OBD/состояние (как в v0.1). - **Лицензии:** новых тяжёлых зависимостей нет; splash переиспользует Slint (GPL-3.0 exception в `deny.toml`, уже заведено) + `png` (уже в lock). `just deny` — зелёный. - **eMMC write-min (A11):** splash.png/frame.png/маркеры — в **tmpfs `/run`** (volatile), не на flash. --- ## 4. Раскладка (новые/изменённые артефакты) ### 4.1 Бинари/крейты - **`shturman-splash`** (новый bin, `crates/apps/`): Slint-компонент splash + `--screenshot ` режим (как shell). Дефолт — интерактив (HW/dev-Mac); `--screenshot` — headless PNG (VM/E2E). Splash **не** читает шину (нет зависимости от Power/Settings — стартует до них). - **Общий рендер-хелпер** (выделить из `shturman-shell`): `render_component_to_png(ui, size, path)` поверх Slint software-renderer (thread_local `MinimalSoftwareWindow` + `set_platform` once + `draw_if_needed` + `png`). Используют `shturman-shell` и `shturman-splash`. Место (отдельный lib-крейт vs модуль) — план. ### 4.2 systemd-юниты | Юнит | Роль | Ключевое | |------|------|----------| | `shturman.target` | **зонтик** v0 | `Wants=`stage0+stage1+stage2; `After=data.mount`; `WantedBy=multi-user.target` | | `shturman-stage0.target` | Stage 0 (splash) | `Wants=shturman-splash.service` | | `shturman-stage1.target` | Stage 1 (ядро+кадр) | `Wants=`firstboot+machineid+power+settings+shell; `Requires/After=data.mount` | | `shturman-stage2.target` | Stage 2 (фон) | `Wants=shturman-stage2-warmup.service`; `After=shturman-stage1.target` | | `shturman-splash.service` | рендер splash | минимум зависимостей; `Before=shturman-shell.service`; oneshot+RemainAfterExit | | `shturman-stage2-warmup.service` | плейсхолдер фона | oneshot; `After=shturman-shell.service`; лог+маркер `/run/shturman/stage2.ready` | **Рефактор:** нынешние `WantedBy=shturman.target` у firstboot/machineid/power/settings/shell → **`WantedBy=shturman-stage1.target`**. `shturman.target` перестаёт прямо тянуть сервисы — тянет три под-таргета. --- ## 5. Контракты D-Bus **Новой поверхности нет.** Фазы boot — это systemd-оркестрация, не шина. (`BootStage`-property на `Power` рассматривалась — **YAGNI**, отвергнута: фазы наблюдаемы через `systemctl`/journald; реальный lifecycle-FSM — v0.3, домен B.) Power/Settings-контракты v0.1 — без изменений. --- ## 6. Splash — Stage-0 кадр (срез A05) - **UI (Slint):** минимальный брендовый кадр — wordmark «Штурман» по центру на тёмном фоне (нейтральный плейсхолдер; **визуальные токены design-system — каркас**, полный язык — гейт v0.5). Без статус-бара/тайлов (это Shell, Stage 1). Без чтения шины — **статичный** (поэтому стартует до Power/Settings → «мгновенно»). - **Рендер-бэкенды** (как Shell §6 v0.1): - *dev интерактивно:* Slint под weston/нативно. - *VM/E2E:* **software-renderer → `/run/shturman/splash.png`** (без дисплея); ассерт «splash не пустой». - **«Мгновенность»:** splash-сервис без `Requires=data.mount`/dbus — стартует на `basic.target`/`/run` готов, параллельно критическому набору; `Before=shturman-shell.service` гарантирует splash.png **раньше** frame.png. - **Граница:** на железе Stage-0-splash — U-Boot framebuffer **до** systemd (a-base §4); systemd-splash здесь — dev-модель + ранний пост-ядерный splash. Handoff на дисплее (splash→Shell без мелькания) — v0.5. --- ## 7. Boot-конвейер фазами (A04/A15) Модель (architecture §6, a-base §4): **Stage 0 мгновенно · Stage 1 ~3–5 c · Stage 2 фоном**. - **Stage 0:** `shturman-splash.service` → splash.png. Минимум зависимостей, до первого кадра. - **Stage 1 (нынешний critical set v0.1):** `data.mount` → firstboot → machineid → dbus → power+settings → **shell (первый кадр frame.png)**. Ordering — в самих юнитах (как в v0.1), членство — `shturman-stage1.target`. - **Stage 2:** `shturman-stage2-warmup.service` `After=shturman-shell.service` — стартует **после** кадра (деферред); пишет маркер `/run/shturman/stage2.ready` + лог. Каркас для фоновых сервисов v1+. - **Наблюдаемый порядок фаз:** `splash.png` (mtime) < `frame.png` (mtime) < `stage2.ready` (mtime); три таргета достижимы (`is-active`); warmup `After` кадра (journald-время старта > времени рендера кадра). - **Тайминг (A04, функц.):** E2E логирует `systemd-analyze time` + Δ(boot→splash) + Δ(boot→frame); порог <10 c **не гейтит** (вердикт — RK3588). Дисциплина: монотонные часы для замеров (a-base §4 / common-helper). --- ## 8. Dev-харнесс (расширение v0.6) - **`justfile`:** `splash-frame [path]` — инспекция splash-кадра (как `shell-frame`). `run`/`e2e` — без новых целей (фазы поднимаются тем же `shturman.target`). - **`tests/e2e/run.sh`:** добавить блок **«Stage 0/1/2»**: - три таргета `is-active`/reached; - `splash.png` существует, валидный PNG, mtime **< `frame.png`**; - `stage2.ready` существует, mtime **> `frame.png`** (warmup после кадра); - лог `systemd-analyze` + Δ-тайминги (не гейт). - **`lima/shturman.yaml`:** разложить новые юниты (stage0/1/2.target, splash, warmup) + бинарь splash в `run.sh`. Splash-зависимостей (пакетов) нет — Slint build-deps уже есть (v0.6). --- ## 9. План тестирования и приёмка ### 9.1 Unit - `shturman-splash`: `render → PNG` непустой, верный размер, бренд-фон тёмный (зеркало shell `screenshot.rs`). - Общий рендер-хелпер: один тест на оба компонента (или по тесту на крейт). ### 9.2 E2E (Lima, расширение `run.sh`) - **Фазы разделены:** `shturman-stage0/1/2.target` достижимы; splash.png **до** frame.png; stage2.ready **после**. - **Splash:** PNG валиден/непустой. - **Регресс v0.1/v0.6 не сломан:** все прежние проверки (mount/firstboot/per-unit/шина/fake-ACC/кадр/бюджеты/ персист+reboot) — зелёные на рефакторенных таргетах. - **Тайминг:** залогирован (функц.). ### 9.3 Критерии приёмки (acceptance) - [ ] `shturman.target` = зонтик; `shturman-stage0/1/2.target` достижимы и **разделены** (per-target active). - [ ] Splash-кадр рендерится (`splash.png` непустой) **раньше** первого кадра Shell (`frame.png`). - [ ] Stage 2 (warmup) стартует **после** первого кадра (деферред наблюдаем). - [ ] Boot-тайминг логируется (Δ splash/frame, `systemd-analyze`); <10 c — пометка «вердикт на RK3588». - [ ] Вся приёмка v0.1/v0.6 (§9.4 foundation) — **зелёная** на новой фазовой раскладке (нет регресса). - [ ] `just ci` зелёный; красные линии целы (нет CAN/actuator). --- ## 10. Двунаправленные швы (синхронизировать при реализации) - **a-base §4 / architecture §6:** уточнить, что в **dev-VM** Stage-0-splash — systemd-сервис (software-render PNG), а U-Boot framebuffer-splash — HW; пометить как VM↔HW-границу (как уже сделано для overlay/A-B в v0.6). - **roadmap §v0.2:** по прохождении — отметить веху ✅; «splash мгновенно» в VM = splash.png до frame.png. - **CLAUDE.md:** обновить статус (v0.2 готово → следующее v0.3/v0.5). - **v0.1-v0.6 spec §13:** добавить шов «shturman.target → зонтик; критический набор → stage1.target». - Если всплывёт: handoff splash→Shell и ранний путь камеры — указатели на v0.5 / домен J. --- ## 11. Дальше по ритму `v0.2` (эта спека) → **writing-plans** (план реализации: рендер-хелпер → splash → таргеты-рефактор → warmup → E2E-блок) → **TDD** → реализация → **verify в Lima** → коммит. Не писать код до утверждённой спеки. Далее по роадмапу: `v0.3` power-safe и `v0.5` shell — параллельно поверх v0.2.