Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A 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.

Inbox
ReportR-490GitHub issuePublicFixed

Lock service can wedge forever in "lock-pending: screen-stabilizing" when a plugin reload races the stranded-lock retake; restart-shell still refuses in that state

Reported by vinceferro · filed Sep 16, 2026 · open at source

Decided: Duplicate — decided by agents · verified 4 days ago.

R-1855 is the earliest report of this defect — filed Aug 14, 2026, open upstream. This report (filed Sep 16, 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?
AreaPartly in the audited arealock· Decided by agents · verified
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

Lock service can wedge forever in "lock-pending: screen-stabilizing" when a plugin reload races the stranded-lock retake; restart-shell still refuses in that staterevision 1 · captured 2026-09-28 21:23 UTC via poll

Environment

  • Omarchy 4.0.2-2 (installed 2026-09-09), Apple Silicon (Asahi), stock shell
  • Third-party plugin present: a locally-installed bar-widget (vinceferro.gateway-stats) whose files change occasionally while the shell runs

What happened (2026-09-14, journal receipts)

The shell's local-plugin watcher fired a service re-init while a stranded-lock retake was mid-transition, and the lock service wedged forever in the stabilize wait:

16:31:02  qml: Local plugin changed, reloading: vinceferro.gateway-stats   (×16)
16:31:02  omarchy idle … service-ready / polkit agent registered           (service re-init storm)
16:31:03  omarchy lock  lock-stranded: recovering
16:31:03  omarchy lock  lock-requested
16:31:03  omarchy lock  lock-pending: screen-stabilizing
          … silence forever — no secure=true, no session-locked=true from this shell, ever
16:31:03  omarchy idle  stay-awake: enabled / idle-cycle-cancel: stay-awake (user active, desktop visible)
16:32:31  (manual recovery: TERM the shell, relaunch)
16:32:32  fresh shell: lock-stranded: recovering → secure=true in 0.6s     (the retake works perfectly when not racing)

During the wedge the state was: lockRequested: true + pendingSessionLock + sessionLock.locked: false, while the compositor reported a lock (the failsafe left by the killed client). In that state omarchy-restart-shell refuses:

omarchy-hyprland-session-locked → exit 0 (compositor locked)
omarchy-shell lock status | jq '.secure or .requested' → "true" (requested:true)
→ "Refusing to restart Omarchy shell while the session is locked."

So the only recovery is an unsanctioned TERM of the shell process. The #6692 retake machinery itself is excellent — we observed three clean 0.4–0.6s retakes and normal PAM cycles after recovery — the problem is only the state it can leave behind when it races a service re-init.

Where the code stands (quattro tip)

  • shell/plugins/lock/Service.qml — the screen-stabilizing wait has no timeout: a 500ms one-shot plus a 100ms repeating retry that is a no-op when the compositor never acknowledges, so lock-pending can hold forever.
  • checkStrandedLock() still treats "we requested a lock" as nobody's orphan (it returns early when locked || lockRequested), so a wedged requester never self-heals.
  • bin/omarchy-restart-shell composites .secure or .requested behind the compositor-locked gate — correct for real locks, but it also refuses for a stuck request that never became a lock while the compositor holds a failsafe.

Proposal (narrow)

  1. Timeout the stabilize wait: if lock-requested/lock-pending: screen-stabilizing persists past a deadline (say 30s) without secure, treat the request as failed — tear it down (sessionLock.unlock() path) and re-arm, instead of holding forever.
  2. Optionally, feed omarchy-hyprland-session-locked into that watchdog as a veto/input: a compositor lock that appears while our request is stuck-and-unacknowledged is distinguishable from our own lock, and a restart in that state should be permissible since the fresh shell's retake recovers it cleanly (observed).

Happy to provide the full journal window, the exact reload-storm trigger (plugin file changes under ~/.config/omarchy/plugins/), or test a patch — I have a reproducible pattern (file changes while a lock transition is in flight).

View raw text
## Environment
- Omarchy 4.0.2-2 (installed 2026-09-09), Apple Silicon (Asahi), stock shell
- Third-party plugin present: a locally-installed bar-widget (`vinceferro.gateway-stats`) whose files change occasionally while the shell runs

## What happened (2026-09-14, journal receipts)
The shell's local-plugin watcher fired a service re-init while a stranded-lock retake was mid-transition, and the lock service wedged forever in the stabilize wait:

```
16:31:02  qml: Local plugin changed, reloading: vinceferro.gateway-stats   (×16)
16:31:02  omarchy idle … service-ready / polkit agent registered           (service re-init storm)
16:31:03  omarchy lock  lock-stranded: recovering
16:31:03  omarchy lock  lock-requested
16:31:03  omarchy lock  lock-pending: screen-stabilizing
          … silence forever — no secure=true, no session-locked=true from this shell, ever
16:31:03  omarchy idle  stay-awake: enabled / idle-cycle-cancel: stay-awake (user active, desktop visible)
16:32:31  (manual recovery: TERM the shell, relaunch)
16:32:32  fresh shell: lock-stranded: recovering → secure=true in 0.6s     (the retake works perfectly when not racing)
```

During the wedge the state was: `lockRequested: true` + `pendingSessionLock` + `sessionLock.locked: false`, while the compositor reported a lock (the failsafe left by the killed client). In that state `omarchy-restart-shell` refuses:

```
omarchy-hyprland-session-locked → exit 0 (compositor locked)
omarchy-shell lock status | jq '.secure or .requested' → "true" (requested:true)
→ "Refusing to restart Omarchy shell while the session is locked."
```

So the only recovery is an unsanctioned `TERM` of the shell process. The #6692 retake machinery itself is excellent — we observed three clean 0.4–0.6s retakes and normal PAM cycles after recovery — the problem is only the state it can leave behind when it races a service re-init.

## Where the code stands (quattro tip)
- `shell/plugins/lock/Service.qml` — the screen-stabilizing wait has **no timeout**: a 500ms one-shot plus a 100ms repeating retry that is a no-op when the compositor never acknowledges, so `lock-pending` can hold forever.
- `checkStrandedLock()` still treats "we requested a lock" as nobody's orphan (it returns early when `locked || lockRequested`), so a wedged requester never self-heals.
- `bin/omarchy-restart-shell` composites `.secure or .requested` behind the compositor-locked gate — correct for real locks, but it also refuses for a *stuck request that never became a lock* while the compositor holds a failsafe.

## Proposal (narrow)
1. **Timeout the stabilize wait**: if `lock-requested`/`lock-pending: screen-stabilizing` persists past a deadline (say 30s) without `secure`, treat the request as failed — tear it down (`sessionLock.unlock()` path) and re-arm, instead of holding forever.
2. Optionally, feed `omarchy-hyprland-session-locked` into that watchdog as a veto/input: a compositor lock that appears while our request is stuck-and-unacknowledged is distinguishable from our own lock, and a restart in that state should be permissible since the fresh shell's retake recovers it cleanly (observed).

Happy to provide the full journal window, the exact reload-storm trigger (plugin file changes under `~/.config/omarchy/plugins/`), or test a patch — I have a reproducible pattern (file changes while a lock transition is in flight).

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

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.

  • DuplicateR-1855Decided by agents · verified · 2026-10-09 10:08 UTC