fix(idle): skip DPMS-off when docked (#127 mitigation)
All checks were successful
Check / eval (push) Successful in 5m24s
All checks were successful
Check / eval (push) Successful in 5m24s
Blanking the only live output in dock mode led to a brick where wake and even VT switch failed. Skip hypridle's 10m dpms off when any laptop internal (eDP/LVDS/DSI) is present but not enabled; lock at 5m remains. Undocked still blanks. Document LATER revisit for intentional DPMS-when-docked once wake is proven. V1: nix flake check --no-build. V3: docked idle stays lit under lock.
This commit is contained in:
@@ -258,7 +258,7 @@ two tables below are split along exactly that line.
|
||||
| `nomarchy.batteryNotify.enable` | `true` | Low-battery toasts at the bar's thresholds — 25% low, 10% critical (stays up until dismissed); silent no-op on machines without a battery |
|
||||
| `nomarchy.dockAudio.enable` | `true` | On a fresh external-monitor plug, PipeWire/WirePlumber are reprobed after hardware settles and the highest-priority available HDMI/DP/USB sink becomes default, with a toast and journal result. A later manual speaker choice sticks until the next physical plug; unplug falls back to built-in. Manual route: System › Audio |
|
||||
| `nomarchy.firstBootWelcome.enable` | `true` | One dismissible “you're set” toast on the first session (SUPER+M / SUPER+T / SUPER+? + network pointer); marker is `settings.firstBootShown` in the flake checkout |
|
||||
| `nomarchy.idle.enable` | `true` | hyprlock + hypridle (idle lock 5 min, display off 10, suspend 15 min — battery-only; uses `nomarchy-suspend` so suspend-then-hibernate applies when enabled) |
|
||||
| `nomarchy.idle.enable` | `true` | hyprlock + hypridle (lock 5 min; display off 10 min **except when docked** — laptop internal present but disabled skips DPMS, #127; suspend 15 min battery-only via `nomarchy-suspend`) |
|
||||
| `nomarchy.idle.fingerprint` | `false` | Unlock the lock screen with a fingerprint as well as the password, and say so on the input field. Set it alongside `nomarchy.hardware.fingerprint.pam` in system.nix: hyprlock is configured from Home Manager, which cannot read the NixOS option — and hyprlock does **not** take a fingerprint through PAM at all (its PAM stack runs only on submit), so it uses its own fprintd backend that this switch turns on |
|
||||
| `nomarchy.yazi.enable` | `true` | yazi TUI file manager, themed + curated plugins |
|
||||
| `nomarchy.osd.enable` | `true` | swayosd on-screen display for volume/brightness/mute |
|
||||
|
||||
@@ -55,16 +55,21 @@ or (b) undock → `nomarchy-display-transition undock` re-enabling the
|
||||
panel. Both failed. `after_sleep_cmd` only does `hyprctl dispatch dpms on`
|
||||
and never re-enables a disabled internal.
|
||||
|
||||
**Progress 2026-07-15 (no-SSH path + recovery hardening):** undock/enable
|
||||
always end with `dpms on`; hypridle `on-resume` / `after_sleep` run
|
||||
`nomarchy-display-wake` (dpms + zero-output undock rescue + auto-dump);
|
||||
`nomarchy-display-dump` + SUPER+SHIFT+D + TTY (`Ctrl+Alt+F3`) so capture
|
||||
does not need SSH. V3 still needs a real docked idle repro.
|
||||
**Progress 2026-07-15:**
|
||||
- Recovery tooling: undock ends with `dpms on`; `nomarchy-display-wake` /
|
||||
`nomarchy-display-dump` (SUPER+SHIFT+D; TTY if it works).
|
||||
- **Mitigation (shipped):** do **not** DPMS-off when docked — if any
|
||||
laptop internal (eDP/LVDS/DSI) exists in `monitors all` but is not
|
||||
enabled, the 10 min listener skips blanking. Lock at 5 min still runs;
|
||||
undocked laptops still DPMS-off as before. Bernardo: Ctrl+Alt+F3 did
|
||||
not yield a usable TTY on the original brick, so prevention > dump path.
|
||||
- **Revisit later (LATER):** intentional DPMS-when-docked once wake is
|
||||
proven trustworthy (monitor power-save without a brick).
|
||||
|
||||
**Pass:** docked on AC, idle past lock + DPMS; external KB/mouse restores
|
||||
the external; if the external is unplugged while black, eDP comes back
|
||||
without reboot; journal shows display-watch undock `result=ok` when the
|
||||
cable leaves. Capture steps in HARDWARE-QUEUE (TTY dump preferred).
|
||||
**Pass (current mitigation):** docked on AC, idle past 10+ min → external
|
||||
stays lit under hyprlock (journal: `dpms-off skipped: docked`); undocked
|
||||
still blanks at 10 min and wakes on input. Full original pass (wake after
|
||||
DPMS-while-docked) deferred to the LATER revisit.
|
||||
|
||||
## NEXT
|
||||
|
||||
@@ -131,6 +136,14 @@ offline ISO's behaviour untouched (`checks.*` for the offline path stay green).
|
||||
|
||||
## LATER
|
||||
|
||||
- **DPMS when docked (revisit #127):** today we **skip** display blanking
|
||||
while any laptop internal is present-but-disabled (dock/clamshell), so
|
||||
idle only locks. That avoids blanking the sole external and the brick
|
||||
where wake/TTY failed (2026-07-15). Revisit when we want monitor
|
||||
power-save on dock again: re-enable DPMS-off for that mode only if
|
||||
`nomarchy-display-wake` (or better) reliably restores the external and
|
||||
undock-while-black restores eDP on the AMD dock setup — without
|
||||
depending on SSH. Until then, leave the skip in `modules/home/idle.nix`.
|
||||
- **Wallpapers artifact split** (ROADMAP § Faster switches — decided,
|
||||
deferred): pinned `Nomarchy-wallpapers` input so a state write stops
|
||||
re-copying 86 MB. Follow-on: pre-built theme variants if switches are
|
||||
|
||||
@@ -49,35 +49,20 @@ Everything else below stays open; order is convenience, not a gate.
|
||||
restores **only** the radios that were on before. If Wi-Fi was already
|
||||
off, it must stay off after disengage. Glyph must **not** appear when
|
||||
airplane is off.
|
||||
- [ ] **#127 docked idle blackout (AMD dev box, 2026-07-15)** —
|
||||
**Incident (FAILED, unsolicited):** laptop docked, idle a few minutes,
|
||||
screens went black ("sleep"). External keyboard/mouse did not restore
|
||||
any display; unplugging the external did not re-enable the laptop
|
||||
panel; Caps Lock LED still toggled (machine alive). Forced recovery
|
||||
was needed; a long Grok session died with the brick.
|
||||
**Important distinction:** on AC, hypridle is *not* supposed to
|
||||
suspend — only lock (5m) + `dpms off` (10m). Confirm next time with
|
||||
dump file or journal for `Suspending|PM: suspend` vs hypridle lines
|
||||
so we know DPMS-stuck vs real S3.
|
||||
**No SSH required** (post-#127 tooling): Caps Lock alive ⇒ machine is
|
||||
up. Prefer **local TTY** over SSH:
|
||||
1. `Ctrl+Alt+F3` → log in on the text console.
|
||||
2. `nomarchy-display-wake` — try recovery (dpms on + undock rescue).
|
||||
3. `nomarchy-display-dump` — writes `~/nomarchy-display-dump-*.txt`
|
||||
(monitors, journals, DRM status). Open that file after the seat
|
||||
is usable; no second machine needed.
|
||||
4. Optional while unlocked: `SUPER+SHIFT+D` runs the same dump.
|
||||
Auto: undock enable-fail and zero-output wake also dump under `~/`.
|
||||
**Repro (after `nomarchy-home` + relogin so hypridle/watcher pick up):**
|
||||
1. Dock, confirm dock mode (eDP disabled).
|
||||
2. Idle past 10 min **or** force: `loginctl lock-session` then
|
||||
`hyprctl dispatch dpms off`.
|
||||
3. External KB/mouse — external should wake (`nomarchy-display-wake`
|
||||
path). If not: TTY → dump → note.
|
||||
4. Unplug external while black — eDP should return (undock + `dpms on`).
|
||||
**Pass:** input wakes external while docked; undock while black restores
|
||||
eDP without reboot; dump files only appear on real failures.
|
||||
Related: docking recovery round 8 (awake undock) and BACKLOG #127.
|
||||
- [ ] **#127 docked idle — mitigation check (AMD dev box)** —
|
||||
**Context:** original brick = docked idle → black, no input wake, undock
|
||||
no eDP, Caps Lock alive; Ctrl+Alt+F3 gave no usable TTY. **Shipped
|
||||
mitigation:** skip DPMS-off while docked (internal present-but-disabled);
|
||||
lock at 5m still. Full DPMS-when-docked deferred (BACKLOG LATER).
|
||||
**After `nomarchy-home` + relogin:**
|
||||
1. Dock (eDP disabled in `hyprctl monitors all -j` / not in `monitors`).
|
||||
2. Idle past 10+ min (or wait for hypridle).
|
||||
3. **Pass mitigation:** external still shows hyprlock (not black power-save);
|
||||
`journalctl --user -t nomarchy-idle --since '-20 min'` has
|
||||
`dpms-off skipped: docked`.
|
||||
4. Undocked control: eDP only → at 10 min screen *does* blank; input wakes.
|
||||
Optional: `nomarchy-display-dump` / SUPER+SHIFT+D for other display faults.
|
||||
Related: docking round 8; LATER “DPMS when docked”.
|
||||
- [ ] **#96 battery-limit row on threshold-less firmware (Acer M5-481T)** —
|
||||
on the Acer (live or installed session with the commit carrying this
|
||||
entry): open System (`SUPER+CTRL+I`). **Pass:** a "Battery limit" row
|
||||
|
||||
@@ -19,6 +19,15 @@ Template:
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-15 — #127 skip DPMS-off when docked (mitigation)
|
||||
- **Task:** Bernardo: no usable TTY on brick; prefer prevent over dump.
|
||||
- **Did:** hypridle 10m listener skips `dpms off` when an internal
|
||||
(eDP/LVDS/DSI) is present-but-disabled; lock still at 5m. Documented
|
||||
LATER “DPMS when docked” revisit. Dump/wake tools remain.
|
||||
- **Verified:** V0/V1 flake check. V3: HARDWARE-QUEUE mitigation check.
|
||||
- **Pending:** human docked idle past 10m → external lit under lock.
|
||||
- **Next suggestion:** V3 docked idle, or other queue.
|
||||
|
||||
## 2026-07-15 — #127 no-SSH dump + docked idle wake harden
|
||||
- **Task:** Tackle docked idle blackout without needing SSH mid-brick.
|
||||
- **Did:** `nomarchy-display-dump` / `nomarchy-display-wake`; undock always
|
||||
|
||||
@@ -441,6 +441,12 @@ 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.
|
||||
- **Docked idle DPMS (#127 mitigation):** after a docked-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
|
||||
(dock/clamshell). Lock at 5 min unchanged; undocked still blanks at 10 min.
|
||||
Intentional DPMS-when-docked is LATER (BACKLOG) once wake is proven.
|
||||
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
|
||||
|
||||
@@ -20,24 +20,10 @@ let
|
||||
exit 1
|
||||
'';
|
||||
|
||||
# Same transition binary hyprland.nix puts on PATH — re-derived here so
|
||||
# hypridle can pin absolute store paths (thin PATH in the user unit).
|
||||
# Must stay in lockstep with modules/home/hyprland.nix's transition.
|
||||
# We only need undock/enable + dpms; call via PATH-installed name is
|
||||
# fragile, so wake embeds the transition from a minimal import chain:
|
||||
# dump+wake live in display-tools.nix; transition is the public name
|
||||
# on PATH after HM activation — wake script uses absolute path from
|
||||
# a local reimplementation of just the enable/dpms rescue when the
|
||||
# full transition package isn't injectable without circular imports.
|
||||
#
|
||||
# Practical approach: invoke `nomarchy-display-wake` from PATH after
|
||||
# activation; for the unit Exec lines use a wrapper that prefers the
|
||||
# store path of a wake script built with transition = null fallback
|
||||
# (hyprctl keyword + reload + dpms) matching undock's public contract.
|
||||
# Absolute store paths for hypridle (thin PATH). Wake reuses the shared
|
||||
# helper; a mini transition avoids a circular import on hyprland.nix.
|
||||
displayWake =
|
||||
let
|
||||
# Minimal undock-equivalent for idle's store path (no circular dep on
|
||||
# hyprland.nix). Prefer the real transition when on PATH at runtime.
|
||||
miniTransition = pkgs.writeShellScriptBin "nomarchy-display-transition" ''
|
||||
set -u
|
||||
case "''${1:-}" in
|
||||
@@ -65,6 +51,31 @@ let
|
||||
inherit pkgs;
|
||||
displayTransition = miniTransition;
|
||||
}).displayWakeTool;
|
||||
|
||||
# #127 mitigation (2026-07-15): blanking the *only* live output while
|
||||
# docked (eDP disabled) left a black seat that sometimes would not
|
||||
# recover (and even VT switch looked dead). Skip DPMS-off when any
|
||||
# laptop internal is present but not enabled. Lock still runs at 5 min.
|
||||
# Revisit: intentional DPMS-on-dock once wake is trustworthy — see
|
||||
# BACKLOG #127 and LATER "DPMS when docked".
|
||||
dpmsOff = pkgs.writeShellScript "nomarchy-dpms-off" ''
|
||||
set -euo pipefail
|
||||
jq=${pkgs.jq}/bin/jq
|
||||
internals=$(hyprctl monitors all -j 2>/dev/null \
|
||||
| $jq -r '.[] | select(.name | test("^(eDP|LVDS|DSI)")) | .name' \
|
||||
2>/dev/null || true)
|
||||
if [ -n "$internals" ]; then
|
||||
for m in $internals; do
|
||||
if ! hyprctl monitors -j 2>/dev/null \
|
||||
| $jq -e --arg m "$m" 'any(.[]; .name == $m)' >/dev/null 2>&1; then
|
||||
${pkgs.util-linux}/bin/logger -t nomarchy-idle -- \
|
||||
"dpms-off skipped: docked (internal $m not enabled)"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
hyprctl dispatch dpms off
|
||||
'';
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.idle.enable {
|
||||
@@ -168,8 +179,8 @@ in
|
||||
{ timeout = 300; on-timeout = "loginctl lock-session"; }
|
||||
{
|
||||
timeout = 600;
|
||||
on-timeout = "hyprctl dispatch dpms off";
|
||||
# Same rescue path as after_sleep (#127).
|
||||
# Docked: skip blanking sole output (#127). Undocked: DPMS off.
|
||||
on-timeout = "${dpmsOff}";
|
||||
on-resume = "${lib.getExe displayWake}";
|
||||
}
|
||||
# Suspend only on battery, and sooner than the old fixed 30 min
|
||||
|
||||
Reference in New Issue
Block a user