Skip to content

ci: pin macOS wheel runners to macos-15 - #19

Merged
trendvidia merged 1 commit into
mainfrom
ci/pin-macos-15-wheel-runners
Aug 31, 2026
Merged

trendvidia merged 1 commit into
mainfrom
ci/pin-macos-15-wheel-runners

Conversation

@trendvidia

@trendvidia trendvidia commented Aug 31, 2026 •

Copy link
Copy Markdown
Owner

Fixes #18.

macos-latest rolled forward to macOS 26 (Tahoe) in July 2026. Homebrew's bottled
protobuf/abseil now target 26.0, while both workflows build the wheel against
MACOSX_DEPLOYMENT_TARGET: "15.0" — and delocate refuses to bundle dylibs whose
min target is newer than the wheel's:

delocate.libsana.DelocationError: Library dependencies do not satisfy target MacOS version 15.0:
  .../protowire/.dylibs/libprotobuf.35.1.0.dylib has a minimum target of 26.0
  .../protowire/.dylibs/libabsl_*.2601.0.0.dylib has a minimum target of 26.0

This pins the two wheel-building matrices to macos-15, so the runner image and
the deployment target agree again.

Why pin the runner rather than raise the target

Raising MACOSX_DEPLOYMENT_TARGET to 26.0 is the other one-line fix, and it is the
wrong one to take silently: it would set the published wheel's macOS support floor to
26, dropping every macOS user below it. That is a release decision, not a CI fix.
Pinning restores green while leaving the support matrix exactly where it is.

Discussed as option (b) in #18; option (c) — building protobuf/absl from source at the
chosen target, as the Linux leg already does — is the durable fix that decouples the
support floor from the runner image entirely. Filed separately as #20.

Both halves, not just the visible one

publish.yml carried the identical pin on the release path. It is latent — no tag has
been pushed since the breakage — so nothing was visibly failing there, but the next
release would have failed the macOS wheel leg identically. Fixed here too.

ci.yml's test matrix deliberately stays on macos-latest: it installs editable
and never runs delocate, so it is unaffected, and it keeps exercising newest-macOS.

On the stale comments

Both files carried a comment asserting macos-latest = 15. That assumption is what
expired, and because it lived only in a comment it expired silently — the job went red
for six weeks with main never visibly failing (no pushes to main between 2026-05-30 and
2026-08-31, so only dependabot PRs ran CI, where the red X read as "the bump is broken").
Replaced with comments stating that the runner image and the deployment target are a
single decision, so the pair gets changed together or not at all.

Evidence

Pre-fix, cibuildwheel smoke / macos-latest failed identically on main @ 954e9b0
(run 33439745254)
and on both open dependabot PRs #15 and #17 — same job, same DelocationError. Every
other leg was green on all three.

Post-fix CI evidence is posted as a comment below once this PR's run completes.

Follow-on

#15 and #17 are both clean and were only ever red from this. Once this lands they should
go green on rebase and can be merged normally. Worth noting #17 has already demonstrated
cibuildwheel 4.2.0 works on the Linux and Windows legs; macOS was the only untested one,
for this reason.

GitHub rolled macos-latest forward to macOS 26 (Tahoe) in July 2026.
Homebrew's bottled protobuf/abseil are now built with a minimum target
of 26.0, but both workflows set the wheel's MACOSX_DEPLOYMENT_TARGET to
15.0. delocate refuses to bundle dylibs whose min target is newer than
the wheel's, so the macOS wheel build has failed since:

  delocate.libsana.DelocationError: Library dependencies do not satisfy
  target MacOS version 15.0:
    .../libprotobuf.35.1.0.dylib has a minimum target of 26.0
    .../libabsl_*.2601.0.0.dylib has a minimum target of 26.0

Pin the two wheel-building matrices to macos-15 so the runner image and
the deployment target agree again. This keeps the published wheel's macOS
support floor exactly where it is; bumping the target to 26.0 instead
would drop every macOS user below 26, which is a release decision rather
than a CI fix.

Both halves are fixed, not just the visible one. publish.yml carried the
identical pin on the release path — latent only because no tag has been
pushed since it broke; the next release would have failed the same way.

ci.yml's test matrix stays on macos-latest: it installs editable and
never runs delocate, so it is unaffected and keeps testing newest-macOS.

The stale "macos-latest = 15" comments are replaced with ones stating
that the runner image and the deployment target are a single decision,
so the next reader changes them together or not at all.

Fixes #18

Claude-Session: https://claude.ai/code/session_01EshKcwQsY1Mf6qhrckL95u
@trendvidia

Copy link
Copy Markdown
Owner Author

CI evidence — all 18 checks green

Run 33443842524 on 521621c.

Analyze (cpp): pass                      macos-latest / py3.10: pass
Analyze (python): pass                   macos-latest / py3.11: pass
CodeQL: pass                             macos-latest / py3.12: pass
cibuildwheel smoke / macos-15: pass      macos-latest / py3.13: pass
cibuildwheel smoke / ubuntu-latest: pass ubuntu-latest / py3.10-3.13: pass
cibuildwheel smoke / windows-latest: pass windows-latest / py3.10-3.13: pass

The mechanism, before and after

The Homebrew bottle actually poured on the runner is the whole story:

bottle macOS
before — main @ 954e9b0, macos-latest protobuf--35.1.arm64_tahoe.bottle
abseil--20260107.1.arm64_tahoe.bottle
Tahoe = 26
after — this PR, macos-15 protobuf--35.1.arm64_sequoia.bottle
abseil--20260107.1.arm64_sequoia.bottle
Sequoia = 15

Same package versions (protobuf 35.1, abseil 20260107.1) — only the bottle's target OS
changed, which is exactly what the deployment target has to match.

delocate now succeeds

*** Created protowire_python-1.0.0-cp312-cp312-macosx_11_0_arm64.whl
Repairing wheel...
+ delocate-wheel --require-archs arm64 -w .../repaired_wheel .../protowire_python-1.0.0-cp312-cp312-macosx_11_0_arm64.whl
  cp312-macosx_arm64: protowire_python-1.0.0-cp312-cp312-macosx_15_0_arm64.whl 1.7 MB in 3 minutes,
  SHA256=9b058220335753153e9164a897107d757efac5fdc6a99e757af661be7e14ca51

No DelocationError; the repair step completed and emitted a wheel.

The support floor is unchanged — which was the point

The repaired wheel is tagged macosx_15_0_arm64, not macosx_26_0_arm64. That is the
check that distinguishes this fix from the raise-the-target alternative: both turn CI
green, but only this one leaves the published wheel installable on macOS 15 and up.

Scope of what is proven

The smoke job builds cp312 only, by design. The full release matrix
(cp310-cp313) still runs only on tag push via publish.yml, so publish.yml's
half of this fix is verified by inspection and by the shared mechanism above, not
by a green release run. Flagging that gap explicitly rather than implying the
release path has been exercised.

@trendvidia
trendvidia merged commit 8a1fc1b into main Aug 31, 2026
18 checks passed
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.

ci: macOS wheel build broken — macos-latest moved to macOS 26, MACOSX_DEPLOYMENT_TARGET pinned to 15.0

2 participants