Repository navigation
chore!: require Xcode 26 (swift-tools-version 6.2) - #898
Merged
Merged
Conversation
Contributor
|
[High risk] Raises minimum build toolchain from Xcode 15 to Xcode 26. The PR appears safe to merge; no outstanding finding or new actionable issue remains. Reviews (2) · Last reviewed commit: "chore!: require Xcode 26 (swift-tools-ve..." |
turnipdabeets
force-pushed
the
chore/v4-swift-tools-6
branch
from
October 2, 2026 23:13
957839f to
e61747c
Compare
turnipdabeets
changed the base branch from
chore/v4-remove-deprecated
to
chore/v4-min-ios-15
October 2, 2026 23:13
Contributor
posthog-ios Compliance ReportDate: 2026-10-05 22:59:42 UTC
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 2809ms |
| Format Validation.Event Has Uuid | ✅ | 2700ms |
| Format Validation.Event Has Lib Properties | ✅ | 2726ms |
| Format Validation.Distinct Id Is String | ✅ | 2673ms |
| Format Validation.Token Is Present | ✅ | 302ms |
| Format Validation.Custom Properties Preserved | ✅ | 2694ms |
| Format Validation.Event Has Timestamp | ✅ | 238ms |
| Retry Behavior.Retries On 503 | ✅ | 5306ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 4744ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 4753ms |
| Retry Behavior.Respects Retry After Header | ✅ | 7765ms |
| Retry Behavior.Implements Backoff | ✅ | 21232ms |
| Retry Behavior.Retries On 500 | ✅ | 8740ms |
| Retry Behavior.Retries On 502 | ✅ | 5567ms |
| Retry Behavior.Retries On 504 | ✅ | 9266ms |
| Retry Behavior.Max Retries Respected | ❌ | 21786ms |
| Deduplication.Generates Unique Uuids | ✅ | 2807ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 9288ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 16256ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 7728ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 2727ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 2702ms |
| Compression.Sends Gzip When Enabled | ✅ | 2736ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 2729ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 273ms |
| Batch Format.Multiple Events Batched Together | ✅ | 2813ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2368ms |
| Error Handling.Does Not Retry On 413 | ✅ | 4668ms |
| Error Handling.Retries On 408 | ✅ | 5374ms |
Failures
retry_behavior.max_retries_respected
Expected 4 requests, got 6
Feature_Flags Tests
✅ 16/16 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 2800ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 2705ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 2738ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 2649ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 2778ms |
| Request Payload.Groups Round Trip | ✅ | 2662ms |
| Request Payload.Groups Default To Empty Object | ✅ | 2930ms |
| Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It | ✅ | 2740ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 2647ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 2721ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 2773ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 57ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 2708ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 5460ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 2697ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 3003ms |
turnipdabeets
force-pushed
the
chore/v4-swift-tools-6
branch
from
October 5, 2026 16:16
e61747c to
dcd721b
Compare
turnipdabeets
force-pushed
the
chore/v4-min-ios-15
branch
from
October 5, 2026 16:16
7e612e3 to
4f7895b
Compare
turnipdabeets
force-pushed
the
chore/v4-swift-tools-6
branch
from
October 5, 2026 16:42
dcd721b to
3c380b4
Compare
turnipdabeets
force-pushed
the
chore/v4-min-ios-15
branch
from
October 5, 2026 16:42
4f7895b to
8de3767
Compare
turnipdabeets
marked this pull request as ready for review
October 5, 2026 17:14
3 of 5 tasks
dustinbyrne
approved these changes
Oct 5, 2026
Base automatically changed from
chore/v4-min-ios-15
to
chore/v4-remove-deprecated
October 5, 2026 22:47
Collapse Package.swift and Package@swift-5.9.swift into a single swift-tools-version 6.2 manifest that keeps Swift 5 language mode, and drop the compiler-version fallbacks that a Swift 6 floor makes dead. CI's minimum-toolchain, Pods-example and CocoaPods publish jobs move to Xcode 26.0.1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
turnipdabeets
force-pushed
the
chore/v4-swift-tools-6
branch
from
October 5, 2026 22:48
3c380b4 to
4352748
Compare
5 tasks done
turnipdabeets
added a commit
that referenced
this pull request
Oct 7, 2026
Collapse Package.swift and Package@swift-5.9.swift into a single swift-tools-version 6.2 manifest that keeps Swift 5 language mode, and drop the compiler-version fallbacks that a Swift 6 floor makes dead. CI's minimum-toolchain, Pods-example and CocoaPods publish jobs move to Xcode 26.0.1. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
turnipdabeets
added a commit
that referenced
this pull request
Oct 9, 2026
Collapse Package.swift and Package@swift-5.9.swift into a single swift-tools-version 6.2 manifest that keeps Swift 5 language mode, and drop the compiler-version fallbacks that a Swift 6 floor makes dead. CI's minimum-toolchain, Pods-example and CocoaPods publish jobs move to Xcode 26.0.1. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
💡 Motivation and Context
Part of the 4.0 stack, on top of #876.
posthog-ios 4 requires Xcode 26 (swift-tools-version 6.2), matching Apple's App Store Connect upload requirement since April 2026.
Every iOS, iPadOS, tvOS, visionOS and watchOS app that ships through the App Store (including TestFlight) already builds with a Swift 6.2 compiler. Since April 28, 2026, App Store Connect has required Xcode 26 and the 26 SDKs (Apple: upcoming requirements), and Xcode 26 ships Swift 6.2. So this floor costs nothing for any of those apps that reach users through Apple's stores.
Who is excluded: builds that never go through App Store Connect and still use Xcode 16.x or older. That covers enterprise/in-house distribution, local and CI builds, and Mac apps. Apple's notice lists the iOS, iPadOS, tvOS, visionOS and watchOS SDKs, not macOS, so Mac apps on older Xcode, in or out of the Mac App Store, are affected too.
This changes the toolchain/manifest floor only. The SDK still compiles in Swift 5 language mode (
swiftLanguageModes: [.v5]; the podspec keepsswift_versions = "5.3", which Xcode compiles as-swift-version 5). There are no strict-concurrency changes and no public API changes (make apiChecksnapshot unchanged).Why now:
Package.swift(tools 5.3) andPackage@swift-5.9.swiftwere near-copies that had drifted: the 5.3 one lacked.visionOS(.v1)and lacked.macCatalystin thePHPLCrashReporterconditions..iOS(.v15)doesn't evaluate ('v15' is unavailable; it needs PackageDescription 5.5). CI never loads that file, because Swift 5.9+ picks the 5.9 manifest. This PR deletes it.PostHog/only existed for pre-Swift-6 compilers.What this unlocks: optional components
SwiftPM package traits (SE-0450) need tools 6.1+. In the 6.2 manifest API,
Package(traits:)and trait conditions on build settings and target dependencies are available.With one manifest at 6.2, a later 4.x minor could add traits that let SPM users opt out of heavy components without splitting posthog-ios into separate packages. Examples: session replay's libwebp and error tracking's PLCrashReporter (#301, and the "break up SDK in packages" item in #557). Default traits would keep everything on, so adding them would be non-breaking.
This PR adds no traits. CocoaPods has no traits; subspecs would be its equivalent. Whether traits fit our replay and error-tracking code layout (conditional compilation via
#ifon trait-defined conditions) is unverified and needs its own investigation.What changed
Package.swiftat tools 6.2, carrying the 5.9 manifest's content plusswiftLanguageModes: [.v5]. Platform minimums are unchanged from chore!: raise minimum iOS deployment target to 15 #876. None of them (.iOS(.v15),.macOS(.v10_15),.tvOS(.v13),.watchOS(.v6),.visionOS(.v1)) is deprecated in the 6.2 PackageDescription API, and the manifest evaluates without warnings.internal importinstead of@_implementationOnly importinPostHogCrashReportProcessor.swift,PostHogErrorTrackingAutoCaptureIntegration.swift,URLSessionSwizzler.swift,BoxedBeforeSend.swiftandUIImage+WebP.swift. The PrivateModules modulemap pattern is unchanged.internal importneeds no feature flag in Swift 5 mode with a Swift 6 compiler.nonisolated(unsafe)onPostHogSDK.sharedwithout the#if swift(>=5.10)fallback (API snapshot identical).SwiftUITapAutocapture.swiftno longer sits behind#if compiler(>=6.0).compiler(>=6.4)OOM guards stay, because they still gate something.macos-15images (26.0.1 / 17A400, per the runner-images readme):swift buildstep so the manifest is checked at the floor too. It's renamed toBuild SDK (minimum toolchain, Xcode 26.0.1), so if branch protection requires the old check name, it needs updating.Example Pods (Static Lib (Xcode 16.2))job is nowStatic Lib (Xcode 26.0.1)onmacos-15-xlarge. It's renamed too, with the same branch-protection caveat.swift buildstep runsmake buildSdkSpm, whichmake buildSdkalso uses.codeql.yml, PRs tomainonly) moves frommacos-14-xlarge(Xcode 16.2) tomacos-15-xlarge.release.ymlmoved from Xcode 16.2 onmacos-14(which has no Xcode 26) to Xcode 26.0.1 onmacos-15.pod trunk pushdoesn't readPackage.swift, but publishing shouldn't validate on a compiler below the supported floor. Nothing else in the release path runs SwiftPM; the other release jobs are Ubuntu-only.Stacked on #876 (min iOS 15), so the single manifest already has
.iOS(.v15).Wrapper SDKs
Each wrapper was built against this branch through a local override in throwaway copies. Nothing was committed to any wrapper repo.
main, Flutter 3.44.1)Podfile.local→ local path)-swift-version 5, no PostHog warningsPackage.swifttools 5.9 → local path)-swift-version 5, no PostHog warnings). Ran on an iOS 26.4 simulator against a local mock server:/batchreceivedswift6_tools_verify($lib=posthog-flutter)pod 'PostHog', :path)-swift-version 5, no PostHog warnings (not run)posthog.useSpm,spm_dependency→file://repo at this branch)-swift-version 5(not run)main, Kotlin 2.4.20 SwiftPM import)localSwiftPackage(...)in place ofswiftPackage(url=...)iosSimulatorArm64TestOK (38 tests, 0 failures). Sample app not runWrapper ecosystems' own minimum Xcode:
main: 16.1.Apps from all three that ship through App Store Connect are already on Xcode 26.
💚 How did you test it?
After restacking onto #876:
make test(909 Swift Testing + 169 XCTest, 0 failures),make buildSdkandmake apiCheckpass; the manifest evaluates. The wrapper builds below ran before the restack, against iOS 13 minimums.On Xcode 26.4.1 (Swift 6.3.1):
make format/make lint: clean (32 SwiftLint warnings, same as base).make test: 909 Swift Testing tests + 169 XCTest, 0 failures.make buildSdk: iOS, macOS (SPM + xcodebuild), Mac Catalyst, tvOS, watchOS, visionOS.make buildExamples: platform examples, the SPM example (iOS + Catalyst), the XCFramework example, and the Pods static lib / static framework / dynamic framework examples.make apiCheck: snapshot up to date.pod lib lint PostHog.podspec --allow-warnings --skip-tests: passed.DOWNGRADE_REF=3.58.0 make testDowngradeCompatibility: passed. Its tools-5.3 smoke package depends on the 6.2 package.I couldn't test Xcode 26.0.1 locally; the new CI floor job covers it.
📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Claude Code (Opus) did the work and the wrapper verification. Decisions:
swift_versions = "5.3": CocoaPods'swift_versionssets the language mode, and 6.x would turn on Swift 6 checking.--swiftversion 5.3alone to avoid unrelated rewrites.🤖 Generated with Claude Code