Files
shturman/docs/specs/v0.2-boot-pipeline.md
kk0t9 9a3b6a8753 docs(v0.2): спека boot-конвейера (Stage 0/1/2 + splash)
Веха v0.2: рефактор плоского shturman.target в фазовый конвейер.
- Stage 0: shturman-splash (Slint software-render → splash.png, до первого кадра);
- Stage 1: критический набор v0.1 → shturman-stage1.target (без изменений тела);
- Stage 2: shturman-stage2-warmup (oneshot-плейсхолдер, после кадра);
- shturman.target → зонтик; общий headless-render хелпер из shell переиспользует splash.
D-Bus-поверхности нет (фазы — systemd). Splash в VM = software-render PNG
(U-Boot framebuffer — HW, шов §10). Тайминг <10c — функц. в VM, вердикт на RK3588.
Приёмка: фазы разделены + splash до кадра + warmup после + регресс v0.1/v0.6 зелёный.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Alexander <akotenev2003@gmail.com>
2026-06-24 19:51:49 +03:00

198 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Спека реализации: 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 <path>` режим
(как 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 ~35 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.