Skip to content

feat: wire fdv1-fallback capability into node-client, browser, and react-native contract-test entities - #1858

Open
joker23 wants to merge 4 commits into
skz/SDK-2912/fdv1-fallback-fix-recovery-orchestrationfrom
skz/sdk-2617/fdv1-fallback-fix
Open

feat: wire fdv1-fallback capability into node-client, browser, and react-native contract-test entities#1858
joker23 wants to merge 4 commits into
skz/SDK-2912/fdv1-fallback-fix-recovery-orchestrationfrom
skz/sdk-2617/fdv1-fallback-fix

Conversation

@joker23

@joker23 joker23 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires the harness's dataSystem.fdv1Fallback.baseUri into the node-client, browser, and react-native contract-test entities so the FDv1 fallback synchronizer connects to the harness's dedicated FDv1 polling endpoint instead of the polling initializer's endpoint (which applyEndpointOverrides otherwise overwrites it with).

Completes contract-test coverage for the FDv1 fallback/recovery behavior built across this stack.


Note

Overview
Contract-test harness entities for browser, node-client, and react-native now map harness dataSystem.fdv1Fallback (polling base URI and optional interval) into each SDK’s streaming connectionModes via an extended translateModeDefinition, so the FDv1 fallback synchronizer uses the harness’s dedicated FDv1 polling endpoint instead of endpoints overwritten by initializer/synchronizer applyEndpointOverrides.

contract-test-utils adds fdv1Fallback on SDKConfigDataSystem. Harness services advertise the fdv1-fallback capability (node-client enables it formally; browser/RN websocket handlers list it). React Native also advertises client-event-source-http-errors.

Suppressions document platform limits: browser skips FDv1 directive request tag tests because native EventSource cannot read stream response headers; React Native skips several FDv1 directive streaming scenarios because react-native-sse delivers headers/open too late for those tests.

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

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 26360 bytes
Compressed size limit: 29000
Uncompressed size: 129188 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk-common size report
This is the brotli compressed size of the ESM build.
Compressed size: 42010 bytes
Compressed size limit: 44000
Uncompressed size: 227536 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/browser size report
This is the brotli compressed size of the ESM build.
Compressed size: 180270 bytes
Compressed size limit: 200000
Uncompressed size: 834109 bytes

@github-actions

Copy link
Copy Markdown
Contributor

@launchdarkly/js-client-sdk size report
This is the brotli compressed size of the ESM build.
Compressed size: 32606 bytes
Compressed size limit: 34000
Uncompressed size: 116941 bytes

Comment on lines +5 to +12
# RN's forked EventSource (react-native-sse) fires `open` too late (from
# onreadystatechange at readyState DONE, not from onprogress at LOADING) and never
# populates headers on error events, so FDv1 fallback directives carried on stream
# response headers don't reach the SDK in time (or at all, on the error path).
streaming/fdv2/FDv1 fallback directive/directive on streaming error engages FDv1 fallback
streaming/fdv2/FDv1 fallback directive/directive on streaming success applies payload then engages FDv1
streaming/fdv2/FDv1 fallback directive/directive without FDv1 fallback configured halts the data system
tags/FDv1 fallback directive requests

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.

This is tracked in a separate ticket

@joker23
joker23 marked this pull request as ready for review August 13, 2026 17:55
@joker23
joker23 requested a review from a team as a code owner August 13, 2026 17:55

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 2 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +68 to +71
function translateModeDefinition(
modeDef: SDKConfigModeDefinition,
fdv1Fallback?: SDKConfigPollingParams | null,
): ModeDefinition {

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.

🟡 Fallback polling settings are ignored when the test harness uses custom connection modes

The fallback polling settings sent by the test harness are only forwarded for the simple configuration path (translateModeDefinition(modeDef, options.dataSystem.fdv1Fallback) at packages/sdk/browser/contract-tests/entity/src/ClientEntity.ts:167) and are silently dropped when the harness also asks for custom connection modes, so those test scenarios run against the wrong endpoint.
Impact: Contract-test scenarios that combine custom connection modes with a fallback endpoint will not exercise the requested fallback and can fail or pass for the wrong reason.

Only one of the two configuration branches forwards options.dataSystem.fdv1Fallback

SDKConfigDataSystem.fdv1Fallback (packages/tooling/contract-test-utils/src/types/ConfigParams.ts:30) is a sibling of connectionModeConfig, so the harness can send both. In all three entities the connectionModeConfig branch still calls translateModeDefinition(modeDef) with no second argument (packages/sdk/browser/contract-tests/entity/src/ClientEntity.ts:150, packages/sdk/node-client/contract-tests/src/sdkClientEntity.ts:156, packages/sdk/react-native/contract-tests/entity/src/ClientEntity.ts:149), while only the top-level initializers/synchronizers branch passes options.dataSystem.fdv1Fallback. In that case the SDK falls back to the built-in default fallback endpoint/interval instead of the one the harness specified.

Prompt for agents
In the three client contract-test entities (packages/sdk/browser/contract-tests/entity/src/ClientEntity.ts, packages/sdk/node-client/contract-tests/src/sdkClientEntity.ts, packages/sdk/react-native/contract-tests/entity/src/ClientEntity.ts) the new fdv1Fallback parameter of translateModeDefinition is only supplied from the branch that wraps top-level initializers/synchronizers into a single 'streaming' mode. The branch that handles options.dataSystem.connectionModeConfig.customConnectionModes still calls translateModeDefinition(modeDef) without the fallback, so a harness configuration that sets both connectionModeConfig and dataSystem.fdv1Fallback loses the requested fallback endpoint/poll interval. Consider forwarding options.dataSystem.fdv1Fallback in the custom connection modes loop as well (for every mode, or at least the modes that have synchronizers).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 5 to 7
streaming/requests/method and headers/REPORT/http
streaming/requests/URL path is computed correctly/no environment filter/base URI has no trailing slash/REPORT
streaming/requests/URL path is computed correctly/no environment filter/base URI has a trailing slash/REPORT

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.

🟡 Browser contract tests will fail because fallback-directive scenarios are advertised but not skipped

The browser test entity now tells the test harness it supports fallback directives while only one of the four directive-based scenarios is skipped (tags/FDv1 fallback directive requests at packages/sdk/browser/contract-tests/suppressions_datamode_changes.txt:7), even though the browser can never observe those directives, so the remaining scenarios run and fail.
Impact: The browser contract-test job in CI is expected to fail on the fallback-directive scenarios.

Browser EventSource reports headers: false, and the FDv2 harness run uses this suppressions file

packages/sdk/browser/contract-tests/entity/src/TestHarnessWebSocket.ts:48 adds the fdv1-fallback capability, so the v3 harness (run with --skip-from=.../suppressions_datamode_changes.txt, see .github/workflows/browser.yml:113-119) will execute the streaming/fdv2/FDv1 fallback directive/... scenarios. The directive is carried on streaming response headers (packages/shared/sdk-client/src/datasource/fdv2/fallbackDirective.ts), but the browser platform uses the native EventSource and reports headers: false (packages/sdk/browser/src/platform/BrowserRequests.ts:22-28, packages/sdk/browser/src/platform/DefaultBrowserEventSource.ts:58). The react-native entity, which has the same limitation on the error path, suppresses those three streaming scenarios (packages/sdk/react-native/contract-tests/suppressions-fdv2.txt:9-11); the browser suppressions omit them.

(Refers to lines 5-8)

Prompt for agents
The browser contract-test entity now advertises the fdv1-fallback capability, but the browser uses the native EventSource which cannot read streaming response headers (BrowserRequests.getEventSourceCapabilities returns headers: false), so the harness scenarios that deliver the FDv1 fallback directive over the streaming response cannot pass. The react-native suppressions file lists the equivalent scenarios (streaming/fdv2/FDv1 fallback directive/...). Either add those streaming scenarios to packages/sdk/browser/contract-tests/suppressions_datamode_changes.txt or do not advertise the fdv1-fallback capability from the browser entity.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@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 using default effort 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 f296bbf. Configure here.

initialConnectionMode: 'streaming',
};
dataSystem.connectionModes = {
streaming: translateModeDefinition(modeDef),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FDv1 fallback skipped for custom modes

Medium Severity

translateModeDefinition now accepts dataSystem.fdv1Fallback, but the connectionModeConfig.customConnectionModes path still calls it without that argument. Harness configs that combine custom modes with fdv1Fallback keep losing the dedicated FDv1 polling URI to applyEndpointOverrides, the same failure this PR fixes on the top-level initializers/synchronizers path.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f296bbf. Configure here.

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.

1 participant