fix(idle): #127 — input wakes the screen compositor-side; revert the clamshell skip
All checks were successful
Check / eval (push) Successful in 3m33s

The idle brick was never DPMS. Hyprland ships misc:key_press_enables_dpms
and misc:mouse_move_enables_dpms OFF, so hypridle's on-resume was the ONLY
caller of `dpms on` in the session — an idle daemon with the display held
hostage behind it. hypridle then deadlocks on an unfixed upstream bug
(hyprwm/hypridle#171, "Disconnected from pollfd id 1", open since 2025-09,
absent from 0.1.7 and main) and hangs WITHOUT exiting, so Restart=always
never fires and systemd still reports it active (running). Blank + deadlock
= a black seat no keypress can escape. That was the brick: two mundane bugs,
not one exotic DRM state. 19 disconnects in 11 days on the dev box, incl.
the incident day; the compositor is healthy through all of them.

Both options on, so the wake lives in the compositor where no daemon can
lose it — a dead hypridle now costs auto-lock, not the machine. The #127
clamshell DPMS-off skip (060bf52) is therefore reverted: idle blanks again
in every dock/lid state, and the 27" panels stop being held lit all night
under a static lock screen. #135 (an option to opt back in) is retired
unbuilt — there is nothing left to opt into.

TEST B's first run was invalid and nearly bought the wrong answer: it ran
`hyprctl dispatch dpms off` by hand, which no wake path watches, so "input
did not wake it" was guaranteed on any hardware. The undocked control
returning the SAME result — where the theory demanded a difference — is what
exposed it. Driven through hypridle instead, input wakes it in all three
configurations, including clamshell-docked on the sole live output.

Filed from the diagnosis: #146 (hypridle dies silently, systemd calls it
healthy — the surviving bug) and #147 (a re-login leaves session units dead;
graphical-session.target never re-enters, which is why Waybar already runs
from exec-once).

V3 on the incident hardware (AMD dev box, clamshell): hypridle deliberately
stopped, `dpms off` -> keypress woke it in 6s; the identical test before the
options stayed black the full 45s. V1: nix flake check, checks.option-docs,
checks.clamshell-logind, checks.docking-ux, checks.display-profiles; read the
emitted hyprland.conf/hypridle.conf rather than the source.

V3 pending: the fix is proven via runtime `hyprctl keyword`, not yet from our
own Nix — HARDWARE-QUEUE re-checks it after nomarchy-home + relogin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 18:48:22 +01:00
parent c32b51897e
commit a2151f424b
7 changed files with 187 additions and 238 deletions

View File

@@ -622,6 +622,10 @@ Design/decision records and a running log of shipped work (items marked
that could not run — two mundane bugs, not one exotic DRM state. The shipped
DPMS mitigation may therefore be treating the wrong cause; #127's TEST B is
what decides, and it is far safer now that an undock works again.
**It did decide, the same day: the hunch was right on both counts** — the
mitigation *was* treating the wrong cause and is now reverted, and the brick
*was* two mundane bugs (an ordinary blank + a wake path that had died). See
"#127 solved" below.
- ✓ **The #107 compat shim is pinned (#133, 2026-07-16):** `mkFlake` prefers
`state.json` and still accepts the legacy `theme-state.json`, because a
machine only migrates on its next menu write — but nothing evaluated a
@@ -723,19 +727,44 @@ Design/decision records and a running log of shipped work (items marked
`nomarchy-suspend` (hypridle + Power menu). LUKS: unlock session before
encrypted hibernate phase so resume is LUKS-only (not hyprlock twice).
Menu row self-gates on CanHibernate. V3: HARDWARE-QUEUE bag-carry test.
- **Clamshell idle DPMS (#127 mitigation):** after an idle brick (alive
machine, black external, undock no eDP, no usable Ctrl+Alt+F3), hypridle
**skips DPMS-off** when any laptop internal is present but not enabled.
Lock at 5 min unchanged; undocked still blanks at 10 min.
**Say clamshell, not "docked" (#136, settled 2026-07-16):** the gate is
"an internal exists and is switched off" — the lid shut — and Bernardo
confirms the incident was exactly that, laptop closed. Docked with the lid
**open** has every output enabled, falls straight through, and still blanks;
whether *that* can brick is untested and not claimed either way. The earlier
wording ("skip when docked") promised twice the coverage the code has, which
is how a recurrence gets misread as a regression.
Intentional DPMS-when-clamshell is LATER (BACKLOG) once wake is proven.
Tooling kept: `nomarchy-display-wake` / `nomarchy-display-dump`.
- ✓ **#127 solved — the idle brick was never DPMS (2026-07-16, AMD dev box):**
the clamshell DPMS-off skip (060bf52, and its #136 wording fix) is
**reverted**; idle blanks again in every dock/lid state. Hyprland ships
`misc:key_press_enables_dpms` and `misc:mouse_move_enables_dpms` **off**, and
nothing else in the session calls `dpms on` — so hypridle's `on-resume` was
the *only* thing that could un-blank a screen: an idle daemon with the
display held hostage behind it. hypridle then deadlocks on an unfixed
upstream bug (hyprwm/hypridle#171, "Disconnected from pollfd id 1", open
since 2025-09, absent from 0.1.7 *and* main) and hangs **without exiting**,
so `Restart=always` never fires and systemd still reports it
`active (running)`. Blank + deadlock = a black seat no keypress can escape.
That is the brick: two mundane bugs, not one exotic DRM state — the same
shape as the #100 latch above.
**Evidence, on the incident hardware.** With hypridle driving the blank,
input woke it in all three configurations — including clamshell-docked on the
sole live output (`nomarchy-display-wake done enabled=1 first=DP-2`), which
is the incident's exact geometry. So blanking-while-clamshell is innocent and
the gate guarded nothing. Then the decisive run: same box, still clamshell,
hypridle **deliberately stopped** (i.e. the brick condition manufactured on
purpose), `dpms off` → a keypress woke it in **6 s** with the two options on.
The identical test before them stayed black the full 45 s.
**Why the first TEST B said the opposite, and the lesson.** It ran `hyprctl
dispatch dpms off` **by hand**, which no wake path watches, so "input did not
wake it" was guaranteed on any hardware, in any dock state. The tell was the
undocked control returning the *same* result where the theory demanded a
different one. A test must put the mechanism under test inside the circuit —
this one measured a wake path that was never armed, and nearly bought a
permanent behaviour cost with the answer.
**Why the fix is structural.** The wake now lives in the compositor, where no
daemon can lose it; a dead hypridle costs auto-lock, not the machine. #135
(an option to opt back into DPMS-when-clamshell) is therefore **retired
unbuilt** — there is nothing left to opt into, and the 27" panels stop being
held lit all night under a static lock screen.
**Still open:** hypridle's silent death is its own bug (~2×/week on this box;
no auto-lock is a security cost even when the screen is recoverable), and the
incident's dead Ctrl+Alt+F3 remains unexplained — a known co-symptom upstream
(hyprwm/hypridle#145) but not accounted for here. Tooling kept:
`nomarchy-display-wake` / `nomarchy-display-dump`.
- ✓ **Generation prune (#128):** weekly `nomarchy-gen-prune` (system + HM):
delete only gens older than **14 days** that are also beyond the **3 most
recent past** gens (current always kept). Stock `nix.gc` no longer uses