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

Media keys start an idle Spotify instead of the last-used player: selectActivePlayer() falls back to whoever holds a corked PipeWire stream

Reported by bldeden · filed Sep 21, 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

Media keys start an idle Spotify instead of the last-used player: selectActivePlayer() falls back to whoever holds a corked PipeWire streamrevision 1 · captured 2026-09-28 21:23 UTC via poll

What happens

With two MPRIS players open and both paused (Chromium/YouTube and Spotify), pressing XF86AudioPlay starts Spotify, not the player that was last used. It reproduces reliably after YouTube has been paused for a while.

What I expected

Play/pause resumes whatever I last paused.

Why

shell/plugins/services/media/Service.qml → selectActivePlayer() (4.0.3, line 231):

return oldestPlayingPlayer(true) || oldestPlayingPlayer(false) || streamPreferred || streamCandidate || preferred || trackPlayer || ...

When nothing is playing, both oldestPlayingPlayer() calls return null and selection falls to streamCandidate — the first player with a matching PipeWire playback stream (playerHasPlaybackStream, line 213). That test only asks whether a stream node exists, not whether it is running:

  • Spotify keeps a corked sink-input open indefinitely while paused, so it always has a stream.
  • Chromium tears its streams down after a media session goes idle, and drops its MPRIS object entirely when a tab's media session ends.

So once YouTube has been paused long enough, Spotify is the only player holding a stream and wins every time.

$ pactl list sink-inputs | grep -E "Sink Input|application.name|Corked"
Sink Input #269
	Corked: yes
		application.name = "Spotify"

Note streamCandidate is evaluated before preferred, so even an explicit preference set by the previous media-key press loses to an unrelated app that merely holds an idle stream.

Two things make it stick:

  1. preferredPlayerKey is the dbus name (org.mpris.MediaPlayer2.chromium.instance1451). Chromium recreates its MPRIS object per media session, and syncPlayingOrder() clears the preference when the object disappears (line 125) — so the preference is lost exactly in the case that needs it.
  2. preferredPlayerKey and playerStartedAt are in-memory only. After omarchy restart shell (or an update) there is no history at all, and selection drops straight to the stream-based fallback.

Steps to reproduce

  1. Open Spotify, play a track, pause it. Leave it running.
  2. Play a YouTube video in Chromium, then pause it.
  3. Wait until Chromium has released its playback streams (a few minutes; YouTube's "Video paused. Continue watching?" prompt is a good marker).
  4. Press the play/pause media key → Spotify starts.

Also reproduces immediately after omarchy restart shell with both players paused.

Suggested fix

Rank a recency signal above the stream-existence fallback, and make it durable:

  • Track "last actually playing" per player and prefer that over streamCandidate when nothing is playing.
  • Key the preference/recency by application rather than dbus name, so Chromium re-registering its MPRIS object doesn't wipe it.
  • Persist it under ~/.local/state/omarchy/ so a shell restart doesn't reset the decision to "whoever holds a stream" (the notifications plugin already does this for DND).

Alternatively, playerHasPlaybackStream() could ignore corked streams — but PwNode doesn't expose corked state, so the recency route looks more tractable.

I have a working patch along these lines running locally in a cloned omarchy.media; happy to open a PR if the approach seems right.

System

Omarchy4.0.3-1
Kernel7.2.3-arch1-3
CPUAMD Ryzen 7 9800X3D
GPUAMD Radeon RX 9070 XT (Navi 48)
Hyprland0.56.2
Quickshell0.3.1-1
Chromium152.0.7977.82-1
Spotify1:1.2.96.518-2
View raw text
### What happens

With two MPRIS players open and both paused (Chromium/YouTube and Spotify), pressing `XF86AudioPlay` starts **Spotify**, not the player that was last used. It reproduces reliably after YouTube has been paused for a while.

### What I expected

Play/pause resumes whatever I last paused.

### Why

`shell/plugins/services/media/Service.qml` → `selectActivePlayer()` (4.0.3, line 231):

```qml
return oldestPlayingPlayer(true) || oldestPlayingPlayer(false) || streamPreferred || streamCandidate || preferred || trackPlayer || ...
```

When nothing is playing, both `oldestPlayingPlayer()` calls return null and selection falls to `streamCandidate` — the first player with a matching PipeWire playback stream (`playerHasPlaybackStream`, line 213). That test only asks whether a stream node *exists*, not whether it is running:

* **Spotify keeps a corked sink-input open indefinitely while paused**, so it always has a stream.
* **Chromium tears its streams down** after a media session goes idle, and drops its MPRIS object entirely when a tab's media session ends.

So once YouTube has been paused long enough, Spotify is the only player holding a stream and wins every time.

```
$ pactl list sink-inputs | grep -E "Sink Input|application.name|Corked"
Sink Input #269
	Corked: yes
		application.name = "Spotify"
```

Note `streamCandidate` is evaluated **before** `preferred`, so even an explicit preference set by the previous media-key press loses to an unrelated app that merely holds an idle stream.

Two things make it stick:

1. `preferredPlayerKey` is the dbus name (`org.mpris.MediaPlayer2.chromium.instance1451`). Chromium recreates its MPRIS object per media session, and `syncPlayingOrder()` clears the preference when the object disappears (line 125) — so the preference is lost exactly in the case that needs it.
2. `preferredPlayerKey` and `playerStartedAt` are in-memory only. After `omarchy restart shell` (or an update) there is no history at all, and selection drops straight to the stream-based fallback.

### Steps to reproduce

1. Open Spotify, play a track, pause it. Leave it running.
2. Play a YouTube video in Chromium, then pause it.
3. Wait until Chromium has released its playback streams (a few minutes; YouTube's "Video paused. Continue watching?" prompt is a good marker).
4. Press the play/pause media key → Spotify starts.

Also reproduces immediately after `omarchy restart shell` with both players paused.

### Suggested fix

Rank a recency signal above the stream-existence fallback, and make it durable:

* Track "last actually playing" per player and prefer that over `streamCandidate` when nothing is playing.
* Key the preference/recency by application rather than dbus name, so Chromium re-registering its MPRIS object doesn't wipe it.
* Persist it under `~/.local/state/omarchy/` so a shell restart doesn't reset the decision to "whoever holds a stream" (the notifications plugin already does this for DND).

Alternatively, `playerHasPlaybackStream()` could ignore corked streams — but PwNode doesn't expose corked state, so the recency route looks more tractable.

I have a working patch along these lines running locally in a cloned `omarchy.media`; happy to open a PR if the approach seems right.

### System

| | |
|---|---|
| Omarchy | 4.0.3-1 |
| Kernel | 7.2.3-arch1-3 |
| CPU | AMD Ryzen 7 9800X3D |
| GPU | AMD Radeon RX 9070 XT (Navi 48) |
| Hyprland | 0.56.2 |
| Quickshell | 0.3.1-1 |
| Chromium | 152.0.7977.82-1 |
| Spotify | 1:1.2.96.518-2 |

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 16:57 UTC