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.
Brief black flash on every lock — beginLock() defers refreshBackground() via Qt.callLater while session lock timers start immediately
Reported by AlyKazani04 · filed Sep 15, 2026 · open at source
R-1213 is the earliest report of this defect — filed Aug 30, 2026, open upstream. This report (filed Sep 15, 2026) describes the same defect, so it is folded under it in the inbox.
Decided by agents · verified· Oct 9, 2026
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.4-1 (quattro branch)
What's wrong?
Every time the session locks (idle timeout or manual lock), there is a brief black flash — the WlSessionLockSurface appears with the solid Color.background color before the wallpaper image loads and the blur renders. The delay is a single frame or two, but noticeable.
This is not related to suspend/resume. It reproduces on every fresh lock.
Steps to reproduce:
1. Have the stock omarchy.lock plugin enabled (no third-party lock plugins)
2. Lock the session (omarchy system lock or idle timeout)
3. Observe: a brief black flash before the blurred wallpaper appears
Root cause:
In shell/plugins/lock/Service.qml, beginLock() defers refreshBackground() via Qt.callLater while queueSessionLock() starts its timers immediately:
function beginLock() {
// ...
lockRequested = true // root.locked = true → loadBackground = true
armBlankTimer()
logEvent("lock-requested")
queueSessionLock() // 500ms stabilize timer starts NOW
Qt.callLater(function() { // deferred to next event loop iteration
root.refreshBackground() // readlinkProc starts here
root.refreshFingerprintStatus()
})
return true
}The race:
1. lockRequested = true → root.locked becomes true → LockView.qml's loadBackground binding flips to true
2. queueSessionLock() starts sessionLockStabilizeTimer (500ms) → sessionLock.locked = true shortly after
3. The Image element in LockView.qml starts loading with whatever backgroundPath is currently set
4. Qt.callLater defers refreshBackground() to the next event loop — readlinkProc hasn't resolved the symlink yet
5. If backgroundPath is empty or stale, the Image loads nothing → black screen
6. Once readlinkProc completes and the Image decodes → wallpaper appears
In LockView.qml:
Image {
id: wallpaper
source: root.loadBackground ? root.fileUrl(root.backgroundPath) : ""
asynchronous: true
cache: false
// ...
}loadBackground is bound to root.locked, which is true the instant beginLock() runs. The Image tries to load before backgroundPath is resolved.
Note on lock-explorer plugin:
This race exists on both quattro and v4-0-4 (stable). The io.github.sirjul1337.lock-explorer plugin copies the same Qt.callLater pattern from the stock plugin. Users may notice the flash more after removing lock-explorer if the plugin's different rendering pipeline happened to mask the symptom.
Related issues:
- #7416 — related but different (wallpaper not reloading after suspend/resume, backgroundVersion cache-bust not firing on wake)
Suggested fix:
Move refreshBackground() before queueSessionLock() so backgroundPath is resolved before the session lock activates:
function beginLock() {
if (!passwordPamConfigured) {
logEvent("lock-denied: missing-pam")
return false
}
resetAuthenticationState()
lockRequested = true
armBlankTimer()
logEvent("lock-requested")
refreshBackground() // resolve path BEFORE arming the lock
refreshFingerprintStatus()
queueSessionLock() // now the 500ms timer runs with a valid backgroundPath
return true
}Or keep the Qt.callLater for fingerprint (which is slow) but resolve the background synchronously.
This issue was investigated and written by OpenCode (AI coding agent) on behalf of the user.
Related Images (@AlyKazani04 here):
Shows up for a split second.
<img width="4080" height="2296" alt="Image" src="https://github.com/user-attachments/assets/6bf288d5-9ede-4213-a278-2318a84d2719" />
After
<img width="4080" height="2296" alt="Image" src="https://github.com/user-attachments/assets/67b7edd3-7ade-4093-ab7c-956632b9d561" />
View raw text
## System details
Omarchy 4.0.4-1 (quattro branch)
## What's wrong?
Every time the session locks (idle timeout or manual lock), there is a brief black flash — the `WlSessionLockSurface` appears with the solid `Color.background` color before the wallpaper image loads and the blur renders. The delay is a single frame or two, but noticeable.
This is **not** related to suspend/resume. It reproduces on every fresh lock.
**Steps to reproduce:**
1. Have the stock `omarchy.lock` plugin enabled (no third-party lock plugins)
2. Lock the session (`omarchy system lock` or idle timeout)
3. Observe: a brief black flash before the blurred wallpaper appears
**Root cause:**
In `shell/plugins/lock/Service.qml`, `beginLock()` defers `refreshBackground()` via `Qt.callLater` while `queueSessionLock()` starts its timers immediately:
```qml
function beginLock() {
// ...
lockRequested = true // root.locked = true → loadBackground = true
armBlankTimer()
logEvent("lock-requested")
queueSessionLock() // 500ms stabilize timer starts NOW
Qt.callLater(function() { // deferred to next event loop iteration
root.refreshBackground() // readlinkProc starts here
root.refreshFingerprintStatus()
})
return true
}
```
The race:
1. `lockRequested = true` → `root.locked` becomes true → `LockView.qml`'s `loadBackground` binding flips to `true`
2. `queueSessionLock()` starts `sessionLockStabilizeTimer` (500ms) → `sessionLock.locked = true` shortly after
3. The `Image` element in `LockView.qml` starts loading with whatever `backgroundPath` is currently set
4. `Qt.callLater` defers `refreshBackground()` to the next event loop — `readlinkProc` hasn't resolved the symlink yet
5. If `backgroundPath` is empty or stale, the Image loads nothing → **black screen**
6. Once `readlinkProc` completes and the Image decodes → wallpaper appears
In `LockView.qml`:
```qml
Image {
id: wallpaper
source: root.loadBackground ? root.fileUrl(root.backgroundPath) : ""
asynchronous: true
cache: false
// ...
}
```
`loadBackground` is bound to `root.locked`, which is true the instant `beginLock()` runs. The Image tries to load before `backgroundPath` is resolved.
**Note on lock-explorer plugin:**
This race exists on both `quattro` and `v4-0-4` (stable). The `io.github.sirjul1337.lock-explorer` plugin copies the same `Qt.callLater` pattern from the stock plugin. Users may notice the flash more after removing lock-explorer if the plugin's different rendering pipeline happened to mask the symptom.
**Related issues:**
- #7416 — related but different (wallpaper not reloading after suspend/resume, `backgroundVersion` cache-bust not firing on wake)
**Suggested fix:**
Move `refreshBackground()` before `queueSessionLock()` so `backgroundPath` is resolved before the session lock activates:
```qml
function beginLock() {
if (!passwordPamConfigured) {
logEvent("lock-denied: missing-pam")
return false
}
resetAuthenticationState()
lockRequested = true
armBlankTimer()
logEvent("lock-requested")
refreshBackground() // resolve path BEFORE arming the lock
refreshFingerprintStatus()
queueSessionLock() // now the 500ms timer runs with a valid backgroundPath
return true
}
```
Or keep the `Qt.callLater` for fingerprint (which is slow) but resolve the background synchronously.
---
*This issue was investigated and written by OpenCode (AI coding agent) on behalf of the user.*
---
Related Images (@AlyKazani04 here):
Shows up for a split second.
<img width="4080" height="2296" alt="Image" src="https://github.com/user-attachments/assets/6bf288d5-9ede-4213-a278-2318a84d2719" />
After
<img width="4080" height="2296" alt="Image" src="https://github.com/user-attachments/assets/67b7edd3-7ade-4093-ab7c-956632b9d561" />- 6bf288d5-9ede-4213-a278-2318a84d2719
- 67b7edd3-7ade-4093-ab7c-956632b9d561
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
- Duplicate ofR-1213[Quattro] Lock wallpaper can show only its fallback color after resume· decided by agents · verified
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.