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-1059GitHub issuePublicDecided· Out of scope

System update widget renders a failed update check as "up to date"

Reported by JesperGravgaard · filed Sep 2, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

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 update widget renders a failed update check as "up to date"revision 1 · captured 2026-09-28 21:24 UTC via poll

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:

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.

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