Skip to content

feat(flags): send the split serial ID on iOS exposure events (EX-3422) - #1410

Draft
danyal002 wants to merge 6 commits into
developfrom
danyal.khan/EX-3422-ios
Draft

danyal002 wants to merge 6 commits into
developfrom
danyal.khan/EX-3422-ios

Conversation

@danyal002

@danyal002 danyal002 commented Sep 9, 2026 •

Copy link
Copy Markdown

What does this PR do?

The iOS bridge now sends the split serial ID on feature flag exposure events.

File Change
packages/core/DatadogSDKReactNative.podspec and 2 other podspecs Moves the iOS SDK to 3.17.0.
example/ios/Podfile.lock, example-new-architecture/ios/Podfile.lock, benchmarks/ios/Podfile.lock Locks the iOS SDK pods at 3.17.0.
packages/core/ios/Sources/DdFlagsImplementation.swift Reads and writes serialId in both bridge directions. Maps the new initializationTimedOut error.
packages/core/ios/Tests/DdFlagsTests.swift Adds 7 tests.
packages/core/ios/Tests/MockDatadogCore.swift and 3 other test mocks Implement remoteConfiguration.
packages/internal-testing-tools/ios/Sources/DatadogCoreProxy.swift Forwards remoteConfiguration to the wrapped core.
packages/core/ios/Tests/DdTraceTests.swift Fixes a race in testTracingConcurrently.

iOS SDK 3.17.0 adds serialID to FlagAssignment, reads it on the exposure event, and includes it in the exposure deduplication cache. The React Native bridge supplies the value.

The bridge converts a FlagAssignment to an NSDictionary with a fixed key list, and converts the dictionary back for exposure tracking. The key list omitted the serial ID. The value was therefore dropped in both directions, and the code still compiled.

The serial ID crosses the bridge as a string. Android does the same, because React Native converts integers to Double. An assignment with no serial ID omits the key instead of sending NSNull.

The reader accepts a string only. NSNumber and Bool bridge into each other on Apple platforms, so a numeric branch would read a boolean true as serial ID 1. Int(String) rejects a boolean, and rejects any other value that is not an integer. A malformed serial ID yields no serial ID. It never rejects the assignment, because that would drop the exposure event for the whole flag.

Serial IDs are zero-based for each org. 0 is therefore a real value, and three tests pin it.

iOS SDK 3.17.0 also changes two APIs that the bridge and its tests depend on. FlagsError adds initializationTimedOut, and the bridge rejects it with the error code INITIALIZATION_TIMED_OUT. DatadogCoreProtocol adds remoteConfiguration. The test mocks return nil, as NOPDatadogCore does. DatadogCoreProxy forwards the value from the core that it wraps.

Motivation

The UFC compiler rewrites a holdout into an ordinary allocation before any SDK reads the flag configuration. An exposure event therefore records no holdout. The split serial ID is the only link back to it. An exposure event without the serial ID cannot be resolved to a holdout.

Additional Notes

Testing. The new tests cover the string form, serial ID 0 in both directions, an absent serial ID omitting the key, four malformed values, a round trip through both conversions, and the INITIALIZATION_TIMED_OUT error code. The DatadogSDKReactNative and DatadogSDKReactNativeSessionReplay test schemes pass on an iOS simulator.

testTracingConcurrently failed intermittently on develop, for example on PR #1409. Its concurrent iterations shared one variable for the span ID. Another iteration could overwrite the value between startSpan and finishSpan, so one span stayed open. Each iteration now keeps its own span ID. The test passed 100 consecutive runs on a simulator.

Risks. The iOS SDK bump from 3.16.0 to 3.17.0 carries every other change in that release.

The bridge ignores a numeric serial ID, whereas the Android bridge accepts a string or a number. Every JavaScript producer sends a string: the native snapshot, the OpenFeature offline adapter, and the core precomputed decoder. No current caller therefore depends on the numeric shape. A test pins the numeric case as ignored, so the difference is deliberate and visible.

The OpenFeature offline path already sends the serial ID. PR #1409 adds it to the core client's offline path. Android already sends the serial ID.

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Tests

✅ All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 3cd6690 | Docs | View more details | Give us feedback!

Bump the iOS SDK to 3.17.0, which adds serialID to FlagAssignment, and
send the value through the React Native bridge.

The iOS bridge converts FlagAssignment to an NSDictionary with a fixed key
list, and converts it back for exposure tracking. The key list omitted the
serial ID, so the value was dropped in both directions. The code still
compiled, so nothing reported the loss.

The serial ID crosses the bridge as a string, for parity with Android,
which sends a string because React Native converts integers to Double. An
assignment with no serial ID omits the key instead of sending NSNull.

The reader accepts a string only. NSNumber and Bool bridge into each other
on Apple platforms, so a numeric branch would read a boolean true as serial
ID 1. Int(String) rejects that. A malformed serial ID yields no serial ID
and never rejects the assignment, because that would drop the exposure
event for the whole flag.
@danyal002
danyal002 force-pushed the danyal.khan/EX-3422-ios branch from 705ae26 to 9cf32f3 Compare October 14, 2026 17:54
@danyal002
danyal002 marked this pull request as ready for review October 14, 2026 17:54
Copilot AI balanced review requested due to automatic review settings October 14, 2026 17:54
@danyal002
danyal002 requested a review from a team as a code owner October 14, 2026 17:54

Copilot AI 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.

🟢 Approval recommended

The implementation and coverage are complete, with only a non-blocking wording correction identified.

1 open finding
What changed in this PR

Adds iOS split serial IDs to feature-flag exposure events.

Changes:

  • Serializes and restores serialId across the iOS bridge.
  • Adds coverage for valid, absent, zero, malformed, and round-tripped IDs.
  • Upgrades Datadog iOS dependencies to 3.17.0.
File Description
packages/​core/​ios/​Sources/​DdFlagsImplementation.swift Bridges serial IDs as strings.
packages/​core/​ios/​Tests/​DdFlagsTests.swift Tests serial-ID conversion behavior.
packages/​core/​DatadogSDKReactNative.podspec Upgrades core iOS SDK pods.
packages/​react-native-webview/​DatadogSDKReactNativeWebView.podspec Upgrades WebView pods.
packages/​react-native-session-replay/​DatadogSDKReactNativeSessionReplay.podspec Upgrades Session Replay pod.
example/​ios/​Podfile.lock Locks upgraded dependencies.
example-new-architecture/​ios/​Podfile.lock Locks upgraded dependencies.
benchmarks/​ios/​Podfile.lock Locks upgraded dependencies.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/core/ios/Tests/DdFlagsTests.swift Outdated
Copilot AI balanced review requested due to automatic review settings October 14, 2026 18:03

Copilot AI 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.

🟢 Approval recommended

The bridge implementation, dependency updates, and focused tests consistently cover the intended serial-ID behavior.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 14, 2026 18:15

Copilot AI 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.

🔵 Needs a closer look

The cross-module iOS SDK upgrade needs native build and regression validation before human approval.

0 open findings

🧠 Review effort: Balanced

@sameerank sameerank 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.

The serial-ID forwarding changes look good! Codex found a couple issues on the SDK 3.17.0 upgrade that might need addressing. Please double check if valid

s.dependency 'DatadogTrace', '3.17.0'
s.dependency 'DatadogRUM', '3.17.0'
s.dependency 'DatadogCrashReporting', '3.17.0'
s.dependency 'DatadogFlags', '3.17.0'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Handle the new initialization timeout error before upgrading DatadogFlags

SDK 3.17.0 adds FlagsError.initializationTimedOut, but the error switch in DdFlagsImplementation.swift still handles only the previous four cases. This makes the switch non-exhaustive and breaks iOS compilation, regardless of whether feature flags are enabled. I reproduced the compiler error against the 3.17.0 enum. Please add a JavaScript error mapping for .initializationTimedOut and a corresponding test alongside this dependency bump.

s.dependency 'DatadogRUM', '3.16.0'
s.dependency 'DatadogCrashReporting', '3.16.0'
s.dependency 'DatadogFlags', '3.16.0'
s.dependency 'DatadogCore', '3.17.0'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Account for the minimum OS version increase in SDK 3.17.0

SDK 3.17.0 raises the minimum supported iOS and tvOS versions from 12.0 to 15.0, while the React Native podspecs still declare 12.0. Applications targeting versions 12–14 will therefore fail CocoaPods dependency resolution after upgrading. The example’s 15.1 deployment target masks this incompatibility. Please preserve the existing minimum through a compatible native SDK release, or explicitly handle and document the platform-support change, including updating the podspec deployment targets.

The DatadogCore 3.17.0 podspec explicitly sets both iOS and tvOS deployment targets to 15.0.

This also applies to the Session Replay and WebView podspecs, which retain the older deployment targets.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hmm, this is a question for @DataDog/rum-mobile I think. Is it safe to raise the minimum?

Copilot AI balanced review requested due to automatic review settings October 14, 2026 18:28

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI balanced review requested due to automatic review settings October 14, 2026 18:49

Copilot AI 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.

🔵 Needs a closer look

No concrete defects were identified, but the SDK-wide upgrade requires human confirmation of native compatibility beyond the reported simulator tests.

0 open findings

🧠 Review effort: Balanced

@maciejburda
maciejburda requested a review from sbarrio October 15, 2026 07:06
@sbarrio

sbarrio commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Hmm, this is a question for @DataDog/rum-mobile I think. Is it safe to raise the minimum?

Hi @danyal002, I still have to properly review the whole PR, but just be aware that the bump of the iOS SDK to 3.17.0 is blocked at the moment, as it includes breaking changes (it drops support for iOS 12, 13 and 14).

The plan is to do a one-off breaking v3 release in the next few weeks that will include that bump as well as the support for SPM (dropping Cocoapods).

Just so you are aware that this PR won't be able to be merged until that happens so you can plan accordingly.

@danyal002

Copy link
Copy Markdown
Author

Hmm, this is a question for @DataDog/rum-mobile I think. Is it safe to raise the minimum?

Hi @danyal002, I still have to properly review the whole PR, but just be aware that the bump of the iOS SDK to 3.17.0 is blocked at the moment, as it includes breaking changes (it drops support for iOS 12, 13 and 14).

The plan is to do a one-off breaking v3 release in the next few weeks that will include that bump as well as the support for SPM (dropping Cocoapods).

Just so you are aware that this PR won't be able to be merged until that happens so you can plan accordingly.

@sbarrio Thanks! That makes sense. I'll put this PR back in draft and check back in a few weeks.

@danyal002
danyal002 marked this pull request as draft October 15, 2026 14:27

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants