fix(docking): the undock keyword is inert, not raced; escalate to reload
All checks were successful
Check / eval (push) Successful in 3m10s
All checks were successful
Check / eval (push) Successful in 3m10s
Round 7 FAILED: 5-6 consecutive unplugs on the dev box, the panel never came back. Round 6's retry could not have worked, because round 6's diagnosis was wrong — and so was the "phantom re-add" theory I brought to this session. With ZERO enabled outputs — panel disabled by the dock, external gone — Hyprland 0.55.4 accepts `hyprctl keyword monitor eDP-1,preferred,auto,1`, prints `ok`, exits 0, and never flushes it: the rule waits for a DRM event that is not coming. It is inert, not raced. Retrying it 25x/poll for 6 polls bought 30s of black screen and nothing else. What made this survive two rounds is worth more than the fix: every `transition=undock result=ok` in the round-6 journal was Bernardo plugging the cable back in because the screen was black. His hotplug flushed the queued rule and the next poll took the credit. Success was indistinguishable from the user working around the failure, so the logs confirmed whichever story we brought to them. Ten minutes of probing on hardware killed both. Probed live 2026-07-14 (dev box, cable out): keyword inert across 4s and 5s in two runs; `dispatch forcerendererreload` inert too; only `hyprctl reload` escapes — 99ms and 289ms. So: issue the keyword (enough whenever another output is still enabled, e.g. the menu's Dock mode), and escalate to reload only when `monitors` proves it inert. After a reload, re-assert the rule so a config that parks the panel off cannot undo the undock, and restore per-device keyboard layouts — a reload re-reads the config and drops the runtime `device[<name>]:kb_layout` an external board depends on. The menu's `enable` now proves itself against `monitors` too, instead of cheering for an exit code. Verified V3 (partial): the fixed transition driven through a real unplug — panel on, workspaces 1-3 home, 1.8s, `keyword=inert escalate=reload` -> `enable=via-reload` -> `result=ok`. V2: nix flake check --no-build; docking-ux + dock-audio; monitor-fallback.nix; shellcheck clean on display-transition. NOT proven, and queued as HARDWARE-QUEUE round 8: the watcher-driven path (exec-once + baked store path = relogin required, the round-5 trap) and repetition. The keyboard-restore path is untested — the dev box's keyboard hangs off the dock's hub, so it leaves with the cable; round 8 adds a check with a keyboard in the laptop. The VM harness still cannot reach any of this: QEMU aborts Hyprland if the last active output is deleted while the DRM output is disabled, which is the same zero-output degeneracy from the other side. New BACKLOG #114 (PROPOSED): tuigreet ignores per-device keyboard layouts — a VT has one keymap, so the greeter cannot honour `device[]:kb_layout`. Bernardo hit it logging out while docked; not a regression, a design gap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -32,36 +32,43 @@ 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 7 (undock panel restore, 2026-07-14)** —
|
||||
round 6 (AMD dev box, Bernardo) **passed on the plug side**: the dock
|
||||
docked by itself, audio went straight to the monitor, and the wallpaper
|
||||
painted on the external. One count failed: **unplugging the cable left
|
||||
the laptop panel black**, recoverable only by re-docking. The journal
|
||||
named the cause exactly — across three undocks, two logged
|
||||
`transition=undock internal=eDP-1 result=enable-timeout` and one
|
||||
`result=ok`, i.e. an intermittent race, not a logic error. Both halves
|
||||
are fixed in the commit carrying this entry: `hyprctl keyword monitor
|
||||
eDP-1,preferred,auto,1` is *accepted* (exit 0) while Hyprland is still
|
||||
tearing down the departing external and then silently dropped, so the
|
||||
transition now re-issues it on every poll for 5s rather than trusting
|
||||
one shot; and the watcher no longer treats a failed undock as final —
|
||||
the departure is queued and retried on the 1s tick (up to 6 attempts)
|
||||
instead of being marked handled with `|| true`, which is what turned one
|
||||
lost keyword into a panel dark until re-dock. **The VM harness cannot
|
||||
reach this** (`tools/monitor-fallback.nix`: QEMU's headless backend
|
||||
aborts Hyprland if the last active output is deleted while the DRM
|
||||
output is disabled, so the test must undock *before* removing DP-1 and
|
||||
never collides the two) — hardware is the only place it can be proven.
|
||||
- [ ] **Docking recovery round 8 (undock panel restore, 2026-07-14)** —
|
||||
round 7 **FAILED** on the AMD dev box (Bernardo, 5–6 consecutive
|
||||
unplugs, none recovered). Its whole diagnosis was wrong, and the way it
|
||||
was wrong is the lesson: round 6 read `result=enable-timeout` ×2 +
|
||||
`result=ok` ×1 as an intermittent race and retried the keyword. But the
|
||||
keyword is **inert, not raced** — with ZERO enabled outputs (panel
|
||||
disabled by the dock, external gone) Hyprland 0.55.4 accepts
|
||||
`keyword monitor` (prints `ok`, exits 0) and never flushes it until a
|
||||
DRM event arrives. Retrying an inert command 25×/poll for 6 polls just
|
||||
bought 30s of black screen. Every `result=ok` in that journal was
|
||||
**Bernardo plugging the cable back in** — his hotplug flushed the queued
|
||||
rule and the next poll took the credit. Probed live 2026-07-14: keyword
|
||||
inert across 4s and 5s in two runs, `dispatch forcerendererreload` also
|
||||
inert, and only `hyprctl reload` worked — 99ms and 289ms, cable out.
|
||||
The transition now escalates to `reload` when the keyword proves inert,
|
||||
re-asserts the rule, and restores per-device keyboard layouts (a reload
|
||||
drops runtime `device[…]:kb_layout` keywords).
|
||||
**Already proven on hardware:** one real unplug, invoking the fixed
|
||||
`nomarchy-display-transition undock eDP-1` directly with the watcher
|
||||
paused — panel on and workspaces 1–3 home in 1.8s, journal
|
||||
`keyword=inert escalate=reload` → `enable=via-reload` → `result=ok`.
|
||||
**What is NOT proven, and is this round:** the *watcher-driven* path
|
||||
(the running watcher calls the transition by baked store path, so it
|
||||
only picks the fix up at relogin — the round-5 trap), and repetition.
|
||||
**Re-check:** relogin (mandatory — see below), dock, then unplug the
|
||||
cable **at least five times**, since the old failure only hit ~2 of 3.
|
||||
**Pass:** the panel comes back every single time with workspaces intact,
|
||||
and `journalctl --user -t nomarchy-display-transition -t
|
||||
nomarchy-display-watch --since '-10 min'` shows a
|
||||
`transition=undock result=ok attempts=N` for each undock and **never**
|
||||
`result=gave-up`. `attempts=2` or more is the retry doing its job and is
|
||||
a pass; `gave-up` means the panel could not be enabled at all and is a
|
||||
different fault — capture the artifacts listed in round 4 before
|
||||
changing state.
|
||||
cable **at least five times**, plus once with the lid shut and once
|
||||
while an external keyboard is plugged into the *laptop* (not the dock's
|
||||
hub) — that last one is the only check on the keyboard-restore path.
|
||||
**Pass:** the panel comes back every time with workspaces intact, the
|
||||
external keyboard keeps its remembered layout, and `journalctl --user
|
||||
-t nomarchy-display-transition -t nomarchy-display-watch --since
|
||||
'-10 min'` shows `result=ok` for each undock with **no**
|
||||
`result=enable-failed`. `keyword=inert escalate=reload` on every undock
|
||||
is EXPECTED — that is the fix firing, not a fault. A `result=ok`
|
||||
**without** a preceding `keyword=inert` line means the keyword flushed
|
||||
on its own and the reload was never needed: interesting, worth
|
||||
reporting, still a pass.
|
||||
- [ ] **Headphone jack-follow (last open count from rounds 4–6,
|
||||
2026-07-14)** — rounds 4–6 opened five counts on the AMD dev box; four
|
||||
are now **confirmed fixed on hardware** by round 6 (Bernardo): wallpaper
|
||||
|
||||
Reference in New Issue
Block a user