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

@@ -95,6 +95,22 @@ pre-existing ISO-pinning gap.
## NEXT
### 107. Rename `theme.json` to reflect that it is the system state
The state file long ago stopped being about themes: it carries night-light,
keyboard memory, display resolution and profiles, auto-commit, services and
more, so `theme.json` now misnames its own contents and misleads anyone
reading the flake. Rename it to `state.json` (Bernardo, 2026-07-14 —
`system.json` is the alternative; pick one and use it everywhere), and carry
the `nomarchy-theme-sync` tool name along with it.
Standalone task — do not fold it into a feature. Ships with a compatibility
shim that keeps reading an existing `theme.json` so downstream checkouts do
not break on a pull, plus a migration note. Pass = a fresh install and an
existing downstream checkout both work, every in-repo reference (modules,
tools, template, docs) uses the new name, and the shim is documented with the
release it can be dropped in.
### 103. Live ISO baseline desktop applications
Make Chromium and Firefox, `libreoffice-fresh`, GNOME Text Editor, Amberol, and