fix(docking): make clamshell hotplug safe and discoverable
All checks were successful
Check / eval (push) Successful in 3m32s

Real dock QA exposed pointer-bound menus, an absent default rescue watcher, the unsafe zero-output panel-off path, missing keyboard/audio hotplug coverage, and unpainted new outputs.

Route Rofi to the focused output; replace panel disable with safe workspace migration; always run and reconnect the display watcher and repaint hotplugged outputs; expose a default per-device keyboard picker; handle audio card availability transitions.

Verified: V1 — nix flake check --no-build; checks.docking-ux real Home Manager artifact build; option-docs/template-sot; Nix parse, py_compile, and git diff --check. V2 unavailable: no readable KVM. V3 pending in agent/HARDWARE-QUEUE.md.
This commit is contained in:
2026-07-13 11:53:01 +01:00
parent 16846786e2
commit 7ebfab4bd4
15 changed files with 357 additions and 171 deletions

View File

@@ -11,54 +11,27 @@ the **T14s** (webcam case).
## Any machine (dev box is fine)
- [ ] **#86 clamshell lid + external display** — V2 asserts
`HandleLidSwitchDocked=ignore` in logind.conf. On a laptop with a
real external monitor: open a session, plug external, close lid —
machine must **stay awake** (no suspend); external panel remains
usable (or wakes with keyboard if DPMS). Unplug external, close lid
— should suspend as usual. Optional: with a docked display-profile
(`eDP-1` disable), confirm clamshell layout still looks right after
lid close. Pass = no surprise suspend when docked.
- [ ] **#87 round 2: dock audio auto-follow (watcher)** — round 1 result
(Newton, 2026-07-12): audio stayed on speakers when docking; the
running generation had no `90-nomarchy-dock-audio` rules yet, and
live testing showed the priority rules alone can never win anyway —
WirePlumber's stored default (`default-nodes` state, written by any
past explicit pick) outranks `priority.session`, and this machine
(like most) has one. Fix shipped: the `nomarchy-dock-audio` user
service `pactl set-default-sink`s dock-class sinks on hotplug;
EasyEffects follows the default (verified live: EE's output links
moved to a fake dock-named null sink mid-playback). Retest after
pull+rebuild+home on ≥ this rev: play audio, plug the dock →
toast "Audio → <monitor/dock>" and sound moves with EE effects
still active; unplug → sound returns to speakers; while docked,
picking speakers in the Audio menu sticks until the next replug.
If it does NOT switch, capture for diagnosis: `pactl subscribe`
output during the plug, `pactl --format=json list sinks` while
docked (sink names may not match the dock regexes, or the sink
node may pre-exist and only flip route availability — the watcher
keys on new-sink events).
- [ ] **Docked display/audio menu rows** (2026-07-12) — with a real
external monitor: Display menu shows "Laptop screen off ·
everything → <ext>" (only with >1 active output), "Screen on ·
<name>" after a disable, "Move workspace · → next monitor", "Swap
workspaces" (exactly 2 outputs). Laptop-off must move its
workspaces to the external; Screen on restores it (preferred/auto —
declared scale/pos return at the next relogin/switch). Audio menu
shows "Send output → <dock sink>" when one exists and isn't
default; picking it moves output + toasts. Pass = rows appear/act
as described, and none of them show on a single-display session.
Also — **run this one with nothing important open**: with the
laptop screen off via the menu, physically unplug the dock. The
panel should re-enable within ~2s (`rescue_blackout` in the
display watcher). Known risk from the VM harness
(tools/monitor-fallback.nix): on Hyprland 0.55.4 the zero-output
state itself can crash the compositor faster than any rescue
(softGL VM: 4/5 runs; control with the panel active survives
always) — a crash on real DRM ends the session to the greeter on
the re-lit panel. If that happens on hardware, the "Laptop screen
off" row needs a rework (mirror instead of disable, or drop until
a Hyprland bump) — file it as a NOW bug with the coredump.
- [ ] **Docking correction round 3 (2026-07-13 hardware-QA follow-up)**
prior result: lid-close stayed awake, but SUPER+M rendered on the
hidden laptop workspace; the keyboard never prompted; audio stayed
on speakers; the old laptop-off action lost some applications and
abrupt undock left eDP black. After updating to the commit carrying
this entry and rebuilding Home Manager, start with the laptop open
and play audio. Close the lid and plug the monitor/keyboard: SUPER+M
must render on the external focused workspace; the new keyboard must
ask for a searchable XKB layout (or set/change it at System
Keyboard); audio must toast and move to the monitor. System Audio
Output device remains the manual fallback; the current wallpaper must
cover the external output/workspaces within ~2s. Open Display and choose
**Dock mode**: all eDP workspaces/windows move intact to the external
and focus follows; no terminal/application exits. Yank the cable: the
internal panel is already the logical fallback, lights immediately,
and the moved workspaces/windows survive. Replug then manually choose
speakers: volume/mute changes must not force the monitor again; only a
fresh replug should. If audio still misses, capture `pactl subscribe`
during plug plus `pactl --format=json list sinks` while docked. If the
menu is still misplaced, capture `hyprctl monitors -j` immediately
before SUPER+M (the `.focused` field is the discriminator).
- [ ] **Parallel fingerprint-or-password on the real reader** (AMD dev
box, 2026-07-12) — with a finger enrolled and
`fingerprint.pam = true` (parallel is the default): `sudo -k true`