From 79319b9d18b5c79219ec090e8b061770224912ab Mon Sep 17 00:00:00 2001 From: Todd Anderson <127344469+tanderson-ld@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:44:38 -0400 Subject: [PATCH 1/4] chore: advertise fdv2 capability in .sdk_metadata.json (#368) ## Summary - Adds `"fdv2": { "introduced": "5.13" }` to `.sdk_metadata.json` so downstream sdk-meta tooling lists the Android Client SDK as FDv2-capable. - Inserted alphabetically between `experimentation` and `flagChanges`. Mirrors the cross-SDK convention used by Python (#375 / metadata in 9.13), .NET (#221 / metadata in 8.11), Java (#120 / metadata in 7.11), Go (#342), Node (#1066). Tracking: [SDK-2443](https://launchdarkly.atlassian.net/browse/SDK-2443). ## Test plan - [x] JSON file parses (validated by the diff being a clean one-line add). - [ ] CI passes on this branch. ## Note on the version pin The `introduced` version assumes the EAP ships as `5.13`. If the umbrella branch advances past that minor before EAP cut, update this value to match the actual release version before merging `sdk-2429-android-fdv2-eap`. [SDK-2443]: https://launchdarkly.atlassian.net/browse/SDK-2443?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- > [!NOTE] > **Low Risk** > Metadata-only JSON change with no effect on SDK runtime behavior. > > **Overview** > Registers **FDv2** as a supported Android Client SDK feature in `.sdk_metadata.json`, with `"introduced": "5.13"`, so sdk-meta and related tooling can treat this SDK as FDv2-capable (aligned with other LaunchDarkly client SDKs). > > The new entry is placed alphabetically in the `features` map between `experimentation` and `flagChanges`. No runtime or SDK code changes in this PR. > > Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e1dd7d1b7a07bcc76ed54da840e80af75a5b8439. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot). --- .sdk_metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.sdk_metadata.json b/.sdk_metadata.json index 0c7130f8..1a43c3ba 100644 --- a/.sdk_metadata.json +++ b/.sdk_metadata.json @@ -15,6 +15,7 @@ "bigSegments": { "introduced": "1.0" }, "contexts": { "introduced": "4.0" }, "experimentation": { "introduced": "2.9" }, + "fdv2": { "introduced": "5.13" }, "flagChanges": { "introduced": "1.0" }, "hooks": { "introduced": "5.8" }, "inlineContextCustomEvents": { "introduced": "5.7" }, From 3736a33601255aa1af62167d9334125d3deb148f Mon Sep 17 00:00:00 2001 From: Todd Anderson <127344469+tanderson-ld@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:44:53 -0400 Subject: [PATCH 2/4] chore: enable FDv2 contract tests via sdk-test-harness v3.1.0-alpha.6 (#367) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Uncomments the v3 contract-test invocation in the Makefile and pins it to sdk-test-harness `v3.1.0-alpha.6` — the first published alpha that includes [sdk-test-harness PR #325](https://github.com/launchdarkly/sdk-test-harness/pull/325) ("updates so FDv2 tests can run against client side sdks"). - Moves the `-stop-service-at-end` flag from the v2 invocation to the v3 invocation (v3 is now the final harness run). - Deletes the obsolete "Uncomment this..." instruction block. Targets the `sdk-2429-android-fdv2-eap` umbrella branch. Tracking: [SDK-2442](https://launchdarkly.atlassian.net/browse/SDK-2442). ## Test plan - [x] `make build-contract-tests` succeeds. - [x] `make start-contract-test-service` installs and starts the APK on the emulator. - [x] `make run-contract-tests` runs both harnesses cleanly: - v2 (FDv1): 798 total, 14 skipped, 784 ran — all passed. - v3 (FDv2, `v3.1.0-alpha.6`): 784 total, 21 skipped, 763 ran — all passed. - [x] Test service stops cleanly after v3 completes. - [ ] CI passes on this branch. [SDK-2442]: https://launchdarkly.atlassian.net/browse/SDK-2442?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- > [!NOTE] > **Low Risk** > Makefile-only CI/contract-test wiring with no production SDK or runtime behavior changes. > > **Overview** > **`make run-contract-tests` now runs both harnesses in sequence:** v2 (FDv1) unchanged except **`-stop-service-at-end` is removed**, then a new **v3** step pinned to **`sdk-test-harness/v3.1.0-alpha.6`** with **`SUPPRESSION_FILE_FDV2`**, **`TEST_HARNESS_PARAMS_V3`**, and **`-stop-service-at-end`** so the contract test service stops after the final run. > > The old commented-out v3 block and “uncomment when ready” note are deleted; the Makefile comment still documents that only the last harness should pass **`-stop-service-at-end`**. > > Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 54f04b5441bdf4095c91abea831dec1b1f7620bf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot). --- Makefile | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index a3ef4777..ed9965b7 100644 --- a/Makefile +++ b/Makefile @@ -18,19 +18,11 @@ run-contract-tests: @echo "Running SDK contract test v2..." @curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \ -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v2/downloader/run.sh \ - | VERSION=v2 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -stop-service-at-end -skip-from $(SUPPRESSION_FILE) $(TEST_HARNESS_PARAMS_V2)" sh - -# Uncomment this, update v3 version, and replace existing run-contract-tests once sdk-test-harness releases a version that includes FDv2 client contract tests. -# -# run-contract-tests: -# @echo "Running SDK contract test v2..." -# @curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \ -# -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v2/downloader/run.sh \ -# | VERSION=v2 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -skip-from $(SUPPRESSION_FILE) $(TEST_HARNESS_PARAMS_V2)" sh -# @echo "Running SDK contract test v3..." -# @curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \ -# -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v3.0.0-alpha.4/downloader/run.sh \ -# | VERSION=v3.0.0-alpha.4 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -stop-service-at-end -skip-from $(SUPPRESSION_FILE_FDV2) $(TEST_HARNESS_PARAMS_V3)" sh + | VERSION=v2 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -skip-from $(SUPPRESSION_FILE) $(TEST_HARNESS_PARAMS_V2)" sh + @echo "Running SDK contract test v3..." + @curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \ + -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v3.1.0-alpha.6/downloader/run.sh \ + | VERSION=v3.1.0-alpha.6 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -stop-service-at-end -skip-from $(SUPPRESSION_FILE_FDV2) $(TEST_HARNESS_PARAMS_V3)" sh contract-tests: build-contract-tests start-emulator start-contract-test-service run-contract-tests From 1bff68981edcd0a6fe3ba16f2d92ef60377483a6 Mon Sep 17 00:00:00 2001 From: Todd Anderson <127344469+tanderson-ld@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:45:14 -0400 Subject: [PATCH 3/4] chore: re-publicize FDv2 data system entry points and lock entry bases (#361) - Make Components.dataSystem() and LDConfig.Builder.dataSystem() public again so customer code can opt in to FDv2 for the EAP. PR #351 had hidden these while the surface was being finalized. - Add package-private no-arg constructors to InitializerEntry and SynchronizerEntry so external code cannot subclass them; the SDK's concrete entry types in the same package continue to compile. - Remove InternalDataSystemAccess (a pure pass-through wrapper) and switch contract-tests SdkClientEntity to call the now-public Components.dataSystem() / LDConfig.Builder.dataSystem() directly. SDK-2438 --- > [!NOTE] > **Medium Risk** > Expands the public API for an unstable EAP data path (FDv2 vs legacy dataSource), but runtime wiring is unchanged aside from visibility and contract-test call sites. > > **Overview** > Re-opens the **early-access FDv2 data system** configuration surface for customer opt-in by making **`Components.dataSystem()`** and **`LDConfig.Builder.dataSystem()`** **public** again (reversing the package-private hiding from PR #351). > > **`InternalDataSystemAccess`** is **removed** as a pass-through; contract-tests now call the public **`Components.dataSystem()`** / **`builder.dataSystem(...)`** APIs directly. > > **`InitializerEntry`** and **`SynchronizerEntry`** gain **package-private no-arg constructors** so code outside the SDK cannot subclass those abstract bases; in-package concrete entry types (e.g. polling/streaming entries) are unchanged. > > Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 24eb4c0ebfcabc6b33597240374995872c374484. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot). --- .../sdk/android/InternalDataSystemAccess.java | 28 ------------------- .../launchdarkly/sdktest/SdkClientEntity.java | 7 ++--- .../launchdarkly/sdk/android/Components.java | 2 +- .../launchdarkly/sdk/android/LDConfig.java | 2 +- .../integrations/InitializerEntry.java | 3 ++ .../integrations/SynchronizerEntry.java | 3 ++ 6 files changed, 11 insertions(+), 34 deletions(-) delete mode 100644 contract-tests/src/main/java/com/launchdarkly/sdk/android/InternalDataSystemAccess.java diff --git a/contract-tests/src/main/java/com/launchdarkly/sdk/android/InternalDataSystemAccess.java b/contract-tests/src/main/java/com/launchdarkly/sdk/android/InternalDataSystemAccess.java deleted file mode 100644 index 792a0ea2..00000000 --- a/contract-tests/src/main/java/com/launchdarkly/sdk/android/InternalDataSystemAccess.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.launchdarkly.sdk.android; - -import com.launchdarkly.sdk.android.integrations.DataSystemBuilder; - -/** - * For LaunchDarkly internal use only. Do not use this class or its methods unless - * you are maintaining LaunchDarkly-produced code for this SDK (for example the contract-tests - * harness). - *
- * Forwards to the package-private data system entry points on {@link LDConfig.Builder} and
- * {@link Components}. Application developers outside LaunchDarkly must not depend on this type;
- * it is not part of the supported public Android SDK API and will be removed in a future release.
- */
-public final class InternalDataSystemAccess {
-
- private InternalDataSystemAccess() {
- }
-
- public static DataSystemBuilder newBuilder() {
- return Components.dataSystem();
- }
-
- public static LDConfig.Builder applyToConfig(
- LDConfig.Builder builder,
- DataSystemBuilder dataSystem) {
- return builder.dataSystem(dataSystem);
- }
-}
diff --git a/contract-tests/src/main/java/com/launchdarkly/sdktest/SdkClientEntity.java b/contract-tests/src/main/java/com/launchdarkly/sdktest/SdkClientEntity.java
index 36280fb9..f9627704 100644
--- a/contract-tests/src/main/java/com/launchdarkly/sdktest/SdkClientEntity.java
+++ b/contract-tests/src/main/java/com/launchdarkly/sdktest/SdkClientEntity.java
@@ -12,7 +12,6 @@
import com.launchdarkly.sdk.android.ConnectionMode;
import com.launchdarkly.sdk.android.DataSystemComponents;
import com.launchdarkly.sdk.android.LaunchDarklyException;
-import com.launchdarkly.sdk.android.InternalDataSystemAccess;
import com.launchdarkly.sdk.android.LDClient;
import com.launchdarkly.sdk.android.LDConfig;
@@ -394,13 +393,13 @@ private LDConfig buildSdkConfig(SdkConfigParams params, LDLogAdapter logAdapter,
private void configureDataSystem(LDConfig.Builder builder, SdkConfigDataSystemParams dataSystem) {
if (Boolean.TRUE.equals(dataSystem.useDefaultDataSystem)) {
- InternalDataSystemAccess.applyToConfig(builder, InternalDataSystemAccess.newBuilder());
+ builder.dataSystem(Components.dataSystem());
return;
}
SdkConfigConnectionModeConfig connModeConfig = dataSystem.connectionModeConfig;
- DataSystemBuilder dsBuilder = InternalDataSystemAccess.newBuilder();
+ DataSystemBuilder dsBuilder = Components.dataSystem();
// at the time of writing this, we did not have contract tests that could test platform state changes,
// disabling automatic mode simplifies the behavior being tested
@@ -425,7 +424,7 @@ private void configureDataSystem(LDConfig.Builder builder, SdkConfigDataSystemPa
dsBuilder.customizeConnectionMode(ConnectionMode.STREAMING, buildConnectionModeBuilder(topLevel));
}
- InternalDataSystemAccess.applyToConfig(builder, dsBuilder);
+ builder.dataSystem(dsBuilder);
}
private static boolean hasTopLevelDataSystemPipelines(SdkConfigDataSystemParams dataSystem) {
diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/Components.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/Components.java
index f1c2aadf..20d72483 100644
--- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/Components.java
+++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/Components.java
@@ -304,7 +304,7 @@ public static PluginsConfigurationBuilder plugins() {
* @see DataSystemComponents
* @see LDConfig.Builder#dataSystem(DataSystemBuilder)
*/
- static DataSystemBuilder dataSystem() {
+ public static DataSystemBuilder dataSystem() {
return new DataSystemBuilder();
}
diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java
index d5f1af13..5b66347f 100644
--- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java
+++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/LDConfig.java
@@ -458,7 +458,7 @@ public Builder dataSource(ComponentConfigurer