Note
🤖 Claude Opus 5.5 responding on behalf of Sam
Triage result: path 1 is ruled out live. Path 2 takes the guarded #147 route by the same measured fact, but its wake case is not observed yet. No fix is needed for anything reproduced so far.
The premise does not hold
The issue assumed that a window on a hidden native Space counts as ordered out.
It does not: macOS reports SLSWindowIsOrderedIn = true for it, both unlocked and locked.
cleanup_unordered_windows(src/ecs/workspace.rs) closes a window only onwindow_ordered_in == Ok(false), so a hidden-Space window never qualifies.claim_replaced_window_handles(src/ecs/triggers.rs) givesAwaitingHandleto every ordered-in window with a dead AX element.window_destroyed_triggerthen skips it, andrecover_window_handlesholds it until the unlock, which is the samanyudas/paneru#104 fix.
Live lock test (path 1)
Build: main app with engine a20f56e (the current pin), on Sam's Mac, verify-miri run 20261106-211445.
- Opened one AXFixture window (391434) and placed it on display 1's hidden Space 4898 with a Mission Control click.
SLSMoveWindowsToManagedSpaceon another process's window does nothing, so the click was needed. - Locked the screen with
SACLockScreenImmediateat 21:17:43 (ACDT) and sampled engine state and the window server once a second. - Sam unlocked at 21:30:48, and sampling ran 90 s more.
Results:
- 623 samples locked (13 min), 90 unlocked.
- Every sample from the corrected sampler shows the same 11 managed windows on the same Spaces (711 identical rows), fixture included.
- The fixture read
ordered_in=true space=[4898] shown=falsein every sample. - The fixture app's
AXWindowsread empty during the lock, so the failed-AX condition was present. - The engine loop wakes at least every 500 ms (2 s in Low Power Mode), and
cleanup_unordered_windowsruns on a 1 s timer, so it ran about once a second, roughly 780 times over the 13-minute lock, without dropping the fixture. - The engine log has no destroy or close line for the run.
verify-miri endrestored the session, and its layout check passed for all 10 pre-existing windows.
The first two samples of the run (21:17:44 and 21:17:45) read managed_count=0 from a sampler parsing bug that also read 0 before the lock.
They are not a drop.
Path 2: not observed
The wake case needs macOS to move a managed window onto a hidden Space during a real sleep and wake. I did not sleep the Mac, because that would pause every other agent run on it.
Inference, not observed: a window moved to a hidden Space is still ordered in, so it gets AwaitingHandle and waits for the unlock like the windows in the #147 runs.
One gap remains in the reasoning.
After the unlock, recover_window_handles keeps a window only if its old AX element answers again or adopt_fresh_handle finds a new one in the app's AXWindows.
That list leaves out windows on hidden Spaces, so a hidden-Space window whose element the wake replaced would be closed after 1 s.
In the #147 runs the old elements revived after the unlock, so this case may never occur.
Next step
Hand check by Sam: with a managed window on a hidden native Space, sleep the Mac (lid close) for about a minute, wake, unlock, and check the window is still managed on its Space.
If it holds, both criteria are met and this can close.
If it drops, the replaced-element gap above is the first suspect.
Labelled needs-info until then.