Skip to content

Ship a universal binary with a real macOS floor (1.4.1) - #25

Merged
vimoxshah merged 1 commit into
mainfrom
fix/universal-binary-macos-floor
Sep 16, 2026
Merged

vimoxshah merged 1 commit into
mainfrom
fix/universal-binary-macos-floor

Conversation

@vimoxshah

Copy link
Copy Markdown
Owner

The defect

The macOS app would not launch for most people who installed it.

scripts/build-menubar-app.sh passed no -target, so swiftc set the deployment target from whatever the build machine ran. Once the CI runners moved to macOS 26, every DMG since 1.3.x shipped:

LC_BUILD_VERSION  minos 26.0     arch: arm64 only

while its own Info.plist advertised LSMinimumSystemVersion 13.0 and Casks/tokenflow.rb declared depends_on macos: :ventura. Homebrew installed it happily on Ventura and on Intel Macs, where it could not start at all. Verified on the shipped 1.3.5 and 1.4.0 images — both minos 26.0, both arm64-only.

Why it shipped three times

The swiftc line ended in | head -40. A pipe discards the exit status, so a compile that produced no binary left an empty Contents/MacOS, the script reported success, and the release workflow packaged a DMG around it. Every other fail-loud guarantee in release.yml checks the plist — which was the half that was lying.

The fix

  • Compile once per architecture, lipo into a universal binary.
  • One variable, TOKENFLOW_MACOS_FLOOR (default 13.0), sets both the -target and LSMinimumSystemVersion, so the advertised floor and the compiled floor cannot drift apart.
  • | head -40 removed — a failed compile now stops the build. Verified locally: the script exits 1 and leaves no binary, where before it exited 0.
  • After lipo, the script reads minos and lipo -archs back off the binary it just produced and refuses to continue if either disagrees with the bundle.
  • test/bundle.test.js asserts both on a real build.

Verification

  • bash -n clean; the build fails loudly here (this Mac has no SwiftUI macro plugins) with exit 1 and no binary — the old behaviour was exit 0 with an empty MacOS/.
  • The ServiceManagement block type-checks and links at -target arm64-apple-macos13.0 and -target x86_64-apple-macos13.0 locally, so the login-item code is not what forces the floor up.
  • npm run lint clean, 841 tests / 838 pass / 3 skipped locally.
  • The two macos-latest jobs are the gate. They are the only place the full SwiftUI app compiles, and now the only place the 13.0 floor is proven. If 13.0 does not compile, the diagnostic names the version and TOKENFLOW_MACOS_FLOOR moves in one line — with depends_on macos: in the cask in the same commit.

🤖 Generated with Claude Code

The macOS app would not launch for most people who installed it.

build-menubar-app.sh passed no -target, so swiftc set the deployment target
from the build machine. Once the CI runners moved to macOS 26, every DMG since
1.3.x carried minos 26.0 and an arm64-only binary, while its own Info.plist
advertised 13.0 and the cask declared depends_on macos: :ventura. Homebrew
installed it on Ventura and on Intel Macs, where it could not start.

The binary is now compiled once per architecture and lipo'd into a universal
one. The floor lives in a single variable, TOKENFLOW_MACOS_FLOOR (default
13.0), which also writes LSMinimumSystemVersion, so the advertised floor and
the compiled floor cannot drift apart again.

This shipped three times without failing a release because the swiftc line
ended in `| head -40`: a pipe discards the exit status, so a compile that
produced no binary left an empty Contents/MacOS and the script reported
success. The pipe is gone, and the build now reads minos and the architecture
list back off the binary it produced, failing if either disagrees with the
bundle. test/bundle.test.js asserts both on a real build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vimoxshah
vimoxshah merged commit ec6d3a8 into main Sep 16, 2026
9 checks passed
@vimoxshah
vimoxshah deleted the fix/universal-binary-macos-floor branch September 16, 2026 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant