src/switcher/state/WindowEventReducerFocusSpecs.md
Covers WindowEventReducer.refrontAfterRemovingTheFocusedWindow: what happens to MRU slot 0 when the window
holding it is removed. Specs + Tests without a same-named kernel (like WindowEventReducerPhantom): the
subject is a reducer decision, not a pure function of its own.
The captured scenario is driven through TestReducerRunner, because the bug only appears as a SEQUENCE
(activation, two 808s, a removal); the rule-level scenarios drive WindowEventReducer.reduce directly.
The reporter's REAPER window stopped moving in the switcher: every alt-tab landed back on the window they
were already in, and the first tile was a Finder window they had left minutes ago. Their --logs=debug
capture (2026-07-27, v11.4.3) shows the exact instant it breaks:
13:28:08.607 focusTarget (pid:681 finder) (wid:3449) ← Finder takes MRU slot 0
13:28:13.634 WS windowFocused wid=4557 ← REAPER's "Insert Multiple Media Items",
13:28:13.845 discovered a new window: (wid:4557) opened by a drag while REAPER is BACKGROUND
13:28:14.961 WS windowFocused wid=4557 ← the click that dismisses it ACTIVATES REAPER
13:28:14.962 WS windowFocused wid=4274 ← the main window, 1 ms later
13:28:16.960 deinit (wid:4557 title:Insert Multiple Media Items)
The dialog is discovered while its app is in the background, so the freshly-created promotion fronts it
(correctly — it IS the focused window). The click then activates REAPER, and of the two 808s that activation
emits, the first (the dialog) is the focus and the second (the main window) is the raise tail, which
ActivationFocusResolver swallows by design (#5596). Both decisions are right on their own. What was missing
is the third: when the dialog is removed, closing the MRU gap hands slot 0 to whoever held slot 1 — Finder,
an app that is not even frontmost.
Nothing corrected it afterwards, which is why the reporter saw it as permanent rather than as a glitch:
re-focusing the already-focused window of the already-frontmost app emits neither an activation nor an 808, so
each alt-tab (13:28:42.720, 43.671, 44.680, all focusTarget (wid:4274)) selected the window the user
was already in and left the order exactly as it was.
The rule: macOS never moves focus to another app because a window closed. So when the removed window held slot 0, the front goes to the frontmost app's own next window, not to the global runner-up.
Mirrors WindowEventReducerFocusTests.swift 1:1.
reaper=1 finder=0, which is the reported bug exactly (first tile Finder, alt-tab lands on the current window)..applyFocus names it.Restoring is the ONE AltTab focus that stirs the app's other windows: it deminiaturizes before focusing.
Every other AltTab focus raises exactly one window, which is why an AltTab-initiated activation normally
snapshots nothing (ActivationFocusResolver.onActivation) — and why that premise had to be narrowed here
rather than dropped. These two pin the reducer end: the kernel only learns the target was minimized because
appActivated reads it off our own model, and no kernel test can prove that call site passes it.
An order-in of the active app's window is read as a raise, because the native Cmd+emits nothing else. Three OS gestures break that reading, all with the same signature: every window of every app ordered in inside one millisecond, and — unlike a Space re-show, an un-hide or a fullscreen exit — **no order-out first**, sooffScreenis empty andcameBackOnScreen` cannot tell a re-show from a raise. Measured live
(macOS 26, 2026-08-12), each with the lag from its own signal to the burst:
| trigger | signal | lag | mute | notes |
|---|---|---|---|---|
| Mission Control / App Exposé | AXExposeShowAllWindows (Dock AX) | 12-106ms | 0.5s | the common one; caught doing the full damage |
| display wake / unlock | screensDidWake / screenIsUnlocked | 2.03s (×3) | 3s | only bites on a Mac that does not lock |
| display reconfiguration | didChangeScreenParameters | ~500ms | 1.5s | was surviving on luck inside inSpaceTransition, once by 28ms |
WindowEventReducer.systemReshowMute(source) sizes each mute for its own trigger, 3-5x that trigger's lag,
armed from DockEvents, SleepWakeEvents / ScreenLockEvents and ScreensEvents. One 3s window for all
three put the cost where users meet it: dismiss Mission Control, cycle windows a beat later, and the raise
lands inside a mute sized for a wake that never happened.
The wake case only bites where the screen does not lock: with loginwindow holding the front, the app-is-active guard already swallows the burst. Mission Control has no such accidental cover, which is why it is the trigger that reproduces on any Mac, at any time of day, with no idling involved.
Under the signals sits a BACKSTOP that needs none of them (reshowBurstGap, 5ms): a raise moves one window,
a re-show moves all of them at once, so an order-in landing within 5ms of an order-in for a DIFFERENT window
does not bump. It covers the race the signals cannot promise to win — both the Dock notification and the
burst reach the main queue by async, and three of ten measured rounds had them in the same millisecond —
and any re-show trigger nobody has wired a signal for. It cannot judge a burst's FIRST member, which is the
harmless one (the frontmost app's front window, at MRU 0 in both captures).
cameBackOnScreen exclusion: a wake leaves minimized windows minimized, and a Dock restore inside the
frontmost app emits ONLY that order-in, so a swallowed bump would never be corrected (#5439).