[Bug]: macOS agent pauses device I/O until restart when a screen/session wake notification never arrives
- Dominant language
- Rust
- Stars
- 21k
- Forks
- 675
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 172
Description
### Pre-flight checklist
- [x] I searched existing issues and this is not a duplicate.
- [x] I am on the latest release (0.8.3).
- [x] Logi Options+ is not installed.
### Which part of OpenLogi?
Both (agent + GUI)
### OpenLogi version
0.8.3
### Operating system
macOS
### OS version & architecture
macOS 26.6.2 (Tahoe), Apple Silicon (M5 Max). MacBook Pro in clamshell mode: lid closed, one external 3840x1600 display as the main display.
### Device model
MX Master 3
### How is the device connected?
Logitech Unifying receiver (046d:c52b)
### Affected area(s)
- [x] Device discovery / detection
### What happened?
The agent paused all HID access and never resumed. `openlogi list` showed the receiver's paired slots as `○ Unknown device` for 66 minutes while I was actively using the machine (the mouse still moved through macOS's own driver, OpenLogi just saw nothing). Restarting the agent fixed it instantly.
`crates/openlogi-agent/src/tray.rs` closes the device-I/O gate on `NSWorkspaceWillSleep` / `ScreensDidSleep` / `SessionDidResignActive` and reopens it only on `ScreensDidWake` / `SessionDidBecomeActive`. Those are edges, and the workspace notification center guarantees neither delivery nor pairing. If a suspend edge arrives and its partner does not, the suspend mask keeps that bit for the life of the process. There is no timeout and no re-read of any state, so the agent cannot notice that its belief disagrees with reality.
Expected: the agent works out that the display and session are back and resumes on its own.
### Steps to reproduce
Not reliably reproducible on demand, since it depends on a dropped notification. The sequence I observed:
1. MacBook in clamshell, one external display as main; MX Master 3 on a Unifying receiver.
2. Leave the machine until it locks; come back and unlock.
3. The display reconfigures at unlock (a ~1 s off/on blink in `pmset -g log`).
4. Keep working. `openlogi list` now reports the paired slots as `○ Unknown device` and the GUI shows no devices, indefinitely.
5. `launchctl kickstart -k gui/$UID/org.openlogi.agent.service` and everything is immediately correct again.
### Logs
`~/.local/state/openlogi/agent.2026-09-05.log` (UTC):
```
2026-09-05T23:04:20.461468Z INFO openlogi_agent::lifecycle: openlogi-agent started
2026-09-05T23:04:20.492010Z INFO openlogi_agent::tray: display/session resumed — enabling device I/O
2026-09-05T23:04:39.393454Z INFO openlogi_agent::tray: display/session suspended — pausing device I/O
... no further display/session line for the next 66 minutes ...
2026-09-05T23:45:34.156297Z WARN tarpc::server: Requests stream errored out: could not flush the transport: Broken pipe (os error 32)
2026-09-05T23:46:39.958208Z WARN tarpc::server: Requests stream errored out: could not flush the transport: Broken pipe (os error 32)
2026-09-05T23:47:03.108966Z WARN tarpc::server: Requests stream errored out: could not flush the transport: Broken pipe (os error 32)
```
The three `Broken pipe` warnings are three `openlogi list` runs in that window. The suspend line does not say which notification produced it, so the log cannot tell a dropped `ScreensDidWake` from a dropped `SessionDidBecomeActive`.
`pmset -g log` (local time, UTC-7) at the same instant:
```
2026-09-05 16:04:29 -0700 Display is turned on
2026-09-05 16:04:39 -0700 Display is turned off
2026-09-05 16:04:40 -0700 Display is turned on
```
16:04:39 local is 23:04:39 UTC, the same second as the suspend line: a one-second blink at unlock with no wake notification after it. The unified log for that window was not retained, so I can't prove which notification was dropped, but either way the gate has no path back.
`openlogi list` during the outage:
```
Unifying Receiver (E3C196DA, vid=046d pid=c52b)
├─ slot 1 ○ Unknown device (mouse, wpid=4069, battery=—)
└─ slot 2 ○ Unknown device (mouse, wpid=4082, battery=—)
```
### Related
The same log shows the relaunch half of #952 from the other side: during an earlier 2.5 h display sleep the agent was relaunched 27 times (the watchdog exit in #952), and every relaunch logged `display/session resumed — enabling device I/O`. That line is only reachable when the startup snapshot decides the display is awake, so `CGDisplayIsAsleep(CGMainDisplayID())` answered `false` for the whole blank that `NSWorkspaceScreensDidSleep` had reported correctly a second earlier. With the lid shut the external panel is the only online display, so reading the full display list gives the same answer, and on Apple Silicon `IODisplayWrangler` has no `IOPowerManagement` dictionary to read instead. So each relaunched agent resumed HID probing behind a dark panel.
I have a fix for both halves; PR to follow.
### macOS permissions
- [x] Accessibility
- [x] Input Monitoring
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in crates/openlogi-agent/src/tray.rs and trace the suspend/resume notification handling, including the startup state check described in the issue. Reproduce or inspect the logged suspend sequence, then verify that device I/O resumes after a missing wake notification and that relaunch behavior does not resume probing while the display is asleep.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, rust
- Domain
- desktop, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100