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.
Bluetooth headset volume can drift from what PC shows — host should push it back as authoritative
Reported by RajdeepVerma · filed Sep 18, 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
Omarchy 4.0.4-1, kernel 7.2.5-3-omarchy. Bluetooth headset: realme Buds Wireless 5 ANC (AVRCP target, A2DP, SBC/AAC).
What's wrong?
A Bluetooth headset's own volume buttons can drift out of sync with the system volume shown on the PC, even when every value this machine can observe agrees with itself. Concretely, on this headset:
- Pressing the physical volume buttons sends AVRCP absolute-volume notifications that BlueZ relays via
org.bluez.MediaTransport1.Volume. - PipeWire's
bluez5.enable-hw-volume(when not blocked by an unrelated quirk-DB match — separate issue, not this one) applies that value to the sink, and it always matches what BlueZ reports — confirmed with a timestamped correlation of everyPropertiesChangedVolumeevent againstwpctl get-volumeduring live button presses. They agree at rest and converge within ~1s during a rapid burst. - Despite that agreement, the headset's actual output loudness can still drift away from the number both BlueZ and PipeWire show, because the AVRCP notification is a one-way, sometimes-rounded echo of the headset's own local volume state — the host currently only ever reads it, never asserts it back. Over repeated button presses, the notified value and the headset's real internal level can diverge.
So this isn't the already-tracked "OSD doesn't appear" issue (#12306, mine, already fixed there) or the already-tracked "audio panel slider doesn't move a Bluetooth sink" issue (#11683 — different root cause, a Quickshell bug where the panel's slider never calls into PipeWire for BlueZ sinks). This is specifically about the headset's own hardware volume silently drifting from what every layer on the PC side agrees is "correct."
Root cause
org.bluez.MediaTransport1.Volume is documented as readable, writable, and a write to it is turned by bluetoothd into a real AVRCP SetAbsoluteVolume command sent to the connected peripheral — not just a local bookkeeping update. Confirmed live with busctl set-property, both with the transport idle and active. Nothing in the current PipeWire/BlueZ/Omarchy stack uses that write path — volume only ever flows peripheral → host, never host → peripheral as a corrective, authoritative push.
Suggested fix
Whenever the resolved system volume for a Bluetooth output changes (from any source — the headset's own buttons or an on-PC control), push that same value back to the transport as the authoritative one, so the headset can't drift from what the host displays:
# resolve fresh each time - sep/fd indices in the object path can change across reconnects
path="$(busctl tree org.bluez | grep -oP "/org/bluez/hci\d+/dev_${addr_us}/sep\d+/fd\d+" | head -n1)"
avrcp=$(( (percent * 127 + 50) / 100 ))
current="$(busctl get-property org.bluez "$path" org.bluez.MediaTransport1 Volume | awk '{print $2}')"
# tolerance of 1: 0-127 and 0-100 don't divide evenly, comparing against the *live* transport
# value (not the last value we pushed) avoids a permanent one-step oscillation
(( diff = avrcp - current, diff < 0 && (diff = -diff), diff > 1 )) && \
busctl set-property org.bluez "$path" org.bluez.MediaTransport1 Volume q "$avrcp"I've implemented and locally verified this as a small addition to the volume-osd-watcher workaround from #12306 (which already watches pactl subscribe for sink changes on this machine). A wpctl set-volume immediately produced the matching write to the transport, and it settled without looping against PipeWire's own hw-volume reapplication. Where this actually belongs upstream is presumably the same place #12306 and #11683 point at — the omarchy.audio/Quickshell audio panel path, or PipeWire's own bluez5 module, rather than a userland watcher — I don't have a strong opinion on which, since omarchy.audio is disabled on this machine (using io.github.solkkku.audio-switcher instead) so I couldn't exercise that path directly.
Related
- #12306 (mine) — OSD not appearing for Bluetooth volume changes, already merged/open
- #11683 — different bug, audio panel slider doesn't move Bluetooth sinks (Quickshell
volumeStepissue) - PipeWire issue #5477 (gitlab.freedesktop.org/pipewire/pipewire/-/issues/5477) — the
hw-volumequirk-DB false positive that has to be worked around before any of this matters
View raw text
### System details
Omarchy 4.0.4-1, kernel 7.2.5-3-omarchy. Bluetooth headset: realme Buds Wireless 5 ANC (AVRCP target, A2DP, SBC/AAC).
### What's wrong?
A Bluetooth headset's own volume buttons can drift out of sync with the system volume shown on the PC, even when every value this machine can observe agrees with itself. Concretely, on this headset:
1. Pressing the physical volume buttons sends AVRCP absolute-volume notifications that BlueZ relays via `org.bluez.MediaTransport1.Volume`.
2. PipeWire's `bluez5.enable-hw-volume` (when not blocked by an unrelated quirk-DB match — separate issue, not this one) applies that value to the sink, and it always matches what BlueZ reports — confirmed with a timestamped correlation of every `PropertiesChanged` `Volume` event against `wpctl get-volume` during live button presses. They agree at rest and converge within ~1s during a rapid burst.
3. Despite that agreement, the headset's *actual* output loudness can still drift away from the number both BlueZ and PipeWire show, because the AVRCP notification is a one-way, sometimes-rounded echo of the headset's own local volume state — the host currently only ever reads it, never asserts it back. Over repeated button presses, the notified value and the headset's real internal level can diverge.
So this isn't the already-tracked "OSD doesn't appear" issue (#12306, mine, already fixed there) or the already-tracked "audio panel slider doesn't move a Bluetooth sink" issue (#11683 — different root cause, a Quickshell bug where the panel's slider never calls into PipeWire for BlueZ sinks). This is specifically about the headset's own hardware volume silently drifting from what every layer on the PC side agrees is "correct."
### Root cause
`org.bluez.MediaTransport1.Volume` is documented as `readable, writable`, and a **write** to it is turned by bluetoothd into a real AVRCP `SetAbsoluteVolume` command sent to the connected peripheral — not just a local bookkeeping update. Confirmed live with `busctl set-property`, both with the transport idle and active. Nothing in the current PipeWire/BlueZ/Omarchy stack uses that write path — volume only ever flows peripheral → host, never host → peripheral as a corrective, authoritative push.
### Suggested fix
Whenever the resolved system volume for a Bluetooth output changes (from *any* source — the headset's own buttons or an on-PC control), push that same value back to the transport as the authoritative one, so the headset can't drift from what the host displays:
```bash
# resolve fresh each time - sep/fd indices in the object path can change across reconnects
path="$(busctl tree org.bluez | grep -oP "/org/bluez/hci\d+/dev_${addr_us}/sep\d+/fd\d+" | head -n1)"
avrcp=$(( (percent * 127 + 50) / 100 ))
current="$(busctl get-property org.bluez "$path" org.bluez.MediaTransport1 Volume | awk '{print $2}')"
# tolerance of 1: 0-127 and 0-100 don't divide evenly, comparing against the *live* transport
# value (not the last value we pushed) avoids a permanent one-step oscillation
(( diff = avrcp - current, diff < 0 && (diff = -diff), diff > 1 )) && \
busctl set-property org.bluez "$path" org.bluez.MediaTransport1 Volume q "$avrcp"
```
I've implemented and locally verified this as a small addition to the `volume-osd-watcher` workaround from #12306 (which already watches `pactl subscribe` for sink changes on this machine). A `wpctl set-volume` immediately produced the matching write to the transport, and it settled without looping against PipeWire's own hw-volume reapplication. Where this actually belongs upstream is presumably the same place #12306 and #11683 point at — the `omarchy.audio`/Quickshell audio panel path, or PipeWire's own bluez5 module, rather than a userland watcher — I don't have a strong opinion on which, since `omarchy.audio` is disabled on this machine (using `io.github.solkkku.audio-switcher` instead) so I couldn't exercise that path directly.
### Related
- #12306 (mine) — OSD not appearing for Bluetooth volume changes, already merged/open
- #11683 — different bug, audio panel slider doesn't move Bluetooth sinks (Quickshell `volumeStep` issue)
- PipeWire issue #5477 (gitlab.freedesktop.org/pipewire/pipewire/-/issues/5477) — the `hw-volume` quirk-DB false positive that has to be worked around before any of this matters
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 15:26 UTC