From 64f7379982b95ff1fe4cd8a52339b9c1d0cb4001 Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Wed, 15 Jul 2026 18:25:47 +0100 Subject: [PATCH] =?UTF-8?q?docs(agent):=20file=20#135/#136=20=E2=80=94=20g?= =?UTF-8?q?ive=20the=20#127=20DPMS=20mitigation=20an=20owner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewing 060bf52 at Bernardo's request. The call is right — the failure mode is a brick (no wake, no VT, hard power-off with the btrfs risk that carries), so prevent-over-recover beats a lit panel. Three things it leaves open, now tracked instead of remembered: #135 — the mitigation is hardcoded policy with no way back. Docked externals never blank and hyprlock has no timeout, so they stay lit indefinitely: ~60-100W nightly and OLED burn-in from a near-static lock screen. Add settings.idle.dpmsWhenDocked (default false = today's behaviour), mostly so the mitigation has a named surface to DELETE once wake is proven, rather than a LATER note that quietly becomes the product. Ordered after the hardware test: if the mitigation is withdrawn, the key never exists. #136 — the gate is clamshell, not "docked". It skips only when an internal is present-but-not-enabled; lid-open docked still falls through to dpms off. Commit body, BACKLOG and journal all claim the broader "docked". Either the scope is deliberate (fix the wording) or the mitigation misses half the docked cases. Bernardo's call; the hardware test settles it. Also recorded in #127 the caveat that outranks both: the fix is a cure for an UNCONFIRMED cause. If DPMS-off is not the trigger, we hold the cost and still have the brick. No code change — #127 stays [blocked:hw] pending the hardware run. --- agent/BACKLOG.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index 8cb1619..fed1ab4 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -64,7 +64,16 @@ and never re-enables a disabled internal. 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). + proven trustworthy (monitor power-save without a brick). Tracked as + **#135** (state key + the surface to delete this by) and **#136** (the + gate is clamshell, not "docked" — lid-open docked still blanks). Both + are downstream of the hardware test below. +- **Caveat the test must settle:** the mitigation is a cure for an + **unconfirmed cause**. "Blanking the only live output caused the brick" + is inference from one incident, shipped at V1. If DPMS-off is not the + trigger, we are paying a permanent behaviour cost (docked externals never + sleep) and the brick is still live — so confirming the cause outranks + #135/#136. **Pass (current mitigation):** docked on AC, idle past 10+ min → external stays lit under hyprlock (journal: `dpms-off skipped: docked`); undocked @@ -73,6 +82,45 @@ DPMS-while-docked) deferred to the LATER revisit. ## NEXT +### 135. Give the #127 DPMS mitigation a state key (and a way back) + +The shipped mitigation is hardcoded policy: docked (clamshell) externals now +**never** blank, and hyprlock has no timeout of its own, so they stay lit +indefinitely. Two real costs land on the user — a couple of 27" panels at +~60–100W all night, and **OLED burn-in** from a near-static lock screen held +for hours. Today there is no way to opt back in, which also breaks the +in-flake-state rule that settings are menu-writable. + +Add `settings.idle.dpmsWhenDocked` (default **false** = today's safe +behaviour), read by `modules/home/idle.nix`'s `dpmsOff` gate, with a +Preferences row. The real point is not the option: it gives the mitigation a +**named surface to delete** once wake is proven, instead of an unowned LATER +note that quietly becomes the product. Whoever removes the mitigation removes +the key in the same commit. + +**Order:** after the #127 hardware test. If DPMS-off turns out not to be the +trigger, the mitigation is reverted wholesale and this key never exists — +building it first risks shipping an option for a policy we withdraw. + +### 136. `[human]` #127's gate is clamshell, not "docked" + +The code skips DPMS-off when a laptop internal is present in `monitors all` +but absent from the enabled list — i.e. **clamshell**. Commit 060bf52, the +#127 entry and the journal all say "docked", which is broader: **docked with +the lid open** (internal + externals all enabled) falls straight through to +`hyprctl dispatch dpms off` and still blanks. So either + +- the narrow scope is deliberate (the brick needs the internal disabled, and + lid-open docked is genuinely safe) → fix the wording in 060bf52's + descendants so the docs stop claiming more than the code does; or +- it is an accidental gap → the mitigation misses half the docked cases and + the brick can still fire with the lid open. + +Bernardo's call, and the #127 hardware test is what settles it: if the brick +reproduces lid-open, this is a gap. Cheap either way — one `jq` predicate or +one docs sweep. Filed because a doc that overclaims its own fix is how the +next session mis-diagnoses the recurrence. + ### 129. Permanent guard for the GTK button-colour trap (#98 follow-up) The #98 regression (destructive-action at 1.03:1, invisible) was caught only