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.
System update widget renders a failed update check as "up to date"
Reported by JesperGravgaard · filed Sep 2, 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?
- AreaOutside the audited area· 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
System details
AMD Ryzen AI 7 350 / Radeon 860M, Omarchy 4.0.0-1, kernel 7.1.8-arch1-3,
pacman-contrib 1.13.1-1. Two displays (eDP-1 2256x1504, DP-3 3840x2160), but see
below — a second display is not required.
Verified against main at 7eca64e2: bin/omarchy-update-available andshell/plugins/bar/widgets/SystemUpdate.qml are byte-identical to the installed
4.0.0 copies, so this is not fixed in 4.0.1 or 4.0.2.
What's wrong?
The system update widget shows no icon while an update is pending. It does not
distinguish "no update" from "the check failed" — any non-zero exit from the
check is rendered as up to date.
The bug
Four things chain together.
1. The widget exists more than once. shell/plugins/bar/Bar.qml:966 isVariants { model: Quickshell.screens }, so each screen builds its own bar and
its own widget instances. Per #8221 an instance also exists transiently "while a
plugin reload overlaps the outgoing instance, which happens on single-monitor
machines too" — so this is not a multi-monitor-only bug.
**2. Each instance runs its own check, and refreshes are fanned out on
purpose.** SystemUpdate.qml gives every instance its own Process on aTimer { triggeredOnStart: true }, and refresh goes throughBarWidget.broadcast(), which is documented to relay to peers because "a bar
surface exists per monitor". So one refresh becomes N concurrentomarchy-update-available runs.
3. `omarchy-update-available` is not concurrency-safe. It callscheckupdates (pacman-contrib), which syncs into one shared temp database,${TMPDIR:-/tmp}/checkup-db-${UID}, and removes db.lck from atrap ... INT TERM EXIT. Concurrent runs share that directory, so whichever
finishes first drops the other's lock; the loser's pacman -Sy fails, or itspacman -Qu reads a half-synced database and prints nothing. Both pacman calls
are silenced (&> /dev/null, 2> /dev/null), so the failure is invisible and
the empty result is mapped to "up to date", exit 1.
4. The widget conflates that with "no update". SystemUpdate.qml:43:
onExited: function(exitCode) {
root.updateAvailable = exitCode === 0
}With visible: updateAvailable, a check that failed for any reason renders as
"you are up to date". That is the wrong direction to fail in: it hides a pending
update rather than showing a spurious one, and it is silent.
Reproduce
The script-level race, with an update actually pending:
$ for i in 1 2; do (out=$(omarchy-update-available 2>&1); echo "run$i: exit=$? | $out") & done; wait
run2: exit=1 | Omarchy is up to date
run1: exit=0 | omarchy 4.0.0-1 -> 4.0.2-1Observed in the bar: with omarchy 4.0.0-1 -> 4.0.2-1 pending, captures of both
bars in the same minute showed the icon present on eDP-1 and absent on DP-3.
To be straight about scope
- The missing icon is transient. It later returned on both bars without my
doing anything to the widget. I could not reproduce that recovery on demand
and cannot prove what caused it; the reload-overlap instantiation described in
#8221 is a plausible explanation, not a demonstrated one.
- The shared-temp-database behaviour is arguably a pacman-contrib bug, and
given how #6964 and #7015 were resolved you may prefer it fixed upstream in
checkupdates rather than worked around here. I am happy to take it there.
- Defect 4 is Omarchy's regardless of where 3 is fixed, and it is the one that
converts a failed check into a false reassurance. Fixing 4 alone would make
the failure visible instead of silent.
Direction, not a prescription
Two separable pieces, and I did not want to presume the shape:
- Stop conflating a failed check with a negative result, so an errored check
leaves the previous state or surfaces the error.
- Run the check once per shell rather than once per surface. shell.qml:285
caches service plugins in _services via createObject(serviceHost), one per
shell rather than one per screen, reached through serviceFor /
firstPartyServiceFor, and omarchy.media already ships as
kinds: ["service", "bar-widget"] — one service feeding N widgets is an
existing shape. That removes the concurrency rather than locking around it,
and drops N-1 redundant pacman syncs.
Same family as #7896 / #8221: a per-surface bar widget driving redundant system
work. Note #8771 already proposes test/shell.d/update-available-test.sh; a test
for this belongs in that file rather than a new one.
Happy to open a PR for either piece if you say which shape you want.
I searched open and closed issues and PRs and found nothing covering this; the
other open work on this script (#8771, #7167, #7398) is unrelated to the check's
concurrency, and no open PR touches SystemUpdate.qml.
— Drafted with Claude Code; findings verified against the repo at 7eca64e2.
View raw text
### System details
AMD Ryzen AI 7 350 / Radeon 860M, Omarchy 4.0.0-1, kernel 7.1.8-arch1-3,
pacman-contrib 1.13.1-1. Two displays (eDP-1 2256x1504, DP-3 3840x2160), but see
below — a second display is not required.
Verified against `main` at 7eca64e2: `bin/omarchy-update-available` and
`shell/plugins/bar/widgets/SystemUpdate.qml` are byte-identical to the installed
4.0.0 copies, so this is not fixed in 4.0.1 or 4.0.2.
### What's wrong?
The system update widget shows no icon while an update is pending. It does not
distinguish "no update" from "the check failed" — any non-zero exit from the
check is rendered as up to date.
## The bug
Four things chain together.
**1. The widget exists more than once.** `shell/plugins/bar/Bar.qml:966` is
`Variants { model: Quickshell.screens }`, so each screen builds its own bar and
its own widget instances. Per #8221 an instance also exists transiently "while a
plugin reload overlaps the outgoing instance, which happens on single-monitor
machines too" — so this is not a multi-monitor-only bug.
**2. Each instance runs its own check, and refreshes are fanned out on
purpose.** `SystemUpdate.qml` gives every instance its own `Process` on a
`Timer { triggeredOnStart: true }`, and `refresh` goes through
`BarWidget.broadcast()`, which is documented to relay to peers because "a bar
surface exists per monitor". So one refresh becomes N concurrent
`omarchy-update-available` runs.
**3. `omarchy-update-available` is not concurrency-safe.** It calls
`checkupdates` (pacman-contrib), which syncs into one shared temp database,
`${TMPDIR:-/tmp}/checkup-db-${UID}`, and removes `db.lck` from a
`trap ... INT TERM EXIT`. Concurrent runs share that directory, so whichever
finishes first drops the other's lock; the loser's `pacman -Sy` fails, or its
`pacman -Qu` reads a half-synced database and prints nothing. Both pacman calls
are silenced (`&> /dev/null`, `2> /dev/null`), so the failure is invisible and
the empty result is mapped to "up to date", exit 1.
**4. The widget conflates that with "no update".** `SystemUpdate.qml:43`:
```qml
onExited: function(exitCode) {
root.updateAvailable = exitCode === 0
}
```
With `visible: updateAvailable`, a check that failed for *any* reason renders as
"you are up to date". That is the wrong direction to fail in: it hides a pending
update rather than showing a spurious one, and it is silent.
## Reproduce
The script-level race, with an update actually pending:
```
$ for i in 1 2; do (out=$(omarchy-update-available 2>&1); echo "run$i: exit=$? | $out") & done; wait
run2: exit=1 | Omarchy is up to date
run1: exit=0 | omarchy 4.0.0-1 -> 4.0.2-1
```
Observed in the bar: with `omarchy 4.0.0-1 -> 4.0.2-1` pending, captures of both
bars in the same minute showed the icon present on eDP-1 and absent on DP-3.
## To be straight about scope
- The missing icon is **transient**. It later returned on both bars without my
doing anything to the widget. I could not reproduce that recovery on demand
and cannot prove what caused it; the reload-overlap instantiation described in
#8221 is a plausible explanation, not a demonstrated one.
- The shared-temp-database behaviour is arguably a `pacman-contrib` bug, and
given how #6964 and #7015 were resolved you may prefer it fixed upstream in
`checkupdates` rather than worked around here. I am happy to take it there.
- Defect 4 is Omarchy's regardless of where 3 is fixed, and it is the one that
converts a failed check into a false reassurance. Fixing 4 alone would make
the failure visible instead of silent.
## Direction, not a prescription
Two separable pieces, and I did not want to presume the shape:
- Stop conflating a failed check with a negative result, so an errored check
leaves the previous state or surfaces the error.
- Run the check once per shell rather than once per surface. `shell.qml:285`
caches service plugins in `_services` via `createObject(serviceHost)`, one per
shell rather than one per screen, reached through `serviceFor` /
`firstPartyServiceFor`, and `omarchy.media` already ships as
`kinds: ["service", "bar-widget"]` — one service feeding N widgets is an
existing shape. That removes the concurrency rather than locking around it,
and drops N-1 redundant pacman syncs.
Same family as #7896 / #8221: a per-surface bar widget driving redundant system
work. Note #8771 already proposes `test/shell.d/update-available-test.sh`; a test
for this belongs in that file rather than a new one.
Happy to open a PR for either piece if you say which shape you want.
I searched open and closed issues and PRs and found nothing covering this; the
other open work on this script (#8771, #7167, #7398) is unrelated to the check's
concurrency, and no open PR touches `SystemUpdate.qml`.
— Drafted with Claude Code; findings verified against the repo at 7eca64e2.
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
Not linked to any known issue, other report or change yet.
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.
- Out of scopeDecided by agents · verified · 2026-10-09 10:35 UTC