Skip to content

feature: Added Filtering and Rate Limiting#1073

Draft
hollyschilling-cio wants to merge 21 commits into
mainfrom
hs/AggEngine
Draft

feature: Added Filtering and Rate Limiting#1073
hollyschilling-cio wants to merge 21 commits into
mainfrom
hs/AggEngine

Conversation

@hollyschilling-cio

@hollyschilling-cio hollyschilling-cio commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

MBL-1747
This PR adds Filtering and Rate Limiting through an aggregation engine. The aggregation engine pulls its config from the Segment config pulled from https://{cdnHost}/projects/{writeKey}/settings using values passed as integrations.aggregationRules.

The largest change introduced here is the addition of a dependency to have a local database. This is not yet handled in the Cocoapods, but we will update this PR to accommodate that before merging.

Complete each step to get your pull request merged in. Learn more about the workflow this project uses.

  • Assign members of your team to review the pull request.
  • Wait for pull request status checks to complete. If there are problems, fix them until you see that all status checks are passing.
  • Wait until the pull request has been reviewed and approved by a teammate
  • After code reviews are approved and you determine this PR is ready to merge, select Squash and Merge button on this screen, leave the title and description to the default values, then merge the PR.

Note

High Risk
Changes which analytics events are sent (server-controlled drops and rate limits) and adds encrypted on-disk persistence keyed by the CDP API key; misconfiguration or storage issues could alter customer data delivery until CocoaPods parity is done.

Overview
Adds server-driven event filtering and rate limiting for Data Pipelines via Segment/CDP settings (aggregationRules on the Customer.io Data Pipelines integration). Rules are cached in a new encrypted local SQLCipher database (SyncSqlCipher), registered at DataPipeline.initialize, and applied by an EventPolicyPlugin that can drop track, screen, identify, alias, and group events before they leave the client.

StorageManager opens a per–CDP API key DB under Application Support, runs aggregation schema migrations, and stores rules plus rate-limit counters (profile vs device scope). EventPolicyEngine evaluates block lists and time windows (including * wildcards); storage errors fail open so events are not silently dropped. Settings refresh updates the engine and persists or deletes cached rules; clearIdentify clears profile-scoped rate-limit state only.

SPM now depends on SyncSqlCipher and bumps the Swift tools version to 5.10; CocoaPods wiring for the DB is called out as follow-up in the PR description. Broad unit tests cover decoding, engine, plugin, storage, and identify reset.

Reviewed by Cursor Bugbot for commit 43b4501. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Sample app builds 📱

Below you will find the list of the latest versions of the sample apps.
It's recommended to always download the latest builds to test this PR accurately.

@hollyschilling-cio hollyschilling-cio marked this pull request as ready for review June 2, 2026 01:15
@hollyschilling-cio hollyschilling-cio requested a review from a team as a code owner June 2, 2026 01:15
@codecov

codecov Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.83665% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.50%. Comparing base (174e133) to head (9061e1e).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
Sources/Common/Storage/StorageManager.swift 78.00% 11 Missing ⚠️
...urces/DataPipeline/Plugins/EventPolicyPlugin.swift 84.61% 6 Missing ⚠️
Sources/Common/DIGraphShared+StorageManager.swift 86.20% 4 Missing ⚠️
...rces/DataPipeline/DataPipelineImplementation.swift 89.47% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1073      +/-   ##
==========================================
+ Coverage   70.47%   70.50%   +0.03%     
==========================================
  Files         224      231       +7     
  Lines       11542    11803     +261     
==========================================
+ Hits         8134     8322     +188     
- Misses       3408     3481      +73     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread Sources/DataPipeline/Plugins/EventPolicyPlugin.swift
Comment thread Sources/DataPipeline/DataPipelineImplementation.swift
Comment thread Sources/DataPipeline/Storage/StorageManager+Aggregation.swift
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

SDK binary size reports 📊

SDK binary size of this PR
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  14.6%   185Ki  14.6%   185Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/autogenerated/AutoMockable.generated.swift
   4.6%  58.7Ki   4.6%  58.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/autogenerated/AutoMockable.generated.swift
   2.4%  30.9Ki   2.4%  30.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/MessagingPush.swift
   2.3%  28.6Ki   2.3%  28.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Storage/StorageManager.swift
   2.2%  27.9Ki   2.2%  27.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/InAppMessageMiddleware.swift
   1.9%  24.7Ki   1.9%  24.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/Event.swift
   1.8%  23.1Ki   1.8%  23.1Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/AnonymousMessageManager.swift
   1.8%  22.7Ki   1.8%  22.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/SseConnectionManager.swift
   1.7%  21.3Ki   1.7%  21.3Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/autogenerated/AutoMockable.generated.swift
   1.6%  20.4Ki   1.6%  20.4Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Migration/autogenerated/AutoMockable.generated.swift
   1.5%  19.2Ki   1.5%  19.2Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/QueueStorage.swift
   1.4%  17.8Ki   1.4%  17.8Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/InAppMessageAction.swift
   1.4%  17.6Ki   1.4%  17.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/AnyEncodable.swift
   1.3%  16.8Ki   1.3%  16.8Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/SseEventParser.swift
   1.3%  16.5Ki   1.3%  16.5Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/autogenerated/AutoMockable.generated.swift
   1.2%  15.6Ki   1.2%  15.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/InAppMessageManager.swift
   1.2%  15.2Ki   1.2%  15.2Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Inbox/DefaultNotificationInbox.swift
   1.2%  14.9Ki   1.2%  14.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/MessagingInApp.swift
   1.1%  14.6Ki   1.1%  14.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipeline.swift
   1.1%  13.5Ki   1.1%  13.5Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Push/PendingPushDeliveryStore.swift
   1.0%  13.0Ki   1.0%  13.0Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/autogenerated/AutoDependencyInjection.generated.swift
   1.0%  12.9Ki   1.0%  12.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipelineImplementation.swift
   1.0%  12.7Ki   1.0%  12.7Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/MessageManager.swift
   1.0%  12.6Ki   1.0%  12.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/CustomerIOInstance.swift
   1.0%  12.1Ki   1.0%  12.1Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/SseService.swift
   0.9%  12.0Ki   0.9%  12.0Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventStorage.swift
   0.9%  11.9Ki   0.9%  11.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/InAppMessageState.swift
   0.9%  10.9Ki   0.9%  10.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/TrackDeliveryEventRequestBody.swift
   0.8%  10.2Ki   0.8%  10.2Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/QueueManager.swift
   0.8%  10.2Ki   0.8%  10.2Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/SseLifecycleManager.swift
   0.8%  10.1Ki   0.8%  10.1Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventBusHandler.swift
   0.8%  10.0Ki   0.8%  10.0Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/InAppMessageReducer.swift
   0.8%  9.95Ki   0.8%  9.95Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/NSEPushCoordinator.swift
   0.8%  9.92Ki   0.8%  9.92Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipelineImplementation+BGQ.swift
   0.8%  9.63Ki   0.8%  9.63Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Gist.swift
   0.7%  9.41Ki   0.7%  9.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/EventPolicy/AggregationRuleset.swift
   0.7%  9.27Ki   0.7%  9.27Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/autogenerated/AutoDependencyInjection.generated.swift
   0.7%  8.96Ki   0.7%  8.96Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/JsonAdapter.swift
   0.7%  8.91Ki   0.7%  8.91Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWeb.swift
   0.7%  8.87Ki   0.7%  8.87Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Type/PushNotification.swift
   0.7%  8.72Ki   0.7%  8.73Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIGraphShared.swift
   0.7%  8.47Ki   0.7%  8.47Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/SseRetryHelper.swift
   0.7%  8.43Ki   0.7%  8.43Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/MessagingPushImplementation.swift
   0.7%  8.30Ki   0.7%  8.30Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/URLComponents.swift
   0.6%  8.16Ki   0.6%  8.16Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/CoreLocationProvider.swift
   0.6%  7.47Ki   0.6%  7.47Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/KeyValueStorage.swift
   0.6%  7.21Ki   0.6%  7.21Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/UserNotificationsFramework/Wrappers.swift
   0.6%  7.07Ki   0.6%  7.07Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushHttpClient.swift
   0.6%  7.06Ki   0.6%  7.06Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventMemoryStorage.swift
   0.6%  6.99Ki   0.6%  6.99Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/FileLastLocationStateStore.swift
   0.5%  6.95Ki   0.5%  6.95Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Views/GistInlineInAppMessageView.swift
   0.5%  6.91Ki   0.5%  6.91Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/EventPolicyPlugin.swift
   0.5%  6.91Ki   0.5%  6.91Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Migration/DataPipelineMigrationAssistant.swift
   0.5%  6.75Ki   0.5%  6.75Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/AutoTrackingScreenViews.swift
   0.5%  6.72Ki   0.5%  6.72Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventBus.swift
   0.5%  6.54Ki   0.5%  6.54Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/LastLocationState.swift
   0.5%  6.42Ki   0.5%  6.42Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/ModalViewManager.swift
   0.5%  6.41Ki   0.5%  6.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/LocationServices.swift
   0.5%  6.25Ki   0.5%  6.25Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Views/UIKitInline.swift
   0.5%  6.10Ki   0.5%  6.10Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Inbox/Type/InboxMessage.swift
   0.5%  5.99Ki   0.5%  5.99Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Integration/CioProviderAgnosticAppDelegate.swift
   0.5%  5.86Ki   0.5%  5.86Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Storage/StorageManager+Aggregation.swift
   0.4%  5.56Ki   0.4%  5.56Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/EventPolicy/EventPolicyEngine.swift
   0.4%  5.41Ki   0.4%  5.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Push/PendingPushDeliveryMetric.swift
   0.4%  5.38Ki   0.4%  5.38Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTaskMetadata.swift
   0.4%  5.14Ki   0.4%  5.14Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Config/SDKConfigBuilder.swift
   0.4%  5.11Ki   0.4%  5.11Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Views/SwiftUIInline.swift
   0.4%  5.00Ki   0.4%  5.00Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/InAppMessageStore.swift
   0.4%  4.91Ki   0.4%  4.91Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Response/ErrorMessageResponse.swift
   0.4%  4.89Ki   0.4%  4.89Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/autogenerated/AutoMockable.generated.swift
   0.4%  4.89Ki   0.4%  4.89Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/HeartbeatTimer.swift
   0.4%  4.78Ki   0.4%  4.78Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Migration/TrackEventMigrationType.swift
   0.4%  4.70Ki   0.4%  4.70Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/InlineMessageManager.swift
   0.4%  4.53Ki   0.4%  4.53Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/Models/Message.swift
   0.3%  4.34Ki   0.3%  4.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/AsyncOperation.swift
   0.3%  4.17Ki   0.3%  4.17Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Config/MessagingPushConfigBuilder.swift
   0.3%  4.05Ki   0.3%  4.05Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Views/InlineMessageBridgeView.swift
   0.3%  4.02Ki   0.3%  4.02Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/LastLocationStorage.swift
   0.3%  3.96Ki   0.3%  3.96Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Queue.swift
   0.3%  3.81Ki   0.3%  3.81Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/MetricRequest.swift
   0.3%  3.60Ki   0.3%  3.60Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/GistDelegate.swift
   0.3%  3.49Ki   0.3%  3.49Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTask.swift
   0.3%  3.48Ki   0.3%  3.48Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/HttpRequestRunner.swift
   0.3%  3.47Ki   0.3%  3.47Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Log.swift
   0.3%  3.45Ki   0.3%  3.45Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Inbox/Network/InboxMessageResponse.swift
   0.3%  3.39Ki   0.3%  3.39Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Atomic.swift
   0.3%  3.38Ki   0.3%  3.38Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized+Collections.swift
   0.3%  3.35Ki   0.3%  3.35Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Integration/CioNotificationCenterDelegate.swift
   0.3%  3.32Ki   0.3%  3.32Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Views/GistModalViewController.swift
   0.3%  3.26Ki   0.3%  3.27Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/LocationModuleState.swift
   0.3%  3.26Ki   0.3%  3.26Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/NSEPushCoordinatorState.swift
   0.3%  3.25Ki   0.3%  3.25Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/MessageTracking.swift
   0.3%  3.23Ki   0.3%  3.23Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/StringExtensions.swift
   0.3%  3.20Ki   0.3%  3.20Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/BaseNetwork.swift
   0.2%  3.16Ki   0.2%  3.16Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Module/ModuleTopLevelObject.swift
   0.2%  3.12Ki   0.2%  3.12Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushDeliveryTracker.swift
   0.2%  3.11Ki   0.2%  3.11Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/DeviceContexualAttributes.swift
   0.2%  3.09Ki   0.2%  3.09Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/ModalMessageManager.swift
   0.2%  3.03Ki   0.2%  3.03Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/LockManager.swift
   0.2%  3.01Ki   0.2%  3.01Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/GistQueueNetwork.swift
   0.2%  2.96Ki   0.2%  2.96Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushRequestHandler.swift
   0.2%  2.92Ki   0.2%  2.92Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWebConfiguration.swift
   0.2%  2.82Ki   0.2%  2.82Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/FileStorage.swift
   0.2%  2.79Ki   0.2%  2.79Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/MessagingInAppImplementation.swift
   0.2%  2.74Ki   0.2%  2.74Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DeviceInfo.swift
   0.2%  2.70Ki   0.2%  2.70Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/StringAnyEncodable.swift
   0.2%  2.57Ki   0.2%  2.57Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/HttpRequestError.swift
   0.2%  2.56Ki   0.2%  2.56Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/HttpRequestParams.swift
   0.2%  2.52Ki   0.2%  2.52Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DateExtensions.swift
   0.2%  2.50Ki   0.2%  2.50Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Type/LocationProviderTypes.swift
   0.2%  2.49Ki   0.2%  2.49Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Inbox/Type/InboxMessageFactory.swift
   0.2%  2.40Ki   0.2%  2.40Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized+Dictionaries.swift
   0.2%  2.40Ki   0.2%  2.40Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIGraphShared+PendingPushDeliveryStore.swift
   0.2%  2.35Ki   0.2%  2.35Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/IdentifyContextPlugin.swift
   0.2%  2.30Ki   0.2%  2.30Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineEventHandler.swift
   0.2%  2.27Ki   0.2%  2.27Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/Context.swift
   0.2%  2.22Ki   0.2%  2.22Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/Core/Subscription.swift
   0.2%  2.21Ki   0.2%  2.21Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Util/PushNotificationLogger.swift
   0.2%  2.20Ki   0.2%  2.20Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/SystemLogger.swift
   0.2%  2.13Ki   0.2%  2.13Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/DeletePushNotificationQueueTaskData.swift
   0.2%  2.12Ki   0.2%  2.12Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Util/DeviceAttributesProvider.swift
   0.2%  2.11Ki   0.2%  2.11Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/DataPipelinePublishedEvents.swift
   0.2%  2.08Ki   0.2%  2.08Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/IdentifyProfileQueueTaskData.swift
   0.2%  2.06Ki   0.2%  2.06Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/SdkCommonLoggerLogger.swift
   0.2%  2.02Ki   0.2%  2.02Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/RegisterPushNotificationQueueTaskData.swift
   0.2%  2.00Ki   0.2%  2.00Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/autogenerated/AutoDependencyInjection.generated.swift
   0.2%  2.00Ki   0.2%  2.00Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/Integration/CioAppDelegateAPN.swift
   0.2%  1.97Ki   0.2%  1.97Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/KeyValueStorageKey.swift
   0.1%  1.86Ki   0.1%  1.86Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTaskRunResults.swift
   0.1%  1.86Ki   0.1%  1.86Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized.swift
   0.1%  1.82Ki   0.1%  1.82Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/CustomerIO+Events.swift
   0.1%  1.65Ki   0.1%  1.65Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIGraphShared+StorageManager.swift
   0.1%  1.65Ki   0.1%  1.65Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Util/DictionarySanitizer.swift
   0.1%  1.63Ki   0.1%  1.63Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/NSEDeliveryContinuationBox.swift
   0.1%  1.59Ki   0.1%  1.59Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Models/InAppMessageResponse.swift
   0.1%  1.55Ki   0.1%  1.55Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/LocationLifecycleObserver.swift
   0.1%  1.52Ki   0.1%  1.52Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/PushClickHandler.swift
   0.1%  1.47Ki   0.1%  1.47Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Util/DataPipelinesLogger.swift
   0.1%  1.46Ki   0.1%  1.46Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/Event+Location.swift
   0.1%  1.43Ki   0.1%  1.43Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DictionaryExtension.swift
   0.1%  1.41Ki   0.1%  1.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Task Data/TrackEventQueueTaskData.swift
   0.1%  1.41Ki   0.1%  1.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Views/GistView.swift
   0.1%  1.38Ki   0.1%  1.38Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/PushMetric.swift
   0.1%  1.37Ki   0.1%  1.37Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/ManualPushHandling+UserNotifications.swift
   0.1%  1.34Ki   0.1%  1.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/CustomerIO.swift
   0.1%  1.34Ki   0.1%  1.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Storage/StorageManager+EventPolicy.swift
   0.1%  1.31Ki   0.1%  1.31Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Config/MessagingInAppConfigBuilder.swift
   0.1%  1.31Ki   0.1%  1.31Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Extensions/GistExtensions.swift
   0.1%  1.06Ki   0.1%  1.28Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DeviceExtension.swift
   0.1%  1.27Ki   0.1%  1.27Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTaskType.swift
   0.1%  1.25Ki   0.1%  1.25Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/UIColor+Hex.swift
   0.1%  1.24Ki   0.1%  1.24Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/ThreadUtil.swift
   0.1%  1.20Ki   0.1%  1.20Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/LogManager.swift
   0.1%  1.14Ki   0.1%  1.14Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Models/QueueMessagesResponse.swift
   0.1%  1.12Ki   0.1%  1.12Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/InAppMetric.swift
   0.1%  1.11Ki   0.1%  1.11Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/RealAppLifecycleNotifying.swift
   0.1%  1.09Ki   0.1%  1.09Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/CustomerIO+Segment.swift
   0.1%  1.07Ki   0.1%  1.08Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/MessagingPushAPN.swift
   0.1%  1.08Ki   0.1%  1.08Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushRequest.swift
   0.1%  1.06Ki   0.1%  1.06Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Util/ProfileEnrichmentAttributesMerger.swift
   0.1%  1.04Ki   0.1%  1.04Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/LocationFilter.swift
   0.1%  1.04Ki   0.1%  1.04Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/UIKitWrapper.swift
   0.1%  1.01Ki   0.1%  1.01Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/LogEndpoint.swift
   0.1%  1.01Ki   0.1%  1.01Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Type/ScreenView.swift
   0.1%    1008   0.1%    1008    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/GlobalDataStore.swift
   0.1%    1008   0.1%    1008    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Config/DataPipelineConfigOptions.swift
   0.1%     980   0.1%     980    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/SdkClient.swift
   0.1%     980   0.1%     980    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/LocationProfileEnrichmentProvider.swift
   0.1%     972   0.1%     972    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Push/AppGroupIdentifier.swift
   0.1%     924   0.1%     924    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/CIOApiEndpoint.swift
   0.1%     908   0.1%     908    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/PushHandling/RichPushDeliveryTracking.swift
   0.1%     876   0.1%     876    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/UserAgentUtil.swift
   0.1%     836   0.1%     836    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Managers/InboxMessageCacheManager.swift
   0.1%     828   0.1%     828    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Logger+Location.swift
   0.1%     784   0.1%     784    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/SdkConfig.swift
   0.1%     768   0.1%     768    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/MockCollection.swift
   0.1%     740   0.1%     740    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/MessagingPushAPN+PushConfigs.swift
   0.1%     732   0.1%     732    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Type/CustomerIOParsedPushPayload.swift
   0.1%     672   0.1%     672    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/ProfileEnrichment/ProfileEnrichmentRegistryImpl.swift
   0.1%     664   0.1%     664    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/LocationSyncCoordinator.swift
   0.0%     612   0.0%     612    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DeepLinkUtil.swift
   0.0%     596   0.0%     596    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/Config/MessagingPushConfigOptions.swift
   0.0%     596   0.0%     596    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/UserNotificationsFramework/UserNotificationsFrameworkAdapter.swift
   0.0%     592   0.0%     592    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPushAPN/MessagingPush+APN.swift
   0.0%     564   0.0%     564    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Extensions/UIViewExtensions.swift
   0.0%     548   0.0%     548    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/Request/EmptyRequestBody.swift
   0.0%     524   0.0%     524    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/ScreenFilterPlugin.swift
   0.0%     524   0.0%     524    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/RichPush/RichPushRequestHandling.swift
   0.0%     520   0.0%     520    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Type/Region.swift
   0.0%     516   0.0%     516    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/Logger.swift
   0.0%     508   0.0%     508    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/UIKitExtensions.swift
   0.0%     468   0.0%     468    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/Encodable.swift
   0.0%     460   0.0%     460    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/Environment.swift
   0.0%     444   0.0%     444    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized+Hashable.swift
   0.0%     440   0.0%     440    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/ProfileStore.swift
   0.0%     436   0.0%     436    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Utilities/HTTPMethod.swift
   0.0%     428   0.0%     428    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/LocationModule.swift
   0.0%     416   0.0%     416    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/RingBuffer.swift
   0.0%     416   0.0%     416    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Utilities/ElapsedTimer.swift
   0.0%     404   0.0%     404    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/autogenerated/AutoDependencyInjection.generated.swift
   0.0%     392   0.0%     392    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized+Equatable.swift
   0.0%     384   0.0%     384    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/Core/Store.swift
   0.0%     380   0.0%     380    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/ArrayExtensions.swift
   0.0%     380   0.0%     380    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/Core/StoreSubscriber.swift
   0.0%     364   0.0%     364    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Store/QueueInventoryMemoryStore.swift
   0.0%     356   0.0%     356    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueStatus.swift
   0.0%     352   0.0%     352    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/UserDefaultExtensions.swift
   0.0%     228   0.0%     348    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SessionManager.swift
   0.0%     324   0.0%     324    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/RegistrationToken.swift
   0.0%     284   0.0%     284    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Inbox/NoOpNotificationInbox.swift
   0.0%     280   0.0%     280    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/Sleeper.swift
   0.0%     280   0.0%     280    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Type/InAppMessage.swift
   0.0%     276   0.0%     276    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Inbox/NotificationInbox.swift
   0.0%     236   0.0%     236    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/RetryDecision.swift
   0.0%     204   0.0%     204    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized+Arithmetic.swift
   0.0%     180   0.0%     180    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DeviceMetricsGrabber.swift
   0.0%     180   0.0%     180    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Extensions/LoggerExtensions.swift
   0.0%     164   0.0%     164    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/QueueEndpoint.swift
   0.0%     152   0.0%     152    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Timer.swift
   0.0%     140   0.0%     140    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Lock.swift
   0.0%     136   0.0%     136    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/CustomerIO+Location.swift
   0.0%     120   0.0%     120    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/DataExtensions.swift
   0.0%     116   0.0%     116    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/CustomerIODestination.swift
   0.0%     116   0.0%     116    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Config/LocationConfig.swift
   0.0%     116   0.0%     116    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/Aliases.swift
   0.0%     112   0.0%     112    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Synchronized/Synchronized+Bool.swift
   0.0%     104   0.0%     104    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Utilities/ApplicationStateProvider.swift
   0.0%      84   0.0%      84    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Service/DownloadFileType.swift
   0.0%      84   0.0%      84    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/Endpoints/Utilities/GistNetworkRequestError.swift
   0.0%      84   0.0%      84    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/SSE/SseConnectionState.swift
   0.0%      68   0.0%      68    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/Network/NetworkSettings.swift
   0.0%      56   0.0%      56    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/AnyEncodable.swift
   0.0%      44   0.0%      44    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Version.swift
   0.0%      44   0.0%      44    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Config/MessagingInAppConfigOptions.swift
   0.0%      36   0.0%      36    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/DateUtil.swift
   0.0%      36   0.0%      36    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/Time.swift
   0.0%      32   0.0%      32    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/SingleScheduleTimer.swift
   0.0%      32   0.0%      32    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Gist/EngineWeb/EngineWebProvider.swift
   0.0%      16   0.0%      16    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/ApplicationStateProvider.swift
   0.0%      12   0.0%      12    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/State/Core/Synchronized.swift
   0.0%       8   0.0%       8    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Extensions/ErrorExtension.swift
 100.0%  1.24Mi 100.0%  1.24Mi    TOTAL

SDK binary size diff report vs. main branch
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  [NEW] +28.6Ki  [NEW] +28.6Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Storage/StorageManager.swift
  +139% +17.9Ki  +139% +17.9Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingPush/MessagingPush.swift
  +622% +12.8Ki  +622% +12.8Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/MessagingInApp.swift
  [NEW] +9.41Ki  [NEW] +9.41Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/EventPolicy/AggregationRuleset.swift
  [NEW] +6.91Ki  [NEW] +6.91Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Plugins/EventPolicyPlugin.swift
  [NEW] +5.86Ki  [NEW] +5.86Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Storage/StorageManager+Aggregation.swift
  [NEW] +5.56Ki  [NEW] +5.56Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/EventPolicy/EventPolicyEngine.swift
   +46% +4.57Ki   +46% +4.57Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipeline.swift
   +48% +4.08Ki   +48% +4.08Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/CustomerIOInstance.swift
   +92% +3.35Ki   +92% +3.35Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Location/Coordinator/FileLastLocationStateStore.swift
  [NEW] +1.65Ki  [NEW] +1.65Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIGraphShared+StorageManager.swift
  [NEW] +1.34Ki  [NEW] +1.34Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/Storage/StorageManager+EventPolicy.swift
   +13% +1.15Ki   +13% +1.15Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipelineImplementation+BGQ.swift
  +7.5%    +916  +7.5%    +916    /Users/runner/work/customerio-ios/customerio-ios/Sources/DataPipeline/DataPipelineImplementation.swift
   +23%    +456   +23%    +456    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/DIGraphShared+PendingPushDeliveryStore.swift
 -56.0%    -356 -56.0%    -356    /Users/runner/work/customerio-ios/customerio-ios/Sources/MessagingInApp/Type/InAppMessage.swift
  -5.9%    -428  -5.9%    -428    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Communication/EventBus.swift
  -5.4%    -528  -5.4%    -528    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/JsonAdapter.swift
 -92.9%    -736 -92.9%    -736    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Util/AnyEncodable.swift
 -31.4% -1.59Ki -31.4% -1.59Ki    /Users/runner/work/customerio-ios/customerio-ios/Sources/Common/Background Queue/Type/QueueTask.swift
 -100.9% -2.46Ki -100.9% -2.46Ki    [22 Others]
  +8.4% +98.6Ki  +8.4% +98.6Ki    TOTAL

Comment thread Sources/DataPipeline/Plugins/EventPolicyPlugin.swift

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 43b4501. Configure here.

// Integration key was present but carried no rules — server explicitly removed them.
// Delete the cached config so stale rules aren't reloaded on next launch.
try? storage?.deleteAggregationConfig()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect else-if branch deletes valid cached config

Low Severity

The else if config != nil branch is intended to handle the case where the integration key is present but carries no rules (i.e., ruleset is nil). However, this branch also executes when ruleset is non-nil but JSONEncoder().encode(ruleset) or String(data:encoding:) fails. In that scenario, the engine already loaded the valid ruleset into memory via engine.load(ruleset:), but the fallthrough into else if config != nil deletes the previously cached config from the database. On next app restart, no cached rules would be available until a settings refresh arrives from the CDN. The condition could be tightened to else if config != nil, ruleset == nil to only delete when rules are genuinely absent.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 43b4501. Configure here.

@matt-frizzell matt-frizzell left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding the database layer should/could be its own reviewable change, separate from the introduction of filtering. It would cut down the lines of code to read and keep the focus on reviewing and testing one thing at a time.

@hollyschilling-cio hollyschilling-cio marked this pull request as draft June 5, 2026 05:29

@mahmoud-elmorabea mahmoud-elmorabea left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the draft! 👍

I have two main points here:

  • To me, the overhead of the DB: creation, tables, migrations and the extra dependency isn't justified by the data being stored here. They're mostly key/value pairs and group of rules that would be saved/loaded and replaced in their entirety. We can still encrypt it if we want even without the database
  • I'd like us to better link this to the issues we've had reported, run a kind of simulation. "For that particular issue we'd apply that rule and it would have that effect" type of thing. A question that could answer is, should these rules apply to only internal events or also customer events? Do we need these rules to be applied server side also or client side is enough?

let rows = try db.query(
Select(col("payload"), col("fetched_at"))
.from("aggregation_rules")
.where(col("id") == 1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the fact that we are using a single hard-coded row id might signal that we don't need a database for this?

We might also be getting ahead of ourselves by creating a database for the rules, I would imagine there would be a handful of rules per workspace and that they wouldn't change all that often.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right that this specific data doesn't need to be in the database. This is also not the reason to have a database. The rate-limiting history does need to be in a database because that may be updated multiple times per second and rewriting an entire JSON file each write is unreasonable.

Even within the database, there is a Key-Value table that could be used. The reason I put it into a table to start is if we decide in the future to begin doing diffing or keeping previous versions for fallback, which will require additional rows.

return false
}

if let rl = rs.rateLimitsByKey[exactKey] ?? rs.rateLimitsByKey[wildcardKey] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does rate limiting wildcardKey something we'd want to do? It would apply a time based rate limit on all track events including ones sent by customers?

/// `@unchecked Sendable` is safe here: all mutable state (`processed`) is
/// protected by `Synchronized<>`, and `StorageManager.db` is serialized
/// internally via a private DispatchQueue.
final class EventPolicyEngine: Sendable {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding myself reverse understanding how this engine would work, it would be very helpful if we can create a spec that describes the intended behavior

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the issues we've seen, what makes sense to me is something like:

  • Filtering (exactly as you describe): Either filter a specific event or all track/screen events
  • Rate limiting an exact event (specific track or screen view): only send once per certain time frame
  • De-duplicate: for a specific event if the payload is the same (excluding timestamp), drop that event

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code is pretty clear so I'm not sure what you are not unerstanding.

De-duplication is not in scope for this.

Segment has 5 basic event types: track, screen, identify, alias, and group. We don't use alias or group, and identify should never be filtered or rate limited by either of these mechanisms. That leaves us only concerning ourselves with track and screen. screen events are screen views where the event name is the name of the screen. track events have a name of whatever event name was given at the call site.

Filter rules have a event name and type. When the engine gets asked if an event should be passed on, it uses the name and type to check against a look up table (O(1)) in memory to see if that particular event type and name combination is filtered or rate limited. If the event is neither, it goes on. If it is filtered, the event is discarded immediately. If it is rate limited, we check and set (atomically) the event's database record to see when it was seen last. If it has not been seen within the window, the last seen time is updated and the event is sent on. If it has been seen within the time window, the record is not modified and the event is destroyed.

Holly Schilling added 3 commits June 10, 2026 09:05
# Conflicts:
#	.swiftformat
#	Sources/DataPipeline/DataPipelineImplementation.swift
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.

3 participants