Repository navigation
feat: add SessionReplay and CrashReporting package traits - #916
Merged
turnipdabeets merged 8 commits intoOct 9, 2026
Merged
Conversation
Contributor
posthog-ios Compliance ReportDate: 2026-10-09 15:06:22 UTC
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 2931ms |
| Format Validation.Event Has Uuid | ✅ | 2785ms |
| Format Validation.Event Has Lib Properties | ✅ | 464ms |
| Format Validation.Distinct Id Is String | ✅ | 2838ms |
| Format Validation.Token Is Present | ✅ | 2845ms |
| Format Validation.Custom Properties Preserved | ✅ | 2818ms |
| Format Validation.Event Has Timestamp | ✅ | 435ms |
| Retry Behavior.Retries On 503 | ✅ | 11773ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 4846ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 4859ms |
| Retry Behavior.Respects Retry After Header | ✅ | 7758ms |
| Retry Behavior.Implements Backoff | ✅ | 21309ms |
| Retry Behavior.Retries On 500 | ✅ | 9274ms |
| Retry Behavior.Retries On 502 | ✅ | 9329ms |
| Retry Behavior.Retries On 504 | ✅ | 9357ms |
| Retry Behavior.Max Retries Respected | ❌ | 21811ms |
| Deduplication.Generates Unique Uuids | ✅ | 3168ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 9465ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 16423ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 8032ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 2994ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 2955ms |
| Compression.Sends Gzip When Enabled | ✅ | 2757ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 444ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 375ms |
| Batch Format.Multiple Events Batched Together | ✅ | 3056ms |
| Error Handling.Does Not Retry On 403 | ✅ | 5420ms |
| Error Handling.Does Not Retry On 413 | ✅ | 4833ms |
| Error Handling.Retries On 408 | ✅ | 9400ms |
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 | ✅ | 2772ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 2764ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 2968ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 3319ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 2915ms |
| Request Payload.Groups Round Trip | ✅ | 2922ms |
| Request Payload.Groups Default To Empty Object | ✅ | 2826ms |
| Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It | ✅ | 2726ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 2877ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 2942ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 2969ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 344ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 3274ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 5836ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 2934ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 3101ms |
turnipdabeets
marked this pull request as ready for review
October 6, 2026 22:11
dustinbyrne
reviewed
Oct 6, 2026
dustinbyrne
left a comment
Contributor
There was a problem hiding this comment.
The default-on traits preserve existing integrations, and the dependency guards, JPEG fallback, and manual exception filtering look consistent. One small test-target guard remains for the new no-WebP iOS configuration.
AI-assisted review.
Contributor
Author
5 tasks done
turnipdabeets
force-pushed
the
chore/v4-remove-deprecated
branch
from
October 7, 2026 01:44
e1cc8cf to
5b6c50e
Compare
SwiftPM apps can now leave out the vendored libwebp and PLCrashReporter by disabling the traits. Both are on by default, so existing setups are unchanged; CocoaPods and xcodeproj builds always include both. Also moves the ignoredExceptionTypes matcher out of the crash-reporting gate so it applies to manual captures everywhere, which fixes it on watchOS and visionOS. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The WebP test suites called `UIImage.webpData`, which SwiftPM compiles out on iOS when the trait is off, so the test target failed to build. Gate them like the encoder and add a separate encoding test that expects WebP or the JPEG fallback depending on the trait. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`make test` runs on macOS, where the iOS-only trait gates compile out, so a test calling trait-gated SDK code on iOS went unnoticed. Build the iOS test target for the simulator with traits off and with each trait on its own. The concurrent flag reload suite's `.timeLimit` needs iOS 16, so limit it to macOS SwiftPM builds rather than every SwiftPM build. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
turnipdabeets
force-pushed
the
feat/spm-package-traits
branch
from
October 7, 2026 02:05
6823d45 to
8641221
Compare
SessionReplay now gates the whole replay engine along with libwebp, so an app that doesn't use replay can leave all of it out. The public replay API (config, masking modifiers, URLSession helpers, start/stop recording) stays compiled; with the trait off the replay integration is a stub that is skipped with `disabledByPackageTrait`. A finer split (replay without WebP) can come later in a minor release by keeping SessionReplay as an umbrella trait that enables the new ones. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3 of 23 tasks
dustinbyrne
approved these changes
Oct 7, 2026
This was referenced Oct 7, 2026
The session replay suite and the two SDK tests that assert replay debug properties need the replay engine, so skip them in SPM builds with the SessionReplay trait off. Also list buildTestsSpmTraitsIOS for trait-gated changes in the contributor guide. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… feat/spm-package-traits
`.timeLimit` needs iOS 16, above the iOS 15 minimum, so the iOS SwiftPM test build failed after merging the 4.0 base. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat: add Surveys package trait SwiftPM apps that don't use surveys can now leave out the survey engine and UI by disabling the `Surveys` trait. It is on by default, so existing setups are unchanged; CocoaPods and xcodeproj builds always include surveys. The public survey API (`config.surveys`, `surveysConfig`, the delegate protocol and display models) stays compiled. With the trait off, the survey integration is a stub that is skipped with `disabledByPackageTrait`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: note the Surveys trait on surveysConfig and surveysDelegate A custom surveysDelegate is never called when the trait is off, so say so where apps set it. Also drop the unused clearInstalls() from the stub. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
turnipdabeets
added a commit
that referenced
this pull request
Oct 9, 2026
* feat: add SessionReplayWebP and CrashReporting package traits SwiftPM apps can now leave out the vendored libwebp and PLCrashReporter by disabling the traits. Both are on by default, so existing setups are unchanged; CocoaPods and xcodeproj builds always include both. Also moves the ignoredExceptionTypes matcher out of the crash-reporting gate so it applies to manual captures everywhere, which fixes it on watchOS and visionOS. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: gate WebP suites on the SessionReplayWebP trait The WebP test suites called `UIImage.webpData`, which SwiftPM compiles out on iOS when the trait is off, so the test target failed to build. Gate them like the encoder and add a separate encoding test that expects WebP or the JPEG fallback depending on the trait. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci: compile the iOS test target with package traits off `make test` runs on macOS, where the iOS-only trait gates compile out, so a test calling trait-gated SDK code on iOS went unnoticed. Build the iOS test target for the simulator with traits off and with each trait on its own. The concurrent flag reload suite's `.timeLimit` needs iOS 16, so limit it to macOS SwiftPM builds rather than every SwiftPM build. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat!: replace the SessionReplayWebP trait with SessionReplay SessionReplay now gates the whole replay engine along with libwebp, so an app that doesn't use replay can leave all of it out. The public replay API (config, masking modifiers, URLSession helpers, start/stop recording) stays compiled; with the trait off the replay integration is a stub that is skipped with `disabledByPackageTrait`. A finer split (replay without WebP) can come later in a minor release by keeping SessionReplay as an umbrella trait that enables the new ones. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: gate the remaining replay tests on the SessionReplay trait The session replay suite and the two SDK tests that assert replay debug properties need the replay engine, so skip them in SPM builds with the SessionReplay trait off. Also list buildTestsSpmTraitsIOS for trait-gated changes in the contributor guide. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: limit the Swift 6 callback suite's timeLimit to macOS `.timeLimit` needs iOS 16, above the iOS 15 minimum, so the iOS SwiftPM test build failed after merging the 4.0 base. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: add Surveys package trait (#918) * feat: add Surveys package trait SwiftPM apps that don't use surveys can now leave out the survey engine and UI by disabling the `Surveys` trait. It is on by default, so existing setups are unchanged; CocoaPods and xcodeproj builds always include surveys. The public survey API (`config.surveys`, `surveysConfig`, the delegate protocol and display models) stays compiled. With the trait off, the survey integration is a stub that is skipped with `disabledByPackageTrait`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: note the Surveys trait on surveysConfig and surveysDelegate A custom surveysDelegate is never called when the trait is off, so say so where apps set it. Also drop the unused clearInstalls() from the stub. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- 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
Every app that adds PostHog through Swift Package Manager compiles and links session replay with the vendored libwebp, and the vendored PLCrashReporter, even when it never turns on replay or crash autocapture. This adds two package traits, both on by default, so an app can leave either one out:
SessionReplayphlibwebpURLSessionhelpers stay available and do nothingCrashReportingPHPLCrashReportercaptureExceptionstill worksListing traits replaces the defaults, so an app names the traits it wants to keep.
traits: []turns both off.A small iOS arm64 Release app that links the SDK dynamically, stripped:
["CrashReporting"][]The traits are on by default, so existing SPM setups don't change. CocoaPods and xcodeproj builds always include both, because the gates are
#if !SWIFT_PACKAGE || <Trait>. Traits needswift-tools-version6.1+, which is why this stacks on the 6.2 bump in #898.What changes:
SessionReplayoff, the iOS replay engine files are compiled out andPostHogReplayIntegrationis a stub that is skipped withdisabledByPackageTrait. The public replay API stays compiled:config.sessionReplay,sessionReplayConfig, the console log types, the SwiftUI/UIKit masking modifiers, theURLSessionhelpers,startSessionRecording/stopSessionRecording. Code using it keeps compiling, andisSessionReplayActive()returnsfalse.imageToBase64(SPI, used by the wrapper SDKs) stays and falls back to JPEG.CrashReportingoff, the autocapture integration becomes the existing watchOS/visionOS stub. It logsskipped: Disabled by a package traitwhenconfig.debugis on.sessionReplay,sessionReplayConfigandautoCapturedocs mention their trait.exceptionListMatchesIgnoredTypesmoved out of the crash-reporting gate, soignoredExceptionTypesapplies to manual captures in every build. This also fixes it on watchOS and visionOS, where the stub always returnedfalse. It has its own patch changeset.spm-no-traitsbuild entry (macOS, plus an iOS cross-build viaswift build --triple), atest-no-traitsjob, and a traits-off step in the Xcode 26.0.1 job, throughmake buildSdkSpmNoTraitsandmake testNoTraits. Thespm-no-traitsentry also runsmake buildTestsSpmTraitsIOS, which compiles the iOS test target for the simulator with traits off,CrashReportingonly andSessionReplayonly. To make that compile, the concurrent flag reload suite's iOS 16-only.timeLimitis limited to macOS SwiftPM builds.Why one
SessionReplaytrait rather than a WebP-only one: dropping libwebp but keeping replay saves less and makes replay upload bigger JPEG frames. Nobody has asked for that, and libwebp's symbols are already prefixed, so it can't clash with another copy. If it's ever wanted, a minor release can addSessionReplayCoreandSessionReplayWebPand keepSessionReplayas an umbrella that enables both. Apps that listSessionReplaykeep the same behavior; I checked that with scratch packages. The reverse doesn't hold: once released, a new default-on trait added on its own silently turns its feature off for apps that list traits. AGENTS.md now records that rule.I considered splitting replay and error tracking into separate modules, as #557 suggests, and rejected it. It would break
imports and moveconfig.sessionReplayConfigandconfig.errorTrackingConfig, and the wrapper SDKs would need changes. Traits get the size win without any of that.Things to know:
Package.swiftwork. I only verified that path.CrashReportingalso turns off iOS 27+ out-of-memory autocapture. That reporter uses MetricKit, not PLCrashReporter, but it lives inside the same integration.Surveystrait on top of this. Both need to ship in 4.0 for the reason above.Closes #301. Part of #557. Stacked on #873.
💚 How did you test it?
On the current commit:
make lintpasses with the same warnings as the base branch.make apiCheckpasses, and the public API snapshot is unchanged.swift build --target PostHogpasses for macOS with traits off and with defaults, and for iOS with defaults,CrashReportingonly, and traits off.make buildTestsSpmTraitsIOScompiles the iOS test target with traits off,CrashReportingonly andSessionReplayonly.make testNoTraits filter=IntegrationInstallationpasses, including the "skipped when the CrashReporting trait is disabled" test.nm: with["CrashReporting"]it links no libwebp or replay capture symbols, and with[]it also links no PLCrashReporter symbols. Sizes are in the table above.On the earlier
SessionReplayWebPrevision, not rerun since:make buildSdkfor iOS, macOS, Mac Catalyst, tvOS, watchOS and visionOS.make testOniOSSimulator,make testandmake testNoTraits. The only failures were the 13PostHogStorageapp-group tests on macOS, which fail the same way on the base on this machine and pass in the simulator.Not tested: the replay stub's skip with the trait off. No lane runs the iOS tests through SwiftPM with traits off, so it's compile-checked only, like the JPEG encoding path. Also not tested: Xcode 26.0.1 locally (CI covers it) and choosing traits from an Xcode app project.
📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
SessionReplayafter measuring per-feature code size and confirming that a later split under an umbrella trait stays compatible.SWIFT_PACKAGEisn't a Swift condition in the xcodeproj or podspec, so non-SPM builds keep both libraries. It also found that the macOS no-traits build still compiled both vendored libraries; that's fixed with--target PostHog. A watchOS test for theignoredExceptionTypesfix is still deferred; no lane runs it today.🤖 Generated with Claude Code