Moving a window is not resizing it: what Beckon 0.1.6 fixed
Beckon 0.1.6 fixes unreliable macOS window layouts with verified Accessibility frame writes, deterministic tests, and real hardware round trips.
A window manager can move a window without resizing it. The API call can return success. The window can visibly jump. The feature can still be broken.
That was the bug in Beckon.
Beckon is my zero-dependency, keyboard-first launcher for macOS. It searches apps and files, evaluates calculations, manages clipboard history, invokes menu actions, switches windows, runs scripts and plugins, and does it without network access.
The window commands looked simple: Left Half, Right Half, Center, quarters, thirds, and display movement. In the demo, Left Half and Right Half moved the window to the correct edge but sometimes retained the old dimensions. Center moved the window but did not define a new size at all.
The visual result was close enough to pass a casual glance. It was not correct.
The API acknowledged the write, not the result
macOS window management through the Accessibility API is asynchronous interprocess communication. Beckon writes AXPosition and AXSize to another application. A successful return means the target accepted the message. It does not prove that the window server applied the complete frame.
The old sequence was:
- Write position.
- Write size.
- Write position again.
- Return success.
That sequence had two problems.
First, some AppKit applications recalculate constraints after a move. A size written between two position writes could be dropped or superseded.
Second, Beckon never read the frame back. A position-only move was indistinguishable from a successful layout operation.
I reproduced the failure against real TextEdit and Terminal windows. Position changed. Size did not reliably reach the requested value. That gave me an oracle better than “it looked okay.”
The fix is a verified state transition
Beckon 0.1.6 now uses this sequence:
- Write size.
- Wait one frame.
- Write position.
- Wait one frame.
- Write size again.
- Read back both position and size.
- Retry the full sequence once if any edge is wrong.
- Return an error if the complete frame still does not match.
The comparison covers all four values: x, y, width, and height. A window that only moved can no longer report success.
Beckon also handles AXEnhancedUserInterface, an application-wide Accessibility flag used by some AppKit applications. If the target permits Beckon to disable it temporarily, Beckon must restore it on every exit path. If restoration fails, the operation cannot report clean success. Some applications expose the flag but reject writes, so Beckon proceeds without claiming that the state changed.
That behavior is covered by five state-transition tests:
- disable, operate, restore
- rejected disable with no restore obligation
- failed operation followed by restoration
- successful operation followed by failed restoration
- failed operation combined with failed restoration
The state machine matters because a window command should not leave another application in a changed Accessibility mode.
Center now has a geometry contract
The old Center action preserved the existing window size and only changed its origin.
That is a valid command, but it is not a predictable layout. A tiny window remains tiny. An oversized window remains oversized.
Center now means a centered two-thirds frame:
- width: two-thirds of the visible screen
- height: two-thirds of the visible screen
- x and y: centered within the visible screen
Left Half and Right Half now mean exact tiling against the screen’s visible frame. The calculations use integer segment boundaries so odd screen dimensions still tile without gaps or overlaps.
I tested the window, not a mock of macOS
The deterministic tests model the failure directly. A mock window can acknowledge the first size write and discard it. The test only passes if Beckon retries, verifies all four frame values, and reaches the target.
Mocks are not enough for Accessibility behavior, so I added a hardware test that targets a real application by process ID. It records the original frame, applies a Beckon action, reads back the actual AX frame, compares it to the target, and restores the original frame.
On the release machine, the real Terminal round trips were:
| Action | Verified target |
|---|---|
| Left Half | 864 × 1084 |
| Right Half | 864 × 1084 |
| Center | 1152 × 722 |
Each operation restored the original 900 × 650 frame after verification.
The final release gate ran 379 automated tests. I then ran 20 serial hardware and subprocess smoke tests covering:
- application launch
- real home-directory indexing
- Spotlight fallback
- file activation
- menu enumeration and verified menu actions
- pasteboard round trip
- plugin handshake, timeout, restart, and failure behavior
- window enumeration and focus restoration
- output volume and mute restoration
- exact left, right, and center frame round trips
The distinction matters. The 379 tests make the logic repeatable. The 20 smoke tests prove that macOS and real subprocesses behave the way the logic expects.
The release path needed the same treatment
The first release build passed compilation, tests, and code signing, then failed because scripts/bundle.sh never created a zip archive.
I fixed the script to emit both:
Beckon-v0.1.6.zipBeckon.zip
Both archives are byte-identical. GitHub recorded this SHA-256:
4846713329cf54e70f8503ec53806790b775d7db41cf49a2db64286ef832b158
Homebrew’s live audit then found two more issues in the cask: the minimum macOS version was not declared, and the description redundantly named the platform. I fixed both, reran style and online audit, and performed a real Homebrew upgrade from the previously installed 0.1.0 cask to 0.1.6.
The installed app reported beckon 0.1.6, passed strict code-signature verification, launched from /Applications, and retained its Accessibility permission because the bundle identity stayed stable.
Reproduce it
Install the release:
brew install --cask jonathanpopham/tap/beckon
Build and run the deterministic gate:
git clone https://github.com/jonathanpopham/beckon.git
cd beckon
scripts/verify.sh
Run a hardware window round trip against the frontmost application:
BECKON_WINMGMT_ACTION=window.left-half \
cargo test -p beckon-macos \
winmgmt::tests::hw_apply_action_from_env \
-- --ignored --exact --nocapture
The source, release artifacts, corrected demo, and checksums are on the Beckon 0.1.6 release.
Caveats
Beckon 0.1.6 is ad hoc signed, not notarized. The Homebrew cask clears the quarantine flag and links to the public source.
The hardware verification ran on macOS 26.2. Accessibility behavior can vary by application, especially for constrained, tiled, or full-screen windows. Beckon now reports failure when it cannot verify the target frame, but this release does not claim that every application permits every geometry.
The important change is smaller than that claim: Beckon no longer confuses an acknowledged write with a correct result.
Move the window. Read it back. Prove the frame.