Files

94 lines
7.9 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.
# План 3 — стаб-сервисы `firstboot` / `settings` / `power` + интеграция на шине
> REQUIRED SUB-SKILL: `executing-plans` + TDD. Полный код — в `src` по ходу; здесь дизайн/задачи/acceptance.
**Goal:** поднять привилегированные стаб-сервисы ядра и доказать «шагающий скелет» на **живой шине**:
`Power`/`Settings` владеют именами, round-trip настроек, fake-ACC сигнал. First-boot идемпотентно готовит `/data`.
**Architecture:** сервисы — отдельные процессы (architecture §3/§4), зависят от `ipc` (контракт), **не** от `sdk`.
Каждый — **lib + bin** (логика в lib для тестов; `main` тонкий). Bus-bootstrap (`connect`) — общий, в `ipc::conn`.
Интеграция — на **session-шине** (`dbus-run-session`), тесты `#[ignore]` (не требуют шины в `just test`).
**Tech:** `zbus` `#[interface]` (server), `tokio`, `shturman-common` (Layout/atomic), `dbus` (session-bus для тестов).
**Решения v0:** Settings хранит **строковые** значения (variant на проводе; типы расширим позже) и **сам сеет
дефолты** на первом старте; firstboot создаёт каталоги + `machine-id` (`/dev/urandom`) + маркер, **дефолты не
сеет** (single source формата — Settings; шов §7.2 синхронизировать). `dev-mocks`**default-фича** power
(прод: `--no-default-features`).
---
### P3.1: `ipc::conn::connect` (рефактор из sdk)
- `crates/shturman-ipc/src/conn.rs`: `pub async fn connect() -> zbus::Result<zbus::Connection>` — система по
умолчанию, `SHTURMAN_BUS=session` → сессия (перенести тело из `sdk::connect`).
- `ipc/lib.rs`: `pub mod conn; pub use conn::connect;`. `sdk/connect.rs``pub use shturman_ipc::connect;`.
- Build + `just test` (без регрессий). commit `refactor(ipc): connect() в ipc::conn; sdk ре-экспортит`.
### P3.2: `shturman-firstboot` (A06) — lib provision + bin (TDD)
- `crates/core/shturman-firstboot` (members). Deps: `shturman-common`, `anyhow`.
- `lib.rs`: `pub fn provision(layout: &Layout) -> std::io::Result<bool>` — idempotent:
маркер есть → `Ok(false)`; иначе создать `/data/{apps,settings,state,log}`, сгенерить `state/machine-id`
(32 hex из `/dev/urandom`, если нет), **durable-write маркер последним**`Ok(true)`.
*(Привязка machine-id→`/etc/machine-id` — отдельный every-boot юнит, План 5. Дефолты настроек — Settings.)*
- `main.rs`: `init_tracing("shturman-firstboot")`; `provision(&Layout::from_env())`; лог; exit.
- **TDD-тесты** (tmp-`/data` через `Layout::new`): (а) идемпотентность (2-й прогон → `false`, структура/`machine-id`
стабильны); (б) factory-reset (снести маркер+wipe → пересоздание, новый `machine-id`); (в) mid-run (каталоги без
маркера → довосстановление, маркер появился).
- Red → impl → green → commit `feat(firstboot): идемпотентный provision /data + machine-id (A06)`.
### P3.3: `shturman-settings` — Settings1 server-стаб (lib + bin)
- `crates/core/shturman-settings` (members). Deps: `shturman-ipc`, `shturman-common`, `zbus`, `tokio`, `anyhow`;
dev-deps: `shturman-sdk`, `tempfile`.
- `store.rs` (lib): `Store{ layout, map: BTreeMap<String,String> }``load_or_seed` (если `settings.json` нет →
дефолты `ui.theme=auto`, `ui.units=metric`, durable-write); `get/set/reset/list`; persist через `common::write_atomic`.
**Unit-тесты:** seed при пустом, round-trip set→get, reset к дефолту, list по префиксу, неизвестный ключ.
- `service.rs` (lib): `SettingsService` + `#[interface(name="ru.shturman.Settings1")]`:
`get(key)->Result<OwnedValue,ipc::Error>` (неизвестный → `InvalidArgument`); `set(key,Value)` (только строка в
v0, иначе `InvalidArgument`; persist + emit `changed`); `list(prefix)`; `reset(key)` (emit `changed`);
`#[zbus(signal)] changed(ctx, key, value)`.
- `main.rs`: `connect()``object_server().at(settings::PATH, svc)``request_name(settings::NAME)` → park.
- Build + unit-тесты store зелёные → commit `feat(settings): Settings1 стаб + атомарный стор + seed`.
### P3.4: `shturman-power` — Power1 server-стаб + dev-mock (lib + bin)
- `crates/core/shturman-power` (members). Deps: `shturman-ipc`, `shturman-common`, `zbus`, `tokio`, `anyhow`;
dev-deps: `shturman-sdk`, `tempfile`. **Features:** `default=["dev-mocks"]`, `dev-mocks=[]`.
- `service.rs` (lib): `PowerService{ state, ignition, source, epoch }` + `#[interface(name="ru.shturman.Power1")]`:
`get_power_state()->String` (= `running` стаб); `request_sleep()` (no-op); `#[zbus(property)]`
`ignition_state`/`uptime`(монотон. `common::monotonic_secs`)/`power_source`; `#[zbus(signal)]`
`acc_changed`/`shutdown_imminent`/`shutdown_aborted`/`sleep`/`wake`.
`#[cfg(feature="dev-mocks")]` второй интерфейс `ru.shturman.dev.PowerMock1` на том же объекте:
`set_acc(bool)` (меняет ignition/state + emit `acc_changed`), `set_ignition(String)`,
`trigger_shutdown(u32,String)` (emit), `abort_shutdown()` (emit).
- `main.rs`: `connect()``at(power::PATH, svc)``request_name(power::NAME)` → park.
- **Unit-тест:** дефолты (`running`/running/`vehicle_12v`), `uptime` монотонен. Build → commit
`feat(power): Power1 стаб + dev-mock fake-ACC (feature)`.
### P3.5: интеграция на session-шине + `just test-integration`
- `shturman-settings/tests/integration.rs` (`#[ignore]`): in-process server на session-conn + `sdk::SettingsClient`
на втором conn → `set("ui.theme","night")``get`==night; приходит `changed`; неизвестный ключ → ошибка.
- `shturman-power/tests/integration.rs` (`#[ignore]`, `--features dev-mocks`): `PowerClient.power_state()==Running`;
`PowerMock1.set_acc(false)` → подписчик получил `acc_changed(false)`; снятие подписки по выходу владельца.
- `justfile`: `test-integration: dbus-run-session -- cargo test --workspace -- --ignored` (+ note: нужен `dbus`).
- Прогон под `dbus-run-session` зелёный (вручную; CI/Lima-E2E — План 5). `just ci` (unit) не затронут (тесты `#[ignore]`).
- commit `test(core): интеграция Settings/Power на session-шине (#[ignore])`.
---
## Acceptance (Плана 3)
- [ ] `cargo build --workspace` зелёный (3 сервиса; default-фича power включает dev-mock).
- [ ] `just test` (unit) зелёный: firstboot (идемпотентность/factory-reset/mid-run), settings-store, power-defaults; common/ipc/sdk не сломаны.
- [ ] `just test-integration` (под `dbus-run-session`): Settings round-trip + `changed`; Power state + fake-ACC `acc_changed`.
- [ ] `prod-build-gate`: `cargo build -p shturman-power --no-default-features``PowerMock1` не регистрируется (нет dev-mock-символов).
- [ ] `just ci` зелёный (fmt/clippy/test/deny). Границы: сервисы зависят от `ipc`, не от `sdk`.
## Дальше
План 4 — `shturman-shell` (Slint первый кадр на `sdk`) + `slint::testing` + slint GPL-3.0 exception в `deny.toml`.
План 5 — dev-tools (валидатор/scaffolding/fixtures) + systemd-юниты + Lima + сквозной E2E.