Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Alexander <akotenev2003@gmail.com>
7.9 KiB
План 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(без регрессий). commitrefactor(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 + emitchanged);list(prefix);reset(key)(emitchanged);#[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 + emitacc_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 → commitfeat(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-ACCacc_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.