fix(docking): don't lose the hotplug event; one prompt per keyboard; follow the jack
All checks were successful
Check / eval (push) Successful in 3m31s

Four failures from Bernardo's round-4 dock pass on the AMD dev box, plus a
headphone regression, tracked to three causes.

The display watcher ran socat with `-T 1`, which closes Hyprland's IPC
socket after one second of *inactivity*. A dock is normally plugged into an
idle desktop, so the socket was almost always mid-reconnect at that moment
and `monitoradded` was lost outright — and the wallpaper repaint, the
docking profile, and the dock-audio reprobe all hung off that single event.
The reconnect path recovered only the lid inhibitor, so the dock stayed
half-configured until something else poked the watcher.

Make the connection long-lived and take the periodic tick from a 1s `read`
timeout instead, then let the *output set* — not the event — decide: a new
`reconcile` diffs it and is called on both ticks and monitor events, so an
event now only makes the reaction instant rather than necessary. A newly
present external output is as unambiguous a physical plug as the event was,
so it may still override a manual sink choice. Wallpaper paints are retried
over the first few seconds because awww registers an output on its own
schedule, not the compositor's.

Hyprland calls every key-capable evdev node a "keyboard": the lid and power
buttons, a monitor's control channel, and each extra HID collection of a
real keyboard. One dock with one keyboard asked for a layout four times.
udev already draws the distinction properly, so take ID_INPUT_KEYBOARD from
it, map the names into Hyprland's spelling, and ask once per physical
keyboard — applying the answer to every node it brought with it.

Finally, a sink WirePlumber has been told to prefer is stored as the
configured default and outranks every priority rule. On UCM cards the
headphones are a sink of their own rather than a route, so once anything
pinned a sink (this feature on a dock plug, or the user in the Audio menu),
plugging headphones in could no longer take the audio back. The `watch`
loop already subscribed to exactly the right events with an empty handler;
finish it. Unplug needs no undo — the pin goes stale and WirePlumber falls
back by priority on its own, to the dock when docked and the speakers
otherwise.

Verified V2: checks.docking-ux and checks.dock-audio pass with new guards
against each regression; the keyboard filter and both sink selectors run
against the dev box's real devices and sink names. The hotplug paths need
hardware — queued as docking round 5.

Also queues #107, renaming theme.json now that it holds the system state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 10:24:48 +01:00
parent 9550d2be5e
commit e0da1ea40f
5 changed files with 263 additions and 87 deletions

View File

@@ -32,6 +32,28 @@ the **T14s** (webcam case).
nomarchy-battery-charge-limit.service` stays false, `Result=success`,
BAT0's `charge_control_end_threshold` still matches the limit, and the
journal has no new `start-limit-hit`/`Failed with result` lines.
- [ ] **Docking recovery round 5 (dock/keyboard/audio hotplug, 2026-07-14)**
— round 4 was run on the AMD dev box and **failed on four counts**
(Bernardo): no wallpaper on the external monitor, no automatic dock
mode (System Display had to be used by hand), audio staying on the
laptop speakers while docked, and one dock + one external keyboard
asking for a layout **four times**. Separately, plugging headphones had
stopped moving audio to them. Causes and fixes in the commit carrying
this entry: the display watcher's `socat -T 1` closed Hyprland's IPC
socket after a second of idle, so a dock plugged into an idle desktop
lost `monitoradded` in the reconnect gap (wallpaper + dock mode + audio
all hang off that one event); Hyprland lists every key-capable evdev
node as a "keyboard"; and a pinned `default.configured.audio.sink`
outranks the priority rules, which kills jack-follow on UCM cards where
the headphones are their own sink. **Re-run round 4 below in full**,
plus: (a) leave the desktop untouched for ~30s, then plug the dock —
wallpaper, dock mode, and audio must all follow with no manual step;
(b) the external keyboard must prompt **exactly once**, and never for
the monitor or the lid/power buttons; (c) docked and undocked, plug and
unplug headphones — audio must move to them and back each time.
`journalctl --user -t nomarchy-display-watch` should show
`outputs-changed added=…`, and `-t nomarchy-dock-audio`
`trigger=jack selected=…` on a headphone plug.
- [ ] **Docking recovery round 4 (#100, closed-lid BenQ sequence)** — after
updating to the commit carrying this entry, run `nomarchy-home` and
relogin. With the lid open, put visible windows on at least workspaces