Files
shturman/docs/specs/v0.3-power-safe.md
kk0t9 4fe5103e88 docs(v0.3): спека power-safe ядра (FSM + graceful shutdown)
Веха v0.3: стаб Power → реальный lifecycle-FSM. Состояния off/accessory/running/
shutting_down{abortable,committed} (sleep/battery_cutoff — каркас); graceful
shutdown (ShutdownImminent→grace→durable-barrier sync→commit=PONR=unmount); abort
до PONR (re-power→ShutdownAborted). dev-mock кормит входы FSM. Watchdog/save-time/
монотоника. Подход A: FSM+сигналы, teardown через systemd/харнесс. Гибрид-E2E:
N=3 in-VM цикла + 1 reboot + abort + power-cut-сим. HW (hold-up/MCU/B08-B09) — v0.4.
Красные линии: Power не трогает CAN, без actuator (#2).

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

19 KiB
Raw Permalink Blame History

Спека реализации: v0.3 — Power-safe ядро (FSM + graceful shutdown)

Веха v0.3 роадмапа: «переживает срыв питания». Capabilities B01 (детект ACC), B02 (graceful shutdown sequencing), B03 (FSM + abort/committed), B04 (ru.shturman.Power), B05 (watchdog), B06 (load-shedding), B07 (save last-known-time), A14 (HW-watchdog + recovery). Поверх v0.2. Источники: docs/domains/b-power-lifecycle.md, docs/contracts/safety.md, docs/contracts/hardware.md, docs/contracts/ipc.md §3, docs/roadmap.md §v0.3. Приёмка роадмапа: «N циклов зажигания без потери /data; abort до PONR».


1. Цель и первый артефакт

Оживить стаб Power (v0.1: плоский State, mock флипает ignition/power) в реальный lifecycle-FSM: ACC → graceful shutdown с durable-write до PONR → переживание срыва питания.

Первый артефакт: fake-ACC-off → FSM runningshutting_downShutdownImminent → grace → commit (durable-write barrier sync → unmount /data = PONR); N=3 цикла зажигания/data цел; abort до PONR (re-power → ShutdownAbortedrunning); power-cut-сим (SIGKILL до fsync → /data консистентен).

Не цель v0.3: реальный hold-up cap / MCU-протокол / fail-safe-таймер и выбор B08/B09 (MCU vs supercap) — v0.4 (вероятно нужна аппаратная проверка); реальный /dev/watchdog арминг — HW; полные sleep/wake/long-park — v1/v2; перф-вердикт — RK3588.


2. Скоуп и границы

2.1 В скоупе (делаем сейчас)

  • FSM питания (B03): чистый модуль PowerFsm — состояния, события, переходы, действия. Юнит-тестируемый без D-Bus. Внутренние субсостояния ShuttingDown{Abortable, Committed} маппятся в D-Bus shutting_down.
  • Детект ACC-логика (B01): debounce/гистерезис + crank-приоритет — формализованы в FSM (вход AccOff принимается только как стабильный; в VM источник — fake-ACC dev-mock). Реальный GPIO/MCU-детект — HW.
  • Graceful shutdown sequencing core (B02): ShutdownImminent(sec, reason) → grace-окно → durable-write barrier (sync(2); Settings уже синхронен) → commit → unmount (PONR). Ordered teardown апов/CAN — позже (§2.2).
  • Abort до PONR (B03): re-power в abortable → ShutdownAborted → назад в running/accessory.
  • Load-shedding (B06): хук на commit/power-loss — в v0 лог (реальных нагрузок нет; рейлы amp/подсветка/ модем — HW).
  • Watchdog (B05/A14): systemd RuntimeWatchdogSec (runtime) + RebootWatchdogSec (shutdown-фаза) — **конфиг
    • дисциплина**. Реальный /dev/watchdog/MCU-арминг — HW.
  • Save last-known-time (B07): shturman-savetime.timer+.service — periodic fake-hwclock save (/data) + on-shutdown save (в graceful sequence до PONR). fake-hwclock/data — уже из v0.6.
  • Монотоника (§8): Uptime + grace-timer + все lifecycle-таймеры на CLOCK_MONOTONIC (shturman_common::monotonic_secs уже есть). НЕ wall-clock.
  • Харнесс: FSM-юниты (каждый переход) + integration (сигналы по session-шине) + E2E гибрид (§9).

2.2 Явно НЕ в скоупе (отложено, с указателем «куда»)

  • Hold-up cap / supercap, MCU-копилот, MCU fail-safe-таймер, SoC↔MCU heartbeat/safe-to-cut, реальный power-cut energy budget + дератинг по THW (hardware §3); выбор B08/B09 (MCU vs supercap-only) — v0.4.
  • Реальный /dev/watchdog арминг + bootcount-handshake recoveryHW/v4 (в VM watchdog-device нет).
  • Полные sleep/wake + long-park battery-cutoff (низкопотребление, wake-on-ACC/таймер/реверс) — v1/v2 (B §7). В v0.3 состояния sleep/battery_cutoffзарезервированы (переходы заглушены).
  • Consumer-ack save-протокол (ShutdownImminent→consumers save→ack/timeout, сумма ≤ hold-up-бюджет) — App-Host v3 (в v0 Settings durable-write синхронен → ack не нужен).
  • E гасит OBD-TX / закрывает ISO-TP при shutdownдомен E / v1 (Power не трогает CAN, §3).
  • Перф-вердикт (time-to-shutdown, hold-time) — RK3588 (performance §2). В VM — функционально.

2.3 Частично в скоупе (каркас сейчас, тело — позже)

  • sleep/battery_cutoff — состояния в enum/FSM есть, переходы no-op/заглушка (тело — v1/v2).
  • Load-shedding — лог-хук (реальные рейлы — HW).
  • Watchdog — конфиг systemd (реальный арминг — HW).
  • ACC-детект — debounce-логика в FSM (источник в VM — fake-ACC; реальный GPIO/MCU — HW).

2.4 Трассируемость ID → статус

ID Веха Статус в v0.3
B01 Детект ACC (debounce + crank) логика в FSM; источник VM = fake-ACC (реальный GPIO/MCU — HW)
B02 Graceful shutdown sequencing core: ShutdownImminent→grace→durable-barrier→commit (teardown апов/CAN — позже)
B03 FSM + abort/committed полностью (sleep/battery_cutoff — каркас)
B04 ru.shturman.Power оживлён из FSM (сигналы/состояние — реальные переходы)
B05 Watchdog конфиг RuntimeWatchdogSec/RebootWatchdogSec + дисциплина (реальный WDT — HW)
B06 Load-shedding лог-хук (реальные нагрузки — HW)
B07 Save last-known-time periodic timer + on-shutdown save в /data
A14 HW-watchdog + recovery конфиг + дисциплина (реальный арминг/recovery — HW/v4)

3. Красные линии, безопасность

  • #2 (нерушимо): Power не трогает CAN и не имеет actuator-путей — только software-оркестрация lifecycle + read-only состояние. CAN-TX-гашение при shutdown — домен E (v1), не Power. Граница — safety.md.
  • #5 (power-safe): durable-write до PONR — главная гарантия; FSM коммитит только после grace + sync. Реальный power-cut на HW; в VM — функциональная модель + атомарность файла (foundation §9.1) уже доказана.
  • Прод-гейт: dev-mock PowerMock1 (fake-ACC/voltage/thermal) — за фичей dev-mocks; прод --no-default-features → не регистрируется (foundation §5.2, §8.3).

4. Раскладка (новые/изменённые артефакты)

  • crates/core/shturman-power/src/fsm.rs (новый) — PowerFsm: State, Event, Action, fn step(&mut self, Event) -> Vec<Action>. Чистый, без D-Bus/async. Grace-таймер — снаружи (сервис), FSM лишь даёт StartGrace(sec)/ принимает GraceExpired.
  • crates/core/shturman-power/src/service.rs — обернуть FSM: D-Bus state/properties/signals из FSM; dev-mock методы кормят FSM-события (не флипают State напрямую).
  • crates/core/shturman-power/src/main.rs — grace-таймер (монотоника, tokio), durable-write barrier (sync), трансляция FSM-actions → D-Bus-сигналы.
  • systemd: shturman-power.service drop-in RuntimeWatchdogSec= (дисциплина); shturman-savetime.service+ .timer (B07 periodic save); system RebootWatchdogSec= (shutdown-дедлайн). Раскладка — lima/E2E.
  • harness: tests/e2e/run.sh — блок power-safe (гибрид §9); integration-тесты в crates/core/shturman-power/tests/.

5. FSM питания (B03) — контракт

Состояния (внутренние): Off, Accessory, Running, ShuttingDown { phase: Abortable | Committed, reason }, Sleep, BatteryCutoff (* — зарезервированы). D-Bus-маппинг (PowerState): ShuttingDown{*}shutting_down; остальные 1:1.

События (Event): AccOn, AccOff, EngineOn, EngineOff (accessory↔running по напряжению; VM — mock), UnderVoltage, ThermalTrip, GraceExpired. (Re-power = AccOn во время shutdown.)

Переходы:

Из Событие В Действия
Off AccOn Accessory EmitAccChanged(true)
Accessory EngineOn Running
Running EngineOff Accessory
Accessory/Running AccOff ShuttingDown{Abortable, acc_off} EmitShutdownImminent(sec, acc_off), StartGrace(sec)
Accessory/Running UnderVoltage ShuttingDown{Abortable, under_voltage} EmitShutdownImminent(sec, under_voltage), StartGrace(sec)
Accessory/Running ThermalTrip ShuttingDown{Abortable, thermal} EmitShutdownImminent(sec, thermal), StartGrace(sec)
ShuttingDown{Abortable} AccOn (re-power) Running EmitShutdownAborted, EmitAccChanged(true)
ShuttingDown{Abortable} GraceExpired ShuttingDown{Committed} Commit (durable-barrier → PONR)
ShuttingDown{Committed} Off (cut: unmount + снятие питания — systemd/харнесс/HW)
Sleep/BatteryCutoff * (no-op) зарезервировано (v1/v2)

Действия (Action): EmitShutdownImminent(reason), EmitShutdownAborted, EmitAccChanged(bool), StartGrace(secs), Commit. reason ∈ {acc_off, under_voltage, thermal, battery_cutoff}. Инвариант: после Committed abort невозможен (только → Off). Чистота: step детерминирован, без I/O; сервис исполняет действия (сигналы/таймер/sync). Юнит-тест — каждый переход.


6. Graceful shutdown (B02/B06) — последовательность (подход A)

Power-сервис = FSM + сигналы + grace/abort-окно; реальный teardown (unmount/cut) — через systemd (реальный poweroff) либо харнесс (in-VM-цикл). На железе — MCU/supercap-sequencing (v0.4).

  1. AccOff (стабильный; VM — fake-ACC) → ShuttingDown{Abortable}ShutdownImminent(sec, acc_off) + grace-таймер (монотоника). Потребители (приборка/будущие апы) получают сигнал и сохраняются.
  2. Abort-окно (abortable): AccOn до GraceExpiredEmitShutdownAbortedRunning; откат load-shed (v0: лог).
  3. GraceExpired → Commit: save last-known-time (B07) → durable-write barrier (sync(2); Settings уже синхронен по каждому Set) → Committed (= PONR).
  4. PONR = unmount /data (RW→RO): на реальном poweroff — systemd; в in-VM-цикле — харнесс; на HW — MCU/supercap дают энергию завершить unmount/sync до cut.
  5. Load-shedding (B06): на commit/power-loss — лог «load-shed: amp/backlight/modem (реальных нагрузок нет в v0)»; hold-up кормит SoC+хранилище — HW.

Гарантия #5: commit (и потому unmount/PONR) наступает только после grace + sync → усечённый shutdown оставляет /data консистентным (атомарность файлов — foundation §9.1).


7. D-Bus ru.shturman.Power — v0.3 оживляет (расширение foundation §5.2)

  • Состояние/properties из FSM (не из плоского State): GetPowerState, IgnitionState, PowerSource, Uptime.
  • Сигналы из FSM-actions (не из mock-флипа): AccChanged, ShutdownImminent(sec, reason), ShutdownAborted. Sleep/Wakeобъявлены, не эмитятся (sleep — v1/v2).
  • PowerSource: vehicle_12v (норма) → на under-voltage/commit сигналим holdup_cap/low_battery (потребителям «времени мало»). sleep_rail — v1/v2.
  • dev-mock ru.shturman.dev.PowerMock1 (fake-ACC, фича dev-mocks) — кормит входы FSM:
    • SetAcc(on)AccOn/AccOff;
    • SetIgnition(state)EngineOn/EngineOff (accessory↔running) либо AccOn/AccOff;
    • TriggerShutdown(sec, reason)UnderVoltage/ThermalTrip с заданным grace;
    • AbortShutdown() → re-power (AccOn) в abortable. Прод-сборка mock не регистрирует (#3-гейт §3). Policy send_destination=ru.shturman.Power покрывает (foundation §13).

8. Watchdog / монотоника / save-time

  • Watchdog (B05/A14): drop-in shturman-power.service.d/watchdog.confRuntimeWatchdogSec= (дисциплина: один userspace-владелец WDT). System systemd/system.conf.d RebootWatchdogSec= — дедлайн shutdown-фазы (зависание в unmount/sync не оставит устройство под питанием). В VM /dev/watchdog нет → конфиг присутствует, реальный арминг — HW (VM↔HW-граница, как zram/vcan в v0.6). MCU-backstop — v0.4.
  • Монотоника (§8): Uptime + grace-таймер + sleep/wake-таймеры на CLOCK_MONOTONIC (monotonic_secs). Wall-clock легитимно прыгает на NTP/GPS-синке — lifecycle на него не завязан.
  • Save last-known-time (B07): shturman-savetime.service (fake-hwclock save с FILE=/data/..., как в v0.6) + .timer (~15 мин, monotonic). On-shutdown save — шаг 3 §6. После срыва часы откатываются максимум на интервал.

9. Dev-харнесс и план тестирования

9.1 Unit (FSM — fsm.rs)

Каждый переход §5: Off→Accessory→Running; Running→ShuttingDown{abortable,reason} для каждого reason; abort (Abortable+AccOn→Running+ShutdownAborted); GraceExpired→Committed+Commit; Committed — abort игнорируется; Sleep/BatteryCutoff — no-op. Действия проверяются по возвращаемому Vec<Action>.

9.2 Integration (session-шина, #[ignore], just test-integration)

SetAcc(false) → наблюдаем ShutdownImminent; AbortShutdown (в abortable) → ShutdownAborted; SetIgnitionIgnitionState property; GetPowerState отражает FSM.

9.3 E2E (Lima, гибрид — расширение run.sh)

  • N=3 in-VM цикла зажигания: записать /data-маркер (Settings ui.theme=night + счётчик /data/state/power-cycles); цикл: fake-ACC-off → наблюдать ShutdownImminent → харнесс: stop shturman-stage1.target + sync + umount /datamount /data → restart → маркер цел, счётчик++. После 3 циклов: night + счётчик=3.
  • 1 реальный reboot-цикл: fake-ACC-off → commit → systemctl powerofflimactl start → boot → /data цел.
  • Abort до PONR: fake-ACC-off → ShutdownImminent → fake-ACC-on до unmountShutdownAborted наблюдаем → /data RW (смонтирован) → GetPowerState=running.
  • Power-cut-сим: во время shutdown (до fsync) SIGKILL power+settings → /data: remount ok, fsck -n clean, последнее durable-значение присутствует (атомарность §9.1 на уровне файла).
  • Монотоника: Uptime растёт; не прыгает при wall-clock-синке.
  • Watchdog/save-time: drop-in RuntimeWatchdogSec у power.service присутствует; shturman-savetime.timer активен; /data/state/fake-hwclock.data обновляется.

9.4 Критерии приёмки

  • FSM: все переходы §5 покрыты unit-тестами; sleep/battery_cutoff — no-op/документированы.
  • ShutdownImminent на ACC-off; abort до PONR → ShutdownAborted; commit только после grace + durable-barrier.
  • N=3 цикла зажигания — /data + счётчик целы (нет потери).
  • 1 реальный reboot-цикл — /data цел.
  • power-cut-сим — /data консистентен (fsck -n clean, last value present).
  • Uptime монотонен; lifecycle-таймеры на CLOCK_MONOTONIC.
  • watchdog-конфиг (RuntimeWatchdogSec/RebootWatchdogSec) на месте; savetime.timer активен.
  • Регресс v0.1/v0.2 (foundation §9.4 + v0.2 §9.3) зелёный (фазы/кадр/персист не сломаны).
  • just ci зелёный; красные линии целы (нет CAN/actuator); prod-build-gate (--no-default-features → нет PowerMock1) зелёный.

10. Двунаправленные швы (синхронизировать при реализации)

  • domain B: пометить реализованные срезы B01–B07 (v0.3, VM-модель); abort/PONR в VM = stop+umount+remount; HW (MCU/hold-up/heartbeat/safe-to-cut/fail-safe-таймер) + выбор B08/B09v0.4.
  • ipc.md §3: Power-сигналы/состояние оживлены из FSM (не mock); Sleep/Wake зарезервированы.
  • foundation §5.2: «Power-стаб» → реальный FSM (обновить формулировку «стартует в running, без логики»).
  • hardware §3 / B §5: B08/B09 (MCU vs supercap-only) остаётся открытым 🟡 → v0.4.
  • CLAUDE.md: статус v0.3 готово → следующее v0.4/v0.5.

11. Дальше по ритму

v0.3 (эта спека) → writing-plansTDD (FSM-юниты → сервис-обёртка → durable-barrier/grace → systemd/save-time → E2E-блок) → реализация → verify в Lima → коммит. Далее: v0.4 (MCU/thermal — замыкает B08/B09) после v0.3; v0.5 (полный shell) параллельно.