fix(power): coalesce charge-limit reapply events
All checks were successful
Check / eval (push) Successful in 3m16s

USB-C power event bursts could repeatedly restart and SIGTERM the settling oneshot until systemd reached its start limit. Let successful runs return inactive and use coalescing start jobs for immediate and delayed reapplication.

Verified: V0 nix flake check --no-build, module parse, and git diff --check; V2 focused battery-charge-limit KVM test with a 12-event active-run burst. V3 hardware item #101 remains queued.
This commit is contained in:
2026-07-13 14:09:05 +01:00
parent 2a34c7398b
commit 7bfe1af5b1
6 changed files with 102 additions and 19 deletions

View File

@@ -595,15 +595,18 @@ Design/decision records and a running log of shipped work (items marked
independent sysfs oneshot writes `charge_control_end_threshold`. Off by
default; the installer scaffolds it commented-out on laptops. ✓ the
threshold is now **re-applied on AC state changes** (a `services.udev`
rule on `SUBSYSTEM=="power_supply", ATTR{type}=="Mains"` restarts the
rule on `SUBSYSTEM=="power_supply", ATTR{type}=="Mains"` starts the
oneshot via `systemctl --no-block`), closing the firmware-resets-on-
unplug gap — the match is by adapter *type*, not kernel name
(AC/AC0/ADP1/ACAD vary), and `restart` (not `try-restart`) re-applies
even if the boot run was inactive. Eval-verified both ways (rule present
(AC/AC0/ADP1/ACAD vary). The successful oneshot returns inactive and
repeated `start` requests coalesce while it is applying; this avoids a
USB-C dock's event burst repeatedly terminating `restart` jobs and
tripping systemd's start limit. Eval-verified both ways (rule present
with charge limit on / absent off), and **VM-verified the trigger**
(`checks.battery-charge-limit`: the `test_power` module fakes a Mains
adapter, toggling `ac_online` emits a real `power_supply` uevent, and the
udev rule restarts the oneshot — confirmed by a changed `InvocationID`).
udev rule starts the oneshot — a burst during an intentionally extended
active run stays successful and a changed `InvocationID` proves reapply).
The sysfs *write* itself needs a real `charge_control_end_threshold`, so
a final on-hardware check (a `sudo nixos-rebuild` + a physical unplug)
remains — the dev box has both an `AC` Mains adapter and a `BAT0`