refactor(display): extract the shared display-transition + keyboard tools (#150)
All checks were successful
Check / eval (push) Successful in 4m29s

The full nomarchy-display-transition (dock/undock/enable — logging, the
lid-inhibitor gate, restore_keyboards, the failure dump) and the
nomarchy-keyboard-layout helper it calls move out of hyprland.nix into
leaf files (modules/home/display-transition.nix, keyboard-tool.nix),
imported by both hyprland.nix and idle.nix.

This kills the lossy ~22-line mini idle.nix carried under the same binary
name to dodge a circular import. The hypridle wake path (after_sleep /
DPMS on-resume) now runs the real undock — restore_keyboards after a
reload and the evidence dump on enable-failure — instead of a bare
keyword+reload, and the two copies can no longer drift.

Behaviour on the hyprland side is unchanged: the built
nomarchy-display-transition and nomarchy-keyboard-layout have
byte-identical store paths on HEAD vs this change (verbatim extraction).

Verify: all four files parse; home activationPackage + system toplevel
build; checks.docking-ux green (bash -n + safety-feature greps on the
extracted scripts). The tools/monitor-fallback.nix dock harness is red on
main already (the #148 reload-mid-dock assertion — identical failure on
clean HEAD; filed BACKLOG #154), so it could not gate this. The idle
wake-path behaviour change (full undock, incl. dock-intent clearing) is
V3 pending: on-hardware suspend/resume + zero-output rescue queued in
HARDWARE-QUEUE.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 19:17:56 +01:00
parent dbe07ea429
commit baf2cd2e13
7 changed files with 343 additions and 293 deletions

View File

@@ -175,24 +175,26 @@ If that count is zero over a few weeks post-linger, **close this unbuilt**. If i
is not, the upstream issue has sat ten months on vaxerski's "that will cause a
segfault no?" and a reproducer would be worth more than a local guard.
### 150. Extract the display-transition tool — idle.nix carries a lossy copy under the same name
### 154. `[watch]` `tools/monitor-fallback.nix` is red on `main` at the #148 reload-mid-dock assertion
Found by the 2026-07-17 structural audit. `modules/home/idle.nix:23-53` defines
`miniTransition`, a ~22-line `writeShellScriptBin` named
**`nomarchy-display-transition`** — the same binary name as the real ~175-line
tool in `modules/home/hyprland.nix:136-310` — implementing only
`undock|enable`, with none of the full tool's safety: no logging, no
lid-inhibitor gate, no `restore_keyboards`, no workspace moves, no
failure dump. The comment says why: "a mini transition avoids a circular
import on hyprland.nix". No PATH collision today (the mini is never installed;
it is baked by store path into hypridle's wake tool via `display-tools.nix`),
but nothing asserts the two stay behaviourally consistent, and this is the
subsystem where #100/#142/#148 all lived. Pitch: extract the full tool into
its own module file (e.g. `modules/home/display-transition.nix`) imported by
both hyprland.nix and idle.nix, delete the mini, re-run the
`tools/monitor-fallback.nix` harness + `checks.docking-ux` as the V2 gate.
Cost: a focused refactor of safety-critical code — deliberately NOT done as
hygiene drive-by; deserves its own iteration.
Found while verifying #150 (2026-07-20): the dock/undock VM harness fails at
the `enforce_dock_intent` step — after a lid-closed `hyprctl reload` it waits
15s (generated `<string>:75`) for the watcher to re-disable `Virtual-1` and
times out; the panel is never re-disabled and `action=re-dock` is never
logged. **Confirmed pre-existing:** a clean-HEAD worktree run
(fdf9790, before any #150 change) fails at the *identical* assertion, and the
#150 refactor is proven inert here (the built `nomarchy-display-transition` /
`nomarchy-keyboard-layout` have byte-identical store paths on HEAD vs the
#150 branch). The `dock` transition itself succeeds (`result=ok`, both
workspaces move, internal disabled) — only the post-reload re-dock invariant
fails. Likely a harness/environment issue (the `enforce_dock_intent` tick
depends on the watcher reading `settings.display.dockMode` from the in-flake
state, which may not be writable in this NixOS-test sandbox) rather than a
product regression — but it means the maintainer V2 dock harness is not a
usable gate until re-greened. Do first: reproduce, then check whether
`set_dock_intent` actually persists `dockMode=true` inside the VM (grep the
run journal for `dock-intent=…state-write-failed`); if the state write is the
gap, the fix is in the harness, not the watcher.
### 149. `[watch]` Waybar's exec-once workaround may be defending against nothing post-linger

View File

@@ -534,6 +534,21 @@ Everything else below stays open; order is convenience, not a gate.
bar, notifications, and clipboard history (SUPER+V) work. This is
the V3 close for the stale `graphical-session.target` /
`start-limit-hit` relogin breakage (BACKLOG #149 note).
- [ ] **#150 hypridle wake path now uses the FULL undock** — after pulling
the #150 commit + `nomarchy-home`: the hyprland-side transition/keyboard
tools are byte-identical (proven by store-path equality), so only the
hypridle wake behaviour changed. Two checks: **(a) suspend/resume while
docked** (lid closed, external on) — suspend, resume; pass = you land
back docked on the external with the panel still off and remembered
external-keyboard layouts intact (the wake now runs the full undock,
which `restore_keyboards` after any reload; the old mini did not). **(b)
zero-output rescue** — the #127 case (dock mode, external gone/black,
eDP disabled): pass = the internal panel comes back lit, workspaces move
to it, and `~/nomarchy-display-dump-*.txt` is written iff it stays dark.
Watch for a regression: the full undock clears dock-intent, so confirm a
*transient* zero-output blip on resume while genuinely still docked does
not leave you undocked with the laptop panel on (the external re-add
should re-dock via the watcher — verify it does).
## AMD dev box only
- [ ] **#118 smartd still runs where drives DO have SMART** (this commit) — the