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-4760GitHub issuePublicReceived

Dismissing the Speed Test panel orphans 8 upload workers that keep saturating the uplink

Reported by orospakr · filed Aug 30, 2026Closed upstream on 2026-08-30 by its own reporter orospakr, as a duplicate of #6989 (R-1833). GitHub close reason: not_planned.

Received and recorded verbatim. Nothing has been checked yet.

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?
Not yet mapped to any requirement or component.
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?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. No decision has been recorded yet.

Original report

Dismissing the Speed Test panel orphans 8 upload workers that keep saturating the uplinkrevision 1 · captured 2026-10-04 12:03 UTC via poll

System details

Intel Xeon W-2140B, AMD Radeon Pro Vega 56 (amdgpu), Omarchy 4.0.1-1, Hyprland 0.56.2, quickshell 0.3.1-1, bash 5.3.15, kernel 7.1.8-arch1, Apple iMacPro1,1 (T2)

What's wrong?

Dismissing the Network Speed Test panel leaves up to 8 orphaned omarchy-network-speedtest worker subshells running. They are reparented to systemd --user and keep looping 64 MB POSTs to Netflix OCA nodes indefinitely — the panel is gone, but the uplink stays saturated until the user notices and kills them by hand. Every dismissal leaks another generation.

I hit this by accident (found 8 stray curl uploads pinning my connection long after closing the panel), then reproduced it deterministically.

Steps to reproduce

omarchy-shell shell summon omarchy.speedtest '{}'
sleep 7                                    # past the 5s download phase, into the upload phase
omarchy-shell shell hide omarchy.speedtest # or just click the overlay's close button
sleep 4
ps -e -o pid=,ppid=,cmd= | grep -F '/omarchy-network-speedtest' | grep -v grep

Expected: no output.

Actual — 6 of the 8 workers survive, reparented to PID 1215 (systemd --user):

 307860    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307861    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307864    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307865    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307868    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307872    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up

Each still has a live curl:

curl -fsS -o /dev/null -X POST --data-binary @- https://ipv4-c001-yul001-beanfield-isp.1.oca.nflxvideo.net/speedtest?c=ca&n=21949...

Recovery is pkill -f omarchy-network-speedtest.

Cause

A teardown race between the panel and the script:

  • omarchy-network-speedtest forks 8 background workers and relies on trap cleanup EXIT (bin/omarchy-network-speedtest:55-67) to reap them.
  • plugins/panels/speedtest/Panel.qml:50-62 close() does the right thing — speedTestProc.running = false sends SIGTERM.
  • But shell.qml:480-494 hide() calls close() and then removes the id from openPanelIds in the same event-loop turn. That flips the Loader's active binding (shell.qml:625) to false, destroying the panel Item — and its Process — while bash is still shutting down.
  • The script can't respond to the SIGTERM instantly: it is blocked in sleep 1 in its sampling loop (:108-128), so it needs up to ~1s to reach the trap. It never gets that long, so cleanup never completes and the 8 workers are orphaned.

Verified both directions: SIGTERM to the script alone cleans up perfectly (0 orphans); SIGKILL reproduces the exact orphan signature above. The speedtest manifest doesn't set keepLoaded, so it's on the destroy-on-hide path.

Possible fixes

Either one alone appears sufficient:

  1. "keepLoaded": true in plugins/panels/speedtest/manifest.json, so the Item survives the hide and close()'s SIGTERM lands. One line, but only covers this panel.
  2. Harden the script — trap cleanup EXIT INT TERM HUP, and put the workers in their own process group so a hard kill takes the children with it. Fixes it for any caller, and makes the script safe to kill from anywhere.

A more general fix would be for hide() to let a plugin finish closing before the Loader is deactivated, since any plugin that spawns a Process is exposed to the same race.

I haven't checked whether omarchy.disk-speedtest has the same problem; its Panel.qml comments suggest the helper cleans up after itself differently, so it may not.

Happy to send a PR for whichever approach you'd prefer.

View raw text
### System details

Intel Xeon W-2140B, AMD Radeon Pro Vega 56 (amdgpu), Omarchy 4.0.1-1, Hyprland 0.56.2, quickshell 0.3.1-1, bash 5.3.15, kernel 7.1.8-arch1, Apple iMacPro1,1 (T2)

### What's wrong?

Dismissing the Network Speed Test panel leaves up to 8 orphaned `omarchy-network-speedtest` worker subshells running. They are reparented to `systemd --user` and keep looping 64 MB `POST`s to Netflix OCA nodes **indefinitely** — the panel is gone, but the uplink stays saturated until the user notices and kills them by hand. Every dismissal leaks another generation.

I hit this by accident (found 8 stray `curl` uploads pinning my connection long after closing the panel), then reproduced it deterministically.

#### Steps to reproduce

```bash
omarchy-shell shell summon omarchy.speedtest '{}'
sleep 7                                    # past the 5s download phase, into the upload phase
omarchy-shell shell hide omarchy.speedtest # or just click the overlay's close button
sleep 4
ps -e -o pid=,ppid=,cmd= | grep -F '/omarchy-network-speedtest' | grep -v grep
```

Expected: no output.

Actual — 6 of the 8 workers survive, reparented to PID 1215 (`systemd --user`):

```
 307860    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307861    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307864    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307865    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307868    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
 307872    1215 /bin/bash /usr/share/omarchy/bin/omarchy-network-speedtest up
```

Each still has a live `curl`:

```
curl -fsS -o /dev/null -X POST --data-binary @- https://ipv4-c001-yul001-beanfield-isp.1.oca.nflxvideo.net/speedtest?c=ca&n=21949...
```

Recovery is `pkill -f omarchy-network-speedtest`.

#### Cause

A teardown race between the panel and the script:

- `omarchy-network-speedtest` forks 8 background workers and relies on `trap cleanup EXIT` (`bin/omarchy-network-speedtest:55-67`) to reap them.
- `plugins/panels/speedtest/Panel.qml:50-62` `close()` does the right thing — `speedTestProc.running = false` sends SIGTERM.
- But `shell.qml:480-494` `hide()` calls `close()` and then removes the id from `openPanelIds` in the **same event-loop turn**. That flips the Loader's `active` binding (`shell.qml:625`) to false, destroying the panel Item — and its `Process` — while bash is still shutting down.
- The script can't respond to the SIGTERM instantly: it is blocked in `sleep 1` in its sampling loop (`:108-128`), so it needs up to ~1s to reach the trap. It never gets that long, so `cleanup` never completes and the 8 workers are orphaned.

Verified both directions: SIGTERM to the script alone cleans up perfectly (0 orphans); SIGKILL reproduces the exact orphan signature above. The speedtest manifest doesn't set `keepLoaded`, so it's on the destroy-on-hide path.

#### Possible fixes

Either one alone appears sufficient:

1. `"keepLoaded": true` in `plugins/panels/speedtest/manifest.json`, so the Item survives the hide and `close()`'s SIGTERM lands. One line, but only covers this panel.
2. Harden the script — `trap cleanup EXIT INT TERM HUP`, and put the workers in their own process group so a hard kill takes the children with it. Fixes it for any caller, and makes the script safe to kill from anywhere.

A more general fix would be for `hide()` to let a plugin finish closing before the Loader is deactivated, since any plugin that spawns a `Process` is exposed to the same race.

I haven't checked whether `omarchy.disk-speedtest` has the same problem; its `Panel.qml` comments suggest the helper cleans up after itself differently, so it may not.

Happy to send a PR for whichever approach you'd prefer.

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.

No decision has been recorded yet.