Proof Portal
Omarchy
ProbeLabs65 findings · 95 requirementsA proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.
Lock: monitor that drops HPD after DPMS-off comes back lit and never re-blanks (blank timer is one-shot)
Reported by bmcswee · filed Aug 27, 2026 · open at source
At a glance
- 1 · What is claimed?
- Only the report text below — no validator has restated it as checkable claims yet.
- 2 · What does it affect?
- 3 · Is it reproducible?
- No validation has been run yet.
- 4 · What remains unclear?
- Not validated yet: no claims, no reproducer.
- 5 · What happens next?
- Decided by agents and verified by a second, independent agent — see the decision.
Original report
System details
- Omarchy 4.0.1-1 · Hyprland 0.56.2 (
efb50993780079460b0cbed1363e2166a2de1d9f) · quickshell 0.3.1-1 · Arch Linux, kernel 7.1.9-arch1-2 - ThinkPad T14 Gen 1 (20UD003LUS), AMD Ryzen 5 PRO 4650U, Renoir iGPU (amdgpu, DCN 2.1)
eDP-1Lenovo 1920x1080 ·DP-1LG UltraGear 2560x1440 ·HDMI-A-1ViewSonic VX2758-Series 2560x1440- Docked, three monitors. Direct connections, no MST.
What's wrong?
After locking, one external monitor blanks correctly with the other two, then
**turns itself back on ~19 seconds later and stays lit showing the lock screen
indefinitely**. The other two stay dark.
This is not one of the existing "display never blanks" reports (#7456,
#7652) — the blank works correctly here. Every output goes dark on schedule at
lock+5s. The problem is that this monitor leaves and comes back, and by
then the only blank that will ever run has already run.
Root cause
Three things compound:
- The panel drops hotplug-detect ~12s after DPMS-off. The ViewSonic
deep-sleeps once it loses signal, de-asserts HPD, then re-scans its inputs
~1s later. This is panel firmware behavior — the LG on DP-1 does not do it,
which is why only one monitor is affected.
2. Hyprland re-adds the returning output enabled and powered on, applies the
monitors.lua rule, and the session-lock surface paints onto it.
3. The lock blank is a one-shot. idleBlankTimer
(shell/plugins/lock/Service.qml) fires once at lock+5s and is only ever
re-armed by runWake() or an authenticatingPassword transition. Neither
happens here — no one touched the machine. So nothing re-blanks the output
that just came back.
onMonitorsChanged in the same file already reacts to output changes by
re-requesting the session lock (so the lock surface is correctly painted onto
the returning monitor) — it just never re-arms the blank timer alongside it.
Evidence
Hyprland event socket + polling hyprctl monitors all -j and/sys/class/drm/card1-*/status through a real idle lock:
08:22:08 lock taken all three monitors On
08:22:13 +5s blank fires all three dpms=false, drm disa/Off
08:22:25 +17s monitorremoved>>HDMI-A-1 drm status → disconnected
08:22:27 +19s monitoradded>>HDMI-A-1 → conn/enab/On, dpmsStatus=true
08:23:00 still lit, until manual unlockCorresponding journal for the same lock:
omarchy lock ...Z lock-requested
omarchy lock ...Z lock-pending: screen-stabilizing
omarchy lock ...Z secure=trueNote the blank itself is fine — hl.dsp.dpms({ action = "disable" }) correctly
took all three outputs to dpmsStatus=false and enabled=disabled. On this
system the table form works, so this is a distinct bug from #7456.
Steps to reproduce
Needs a monitor that deep-sleeps and drops HPD on signal loss (a cheap HDMI
panel with input auto-scan is the usual culprit).
- Dock with at least one such external monitor.
- Lock (
omarchy system lock) and do not touch anything. - All outputs blank at +5s, as expected.
- Watch
hyprctl monitors all -j— around +17s the panel drops off and is
re-added, powered on, and stays lit.
A short observation window will miss this entirely: the HPD drop is ~12s after
the blank, so anything under ~15s of watching looks like a clean pass.
Why re-asserting DPMS is not the fix
I prototyped that first and measured it. Re-blanking on monitoradded does
not converge:
- On re-add it took 9 dispatches over ~4 seconds before DPMS-off would
stick — Hyprland keeps re-lighting the output while it is still configuring it.
- Then the panel re-sleeps and returns ~14s later, and the cycle repeats:
26 re-blanks in 75 seconds.
That trades a permanently-lit panel for one that visibly flashes on every ~14
seconds all night. A naive "re-arm the blank timer on monitorsChanged" fix would
land exactly here, so it is worth knowing before picking an approach.
What does work
Disabling the output for the duration of the lock, rather than blanking it.
Hyprland applies the disabled = true rule to the returning output, so it never
re-lights:
08:26:50 disabled=true output dark
08:27:02 (output absent) drm=disconnected panel deep-sleeps, drops HPD
08:27:03 disabled=true drm=connected re-added STILL DISABLED, not lit
...dark for the remaining 64s, one HPD blip total, no flapping
08:28:07 restored cleanly on unlockOne HPD transition instead of a continuous flap, and the panel genuinely powers
off — which is the user-visible behavior people expect from a locked machine.
Suggested fix
Some way for the lock blank to survive an output that leaves and returns. Rough
options, in the order I'd weigh them:
- **Re-blank on
monitorsChangedwhile locked, but idempotently and with
backoff** — the existing handler is already there. This needs the retry
behavior above accounted for, or it will thrash.
2. Disable outputs for the lock duration instead of DPMS-off. Strictly more
robust for this class of panel, but heavier: it destroys and recreates
wl_output globals, which on Hyprland 0.56.2 is the path implicated in
#7853, and it migrates workspaces.
3. At minimum, a `logEvent` in `runBlank()` — #7652 asks for this too. Right
now there is no journal record of whether a blank ran, which made this
materially harder to diagnose.
Workaround
A user-space watcher that disables the affected output for the duration of the
lock and restores it on unlock. Matching by EDID desc: rather than connector
name keeps it stable across re-enumeration.
Related
- #7456 — also "locked screens never power off", but a different cause (dispatch
form ignored). The table form works on this system.
- #7652 — also "display never blanks", but blank never runs at all there; here it
runs correctly and is defeated afterwards.
- #7853 — relevant to option 2 above: specific-output disabled = true plus
hyprctl reload on 0.56.2 can destroy a wl_output global while clients are
still binding it.
- #7328 — the inverse HPD problem: nothing re-probes when a dock never re-asserts.
Diagnostics
omarchy-debug --no-sudo --print: https://logs.omarchy.org/koIwlR
(No screen capture attached — the bug is a physical panel remaining powered
while the session is locked. A screenshot would just show the normal lock
screen; the event-socket and DRM traces above are the meaningful evidence.)
View raw text
## System details
- Omarchy 4.0.1-1 · Hyprland 0.56.2 (`efb50993780079460b0cbed1363e2166a2de1d9f`) · quickshell 0.3.1-1 · Arch Linux, kernel 7.1.9-arch1-2
- ThinkPad T14 Gen 1 (20UD003LUS), AMD Ryzen 5 PRO 4650U, Renoir iGPU (amdgpu, DCN 2.1)
- `eDP-1` Lenovo 1920x1080 · `DP-1` LG UltraGear 2560x1440 · `HDMI-A-1` ViewSonic VX2758-Series 2560x1440
- Docked, three monitors. Direct connections, no MST.
## What's wrong?
After locking, one external monitor blanks correctly with the other two, then
**turns itself back on ~19 seconds later and stays lit showing the lock screen
indefinitely**. The other two stay dark.
This is *not* one of the existing "display never blanks" reports (#7456,
#7652) — the blank works correctly here. Every output goes dark on schedule at
lock+5s. The problem is that this monitor **leaves and comes back**, and by
then the only blank that will ever run has already run.
## Root cause
Three things compound:
1. **The panel drops hotplug-detect ~12s after DPMS-off.** The ViewSonic
deep-sleeps once it loses signal, de-asserts HPD, then re-scans its inputs
~1s later. This is panel firmware behavior — the LG on `DP-1` does not do it,
which is why only one monitor is affected.
2. **Hyprland re-adds the returning output enabled and powered on**, applies the
`monitors.lua` rule, and the session-lock surface paints onto it.
3. **The lock blank is a one-shot.** `idleBlankTimer`
(`shell/plugins/lock/Service.qml`) fires once at lock+5s and is only ever
re-armed by `runWake()` or an `authenticatingPassword` transition. Neither
happens here — no one touched the machine. So nothing re-blanks the output
that just came back.
`onMonitorsChanged` in the same file already reacts to output changes by
re-requesting the session lock (so the lock surface *is* correctly painted onto
the returning monitor) — it just never re-arms the blank timer alongside it.
## Evidence
Hyprland event socket + polling `hyprctl monitors all -j` and
`/sys/class/drm/card1-*/status` through a real idle lock:
```
08:22:08 lock taken all three monitors On
08:22:13 +5s blank fires all three dpms=false, drm disa/Off
08:22:25 +17s monitorremoved>>HDMI-A-1 drm status → disconnected
08:22:27 +19s monitoradded>>HDMI-A-1 → conn/enab/On, dpmsStatus=true
08:23:00 still lit, until manual unlock
```
Corresponding journal for the same lock:
```
omarchy lock ...Z lock-requested
omarchy lock ...Z lock-pending: screen-stabilizing
omarchy lock ...Z secure=true
```
Note the blank itself is fine — `hl.dsp.dpms({ action = "disable" })` correctly
took all three outputs to `dpmsStatus=false` and `enabled=disabled`. On this
system the table form works, so this is a distinct bug from #7456.
## Steps to reproduce
Needs a monitor that deep-sleeps and drops HPD on signal loss (a cheap HDMI
panel with input auto-scan is the usual culprit).
1. Dock with at least one such external monitor.
2. Lock (`omarchy system lock`) and do not touch anything.
3. All outputs blank at +5s, as expected.
4. Watch `hyprctl monitors all -j` — around +17s the panel drops off and is
re-added, powered on, and stays lit.
A short observation window will miss this entirely: the HPD drop is ~12s after
the blank, so anything under ~15s of watching looks like a clean pass.
## Why re-asserting DPMS is not the fix
I prototyped that first and measured it. Re-blanking on `monitoradded` does
**not** converge:
- On re-add it took **9 dispatches over ~4 seconds** before DPMS-off would
stick — Hyprland keeps re-lighting the output while it is still configuring it.
- Then the panel re-sleeps and returns ~14s later, and the cycle repeats:
**26 re-blanks in 75 seconds.**
That trades a permanently-lit panel for one that visibly flashes on every ~14
seconds all night. A naive "re-arm the blank timer on monitorsChanged" fix would
land exactly here, so it is worth knowing before picking an approach.
## What does work
Disabling the output for the duration of the lock, rather than blanking it.
Hyprland applies the `disabled = true` rule to the returning output, so it never
re-lights:
```
08:26:50 disabled=true output dark
08:27:02 (output absent) drm=disconnected panel deep-sleeps, drops HPD
08:27:03 disabled=true drm=connected re-added STILL DISABLED, not lit
...dark for the remaining 64s, one HPD blip total, no flapping
08:28:07 restored cleanly on unlock
```
One HPD transition instead of a continuous flap, and the panel genuinely powers
off — which is the user-visible behavior people expect from a locked machine.
## Suggested fix
Some way for the lock blank to survive an output that leaves and returns. Rough
options, in the order I'd weigh them:
1. **Re-blank on `monitorsChanged` while locked, but idempotently and with
backoff** — the existing handler is already there. This needs the retry
behavior above accounted for, or it will thrash.
2. **Disable outputs for the lock duration** instead of DPMS-off. Strictly more
robust for this class of panel, but heavier: it destroys and recreates
`wl_output` globals, which on Hyprland 0.56.2 is the path implicated in
#7853, and it migrates workspaces.
3. At minimum, **a `logEvent` in `runBlank()`** — #7652 asks for this too. Right
now there is no journal record of whether a blank ran, which made this
materially harder to diagnose.
## Workaround
A user-space watcher that disables the affected output for the duration of the
lock and restores it on unlock. Matching by EDID `desc:` rather than connector
name keeps it stable across re-enumeration.
## Related
- #7456 — also "locked screens never power off", but a different cause (dispatch
form ignored). The table form works on this system.
- #7652 — also "display never blanks", but blank never runs at all there; here it
runs correctly and is defeated afterwards.
- #7853 — relevant to option 2 above: specific-output `disabled = true` plus
`hyprctl reload` on 0.56.2 can destroy a `wl_output` global while clients are
still binding it.
- #7328 — the inverse HPD problem: nothing re-probes when a dock never re-asserts.
## Diagnostics
`omarchy-debug --no-sudo --print`: https://logs.omarchy.org/koIwlR
(No screen capture attached — the bug is a physical panel remaining powered
while the session is locked. A screenshot would just show the normal lock
screen; the event-socket and DRM traces above are the meaningful evidence.)
Validation
Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.
Linked
- Known issueScreen add/remove while locked clears the blank intent and never re-arms the idle blank timer KI-LOCK-SCREENS-CHANGE-BLANK-LOST· decided by agents · verified
- Related PRpr/10343· confirmed
- Related PRpr/10130· confirmed
- Related PRpr/8581· confirmed
- Fixed bypr/13129· confirmed
Decision
Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.
- DuplicateScreen add/remove while locked clears the blank intent and never re-arms the idle blank timer KI-LOCK-SCREENS-CHANGE-BLANK-LOSTDecided by agents · verified · 2026-10-08 21:39 UTC