From f2d8a1a29e9fce01e972483f919a5b048a348a09 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 5 Oct 2026 22:34:54 -0600 Subject: chore(tasks): log the dead bluetooth resume hook and its live check A dated entry under the sleep task records why the hook never fired and where it now lives. A Manual testing child gives the twenty-second suspend-then-hibernate cycle that proves it runs from the new directory. --- todo.org | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/todo.org b/todo.org index 015f8b0..e735423 100644 --- a/todo.org +++ b/todo.org @@ -3194,6 +3194,32 @@ Mistake worth remembering: =journalctl --since … -k= silently limits itself to the current boot (=-k= implies =-b=); cross-boot kernel facts need =_TRANSPORT=kernel= or an explicit =-b=. +*** 2026-10-05 Mon @ 22:18:03 -0600 The bluetooth resume hook never ran: it was installed where systemd-sleep doesn't look +Bluetooth came back rfkilled after tonight's suspend-then-hibernate (S4 wake +19:43 MDT, hci0's rfkill entry recreated at resume, bluetoothd "Failed to set +mode: Failed (0x03)"), the same double fault the 08-21 hook was written for. +The hook had never fired: btusb was deregistered only twice since 08-20, both +by hand (the 08-21 07:39 test and tonight's 20:06 relief), across about +fifteen hibernate cycles. Cause: the installer created +=/etc/systemd/system-sleep/= and put the hook there, and systemd-sleep (262, +and 261 before it) scans only =/usr/lib/systemd/system-sleep/=. That is the +one path in the binary and the one the man page names, which is also why Arch +ships no =/etc= directory. TLP's hook lives in =/usr/lib= and does run, and +=tlp resume= restores the rfkill state it saved at suspend, so once bluetooth +is blocked at any sleep edge TLP carries the block across every later cycle. + +Fixed tonight: the installer now installs to =/usr/lib/systemd/system-sleep/= +(the step's test pins the full install list, so a copy under =/etc= fails it), +and the live hook on velox was moved there with the dead =/etc= directory +removed. A hand run from the new path exits 0. Ratio has no hook in either +directory and no TLP, so nothing to do there. The real-cycle check rides the +Manual testing task ("Bluetooth resume hook fires on a real sleep cycle"). +One caveat for that check: =man systemd-sleep= says the hooks run in parallel, +so the zz- prefix buys no ordering after TLP's hook (the hook's own comment +claims it does and needs correcting). The reload's one-second settle should +make this hook's unblock land after =tlp resume=, and the re-check step is +what shows it if the race goes the other way. + *** TODO Hibernate entry freeze — confirm under observation, then mitigate :bug:velox:hibernate: Interim rule until this closes: do not hibernate unattended on battery. Shut down, or suspend on AC. @@ -5180,6 +5206,40 @@ Expected: =zfs holds= showed the =upgrade-guarded= tag on the snapshot step -Qkk= over the reconciled names reports no mismatch, including the package cut off mid-extraction. +*** Bluetooth resume hook fires on a real sleep cycle +What we're verifying: that =/usr/lib/systemd/system-sleep/zz-bluetooth-resume= +runs at resume now that it lives in the one directory systemd-sleep scans. Its +old home under =/etc/= was never scanned, so the proof is a btusb reload in the +kernel log at the moment of resume, which about fifteen cycles never showed. +Do it on AC. A twenty-second cycle only suspends, so the hibernate entry +freeze does not come into it. +- Confirm the starting state and note the time: +#+begin_src sh :results output +rfkill list bluetooth | grep Soft; bluetoothctl show | grep Powered; date +%H:%M:%S +#+end_src +- Start a suspend-then-hibernate cycle (the hook reloads btusb for that class + whether or not the hibernate stage was reached): +#+begin_src sh :results output +systemctl suspend-then-hibernate +#+end_src +- Wait about twenty seconds. +- Wake it with a key press. +- After the wake, read the kernel log. The hook itself logs nothing, and + systemd-sleep logs a hook only when it fails, so the system-sleep and + zz-bluetooth terms should match nothing on a pass: +#+begin_src sh :results output +journalctl -b -o short-iso --since "-5 min" | grep -E 'btusb|system-sleep|zz-bluetooth|Failed to set mode' | tail -12 +#+end_src +- Re-check the radio state: +#+begin_src sh :results output +rfkill list bluetooth | grep Soft; bluetoothctl show | grep Powered +#+end_src +Expected: a "deregistering interface driver btusb" line and a fresh btusb +registration, both stamped within seconds of the resume; no system-sleep line +naming the hook; and the re-check still reads "Soft blocked: no" and +"Powered: yes". If the log shows no btusb deregistration at all, the hook +still is not running and the directory is not the cause. + ** DOING [#B] Prepare for GitHub open-source release :PROPERTIES: :LAST_REVIEWED: 2026-08-17 -- cgit v1.2.3