Repository navigation
chore!: remove the public API of disabled package traits - #975
Merged
turnipdabeets merged 2 commits intoOct 27, 2026
Merged
Conversation
Gate trait-specific public API with the same `!SWIFT_PACKAGE || <Trait>` condition as its implementation, so an SPM app that turns a trait off gets a compile error instead of an option that silently does nothing. - SessionReplay: PostHogConfig.sessionReplay/sessionReplayConfig, PostHogSessionReplayConfig, PostHogSessionReplayConsoleLogConfig, PostHogConsoleLogEntry/Level, start/stopSessionRecording(), isSessionReplayActive(), View.postHogNoMask() and the replay SPI. - CrashReporting: PostHogErrorTrackingConfig.autoCapture. - Surveys: PostHogConfig.surveys/surveysConfig, PostHogSurveysConfig, PostHogSurveysDelegate and its callback typealiases, the display, response and next-question types. Add api/posthog-ios.public-api.no-traits.txt (SPM build with --disable-default-traits), checked by `make apiCheck` in CI and regenerated by `make apiUpdate`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 of 15 tasks
turnipdabeets
marked this pull request as ready for review
October 27, 2026 17:20
Xcode 26.4.1 prints @sendable on five closure types in the SPM symbol graph; CI's Xcode 26.3 doesn't, so apiCheck failed.
This was referenced Oct 27, 2026
Contributor
posthog-ios Compliance ReportDate: 2026-10-27T17:40:08.266622+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 2789ms |
| Format Validation.Event Has Uuid | ✅ | 2786ms |
| Format Validation.Event Has Lib Properties | ✅ | 2842ms |
| Format Validation.Distinct Id Is String | ✅ | 507ms |
| Format Validation.Token Is Present | ✅ | 377ms |
| Format Validation.Custom Properties Preserved | ✅ | 377ms |
| Format Validation.Event Has Timestamp | ✅ | 3012ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ✅ | 2829ms |
| Retry Behavior.Retries On 503 | ✅ | 11412ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 4829ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 4865ms |
| Retry Behavior.Respects Retry After Header | ✅ | 7937ms |
| Retry Behavior.Implements Backoff | ✅ | 21806ms |
| Retry Behavior.Retries On 500 | ✅ | 9365ms |
| Retry Behavior.Retries On 502 | ✅ | 9350ms |
| Retry Behavior.Retries On 504 | ✅ | 9403ms |
| Retry Behavior.Max Retries Respected | ❌ | 21892ms |
| Deduplication.Generates Unique Uuids | ✅ | 682ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 9261ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 16335ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 7924ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 2858ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 2930ms |
| Compression.Sends Gzip When Enabled | ✅ | 2806ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 489ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 299ms |
| Batch Format.Multiple Events Batched Together | ✅ | 3084ms |
| Error Handling.Does Not Retry On 403 | ✅ | 4879ms |
| Error Handling.Does Not Retry On 413 | ✅ | 4813ms |
| Error Handling.Retries On 408 | ✅ | 9190ms |
Failures
retry_behavior.max_retries_respected
Expected 4 requests, got 6
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 2837ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 2906ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 2769ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 2761ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 2877ms |
| Request Payload.Groups Round Trip | ✅ | 2821ms |
| Request Payload.Groups Default To Empty Object | ✅ | 2775ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 2742ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 2793ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 2749ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 100ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 2805ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 5601ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 2771ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 2931ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 2929ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 3138ms |
dustinbyrne
approved these changes
Oct 27, 2026
dustinbyrne
left a comment
Contributor
There was a problem hiding this comment.
Trait-gated public API matches feature availability while preserving manual exception reporting and autocapture masking. No actionable findings.
AI-assisted review.
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
Addresses ioannisj's review on #873 (#873): the
SessionReplay,CrashReportingandSurveyspackage traits gated the implementation but not the public API. With a trait off, an app could setsessionReplay = trueorerrorTrackingConfig.autoCapture = true, compile cleanly, and get nothing but a debug-level.skipped(.disabledByPackageTrait)log.Public API that only works with a trait now uses the same
!SWIFT_PACKAGE || <Trait>condition as its implementation. With the trait off, that code fails to compile instead. CocoaPods, XCFramework and Xcode-project builds (!SWIFT_PACKAGE) and SPM with default traits keep everything, so the default API snapshot is unchanged.Gated symbols
SessionReplayPostHogConfig.sessionReplay,PostHogConfig.sessionReplayConfig,PostHogSessionReplayConfig,PostHogSessionReplayConsoleLogConfig,PostHogConsoleLogEntry,PostHogConsoleLogLevel,PostHogSDK.startSessionRecording(),startSessionRecording(resumeCurrent:),stopSessionRecording(),isSessionReplayActive(),View.postHogNoMask(), and the wrapper SPIcaptureSessionReplaySnapshot(episodeFirstFrame:)/sessionReplayDebugProperties()CrashReportingPostHogErrorTrackingConfig.autoCaptureSurveysPostHogConfig.surveys,PostHogConfig.surveysConfig,PostHogSurveysConfig,PostHogSurveysDelegate,OnPostHogSurveyShown/OnPostHogSurveyResponse/OnPostHogSurveyClosed,PostHogDisplaySurveyand its question/appearance/enum types,PostHogSurveyResponse/PostHogSurveyResponseType,PostHogNextSurveyQuestionJudgment calls:
errorTrackingConfig.autoCaptureis gated, the rest ofPostHogErrorTrackingConfigis not. Error tracking isn't a trait:captureException,inAppIncludes/inAppExcludes/inAppByDefault,ignoredExceptionTypes,exceptionStepsandaddExceptionStepall apply to manual captures.autoCaptureonly installsPostHogErrorTrackingAutoCaptureIntegration. That integration is the PLCrashReporter handler, and it also holds the MetricKit OOM reporter, so withCrashReportingoffautoCapturecan't do anything.postHogMask()stays public;postHogNoMask()is gated.postHogMask()regions also keep SwiftUI tap autocapture out of masked areas (SwiftUITapAutocapturereadsPostHogSessionReplayMaskRegistry), so it still does something with replay off.postHogNoMask()only affects replay. Its internalUIView/CALayerflag helpers stay becauseUIView.isNoMask()is compiled with replay off.captureSessionReplaySnapshotandsessionReplayDebugPropertiessit in the same block asstart/stopSessionRecording(), so they're gated too. Wrappers built with default traits or CocoaPods are unaffected.Internal follow-through: the SDK's replay and survey plumbing (
replayIntegration,startSessionRecordingOnOptIn,installReplayIntegration(),surveysIntegration,getIntegrations()) is gated the same way. That let me delete the trait-offPostHogSurveyIntegrationstub. The trait-offPostHogReplayIntegrationis now an emptyenum, kept only as the namespace for theMaskedRegionhelpers thatpostHogMask()uses. The two tests that checked.skipped(.disabledByPackageTrait)with a trait off are removed, because that path can no longer be reached from public API. The compile-time removal is covered by the new snapshot.Public API snapshot with traits off
scripts/check-public-api.sh --no-traitsbuilds the iOS SDK withswift build --disable-default-traitsand extracts its symbol graph intoapi/posthog-ios.public-api.no-traits.txt, using the same extraction and format as the existing snapshot.make apiChecknow checks both snapshots andmake apiUpdateregenerates both, so the existingPublic API snapshotCI job (make apiCheck) fails if either one drifts. Only the step name changed. CONTRIBUTING.md documents the new file.@Sendableclosure types, and the extra top-levelPostHogDataModemirror in the Xcode build. Every other difference between the files is a symbol from the table above.Spec
sdk-specs has nothing on SwiftPM package traits. This changes compile-time availability in SPM builds, not runtime behavior.
💚 How did you test it?
Ran locally on Xcode 26.4.1. The machine was heavily loaded by parallel builds (load average 140–300).
make lintmake buildSdkSpmNoTraitsmake buildTestsSpmTraitsIOSmake buildSdkSpmscripts/check-public-api.sh --update --no-traitsmake testPostHogStorageTestapp-group tests (sandbox denies writes to the group container),PostHogLogsQueueTest,PostHogSDKTestidentify tests and aPostHogPropertiesSerializationTesttimeout.PostHogSDKTestandPostHogPropertiesSerializationTestpassed when rerun alone.PostHogLogsQueueTesttiming tests fail on the base branch too under the same load.make testNoTraitsPostHogPushNotificationTestpassed when rerun alone.make buildSdk,make apiCheck(default snapshot),make testOniOSSimulatorxcprettyisn't installed on this machine, andxcodebuildcan't resolve the example projects'../posthog-iospackage reference from the agent worktree's directory name. CI covers these. Note that the default snapshot only comes from!SWIFT_PACKAGEbuilds, where every new gate is true.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset fileNo new changeset file. I added a sub-bullet to the existing trait entry under Added in
.changeset/v4-major-release.md. Traits are new in 4.0, so this isn't a break against 3.x.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
chore/v4-remove-deprecated.api/posthog-ios.public-api.txtand checked each candidate's readers. That check is whypostHogMask()(autocapture reads it) and the non-crashPostHogErrorTrackingConfigoptions (manualcaptureExceptionuses them) stay public.make apiCheckinstead, so the existing required check covers it and the local workflow is unchanged.🤖 Generated with Claude Code