Skip to content

Ship dd-openfeature as a standalone SDK extended by the Java agent (AI prototype) - #12709

Draft
PerfectSlayer wants to merge 6 commits into
masterfrom
bbujon/ffe
Draft

PerfectSlayer wants to merge 6 commits into
masterfrom
bbujon/ffe

Conversation

@PerfectSlayer

@PerfectSlayer PerfectSlayer commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Warning

AI-generated prototype, not human reviewed.
Claude Code generated all the code, tests and docs in this PR from a design brief. No human has reviewed any of it yet. It is a draft to discuss the design proposal, not a merge candidate. Review it as a design sketch and expect rough edges.

What Does This Do

This prototypes a different architecture for running Datadog Feature Flags without dd-java-agent. It covers the same need as #12576, but under different constraints.

  • dd-openfeature is a standalone SDK in a new root module, :dd-openfeature (JDK 11+), published as com.datadoghq:dd-openfeature.
    • It uses no dd-trace-java internal module.
    • Its only dependencies are the OpenFeature SDK, the OpenTelemetry API and jackson-core, all as plain POM dependencies.
    • It talks to the network through java.net.http.HttpClient.
  • dd-java-agent is optional. When attached, it connects to the SDK through library instrumentation. The SDK then uses the agent's Remote Configuration, its Datadog Agent event proxy, agent telemetry and APM span enrichment.
  • The application always adds the SDK and registers the provider. The agent never installs a provider by itself.
App classloader                                     │ Bootstrap CL              │ Agent CL
────────────────────────────────────────────────────┼───────────────────────────┼─────────────────────────
dd-openfeature (SDK)                                │                           │
  Provider ─► FeatureFlagsRuntime ─► Connectors.detect() ◄── advice (returns JavaAgentConnector)
     │          ├─ configuration: CDN poller │ connector Remote Configuration
     │          ├─ events: direct intake │ connector event proxy (+ fallback)
     │          └─ health metrics / span enrichment: no-op │ connector
  JavaAgentConnector (injected helper) ─────────────► FeatureFlaggingGateway ◄─ FeatureFlaggingSystem
                                                    │  (JDK types only)         │  RC FFE_FLAGS (raw bytes),
                                                    │                           │  EVP proxy, telemetry,
                                                    │                           │  span enrichment

Motivation

The design brief ("[DRAFT] FFE Design Doc", following the product brief Java Feature Flags: organize as standalone and SSI) rejects the shape of #12576 for two reasons:

  1. It turns internal dd-trace-java modules into customer-facing contracts. That slows down the modularization of dd-trace-java.
  2. It bundles internal modules and their dependencies onto the application classpath. That causes hard-to-diagnose conflicts and exposes our internals.

The brief also notes the following:

  • No precedent for auto-installation. Neither the OpenFeature documentation nor any competitor (LaunchDarkly, Split, DevCycle, Statsig, Optimizely, Flagsmith, ConfigCat, Unleash, GrowthBook, flagd) installs a provider without code.
  • Injection is off by default anyway. The FFE team doesn't want injection enabled by default, which defeats the SSI case.

So the install path follows OpenFeature practice: always add the SDK, and optionally attach the agent.

Design differences with #12576

Topic #12576 This PR
SDK packaging Shadow jar bundling internal-api, communication, config-utils, OkHttp, Moshi, JCTools…, relocated and shrunk with minimize() (~1.84 MB) Plain jar, about 154 KB. POM dependencies are only dev.openfeature:sdk, io.opentelemetry:opentelemetry-api and jackson-core. No shading, no minimize()
HTTP and JSON Relocated OkHttp and Moshi java.net.http.HttpClient and jackson-core streaming (no old HTTP client for security scanners to flag)
SDK ↔ agent contract Public bootstrap POJOs (UFC model, ExposureEvent, FlagEvalEvent) on FeatureFlaggingGateway, plus an AGENT/STANDALONE runtime ownership claim An SPI owned by the SDK (com.datadog.openfeature.internal.connector). Instrumentation exit advice on Connectors.detect() fills it in. The bootstrap gateway is internal to the agent, uses JDK types only and can change freely
Version skew Reflection probes and LinkageError catches Muzzle checks the helpers' references to the SPI. On a mismatch the instrumentation doesn't apply and the SDK runs standalone
Provider installation The agent installs the provider when OpenFeatureAPI.getInstance() is called (openfeature-1.20 instrumentation) No auto-installation: the application registers new Provider()
Evaluation and UFC parsing Shared core package; the agent parses with Moshi; the evaluator is injected as helpers Everything in the SDK. The agent forwards raw Remote Configuration documents and event payloads
Remote Configuration without the agent Optional dd-openfeature-remote-config artifact (~4.17 MB, bundles remote-config-core) Out of scope for now (// TODO). remote_config requires the agent
Injected helper conflicts Different copies of evaluator helpers from the agent and the SDK on the same classpath Helpers only implement the SDK's SPI interfaces, so no SDK class is duplicated
Public API datadog.trace.api.openfeature.Provider com.datadog.openfeature.Provider. The old class name stays as a deprecated subclass. The SDK can't sit under datadog.trace.*, which the agent never instruments and loads bootstrap-first
Older SDKs on a new agent Kept working through bridge probes Dropped (see breaking change below)

Changes

  • :dd-openfeature (new root module), ported from feature-flagging-api/-lib and Prototype standalone and injected Java Feature Flags together #12576:
  • dd-openfeature-connector instrumentation (dd-java-agent/instrumentation/datadog/openfeature/):
    • Exit advice on Connectors.detect().
    • Gated by a new TargetSystem.FEATURE_FLAGS, which follows the resolved DD_FEATURE_FLAGS_* settings.
    • Helpers are compiled in a java11 source set.
  • Agent side (products/feature-flagging):
    • The bootstrap module is reduced to a FeatureFlaggingGateway.Backend registry.
    • FeatureFlagsBackend provides:
      • Remote Configuration fan-out of raw FFE_FLAGS documents. The product is registered at agent startup in remote_config mode, so the first poll asks for it.
      • The event platform proxy client, with fallback signalling for the SDK.
      • Telemetry counters.
      • Span enrichment through the existing writer.
  • Removed:
    • The feature-flagging-api module, and the agent-side CDN poller, parsers, event writers and bootstrap POJOs.
    • The agent's CDN-related Config getters, which the SDK now owns.
    • The publication and CI jar paths are switched to :dd-openfeature.
  • Smoke tests (dd-smoke-tests/openfeature) now cover three setups:
    • agent + Remote Configuration
    • agent + CDN, the default source
    • no agent + CDN
  • Docs: dd-openfeature/README.md.

Features by setup

Feature SDK only SDK + dd-java-agent
Configuration (agentless, the default) CDN CDN
Configuration (remote_config) Not supported (init error) Remote Configuration
Exposures / evaluation counts Direct intake (DD_API_KEY) Event proxy; direct intake fallback in agentless mode
feature_flag.evaluations OTel metric Yes Yes
Health metrics, span enrichment No Yes

Breaking change

dd-openfeature 1.66.0 and earlier link against bootstrap types this PR removes, so they no longer work with this agent. dd-openfeature and dd-java-agent must be upgraded together. This was a deliberate choice to avoid keeping the legacy bridge.

Testing

All suites below were run locally on this branch's head commit:

Suite Result
:dd-openfeature:test + forkedTest 781 passed
feature-flagging-lib / -agent / -bootstrap 65 / 3 / 1 passed
dd-openfeature-connector instrumentation (test + forkedTest) 7 passed
:dd-smoke-tests:openfeature (3 setups) 932 passed, 3 skipped (agent telemetry checks in the no-agent setup)
internal-api ConfigTest passed

Not covered:

  • Muzzle: the pass directive can't exist until the SDK is published (// TODO).
  • Benchmarks: JMH benchmarks from the removed modules are not ported (// TODO).
  • Other environments: no SSI or real-backend validation.
  • Pre-PR reviews: /techdebt and /perf-review have not been run.

Open questions

  • Is dropping support for older dd-openfeature versions on a new agent acceptable, or do we need a deprecation window?
  • jackson-core as a plain dependency: what minimum version do we support against customer BOMs?
  • Remote Configuration without the agent (for example through libdatadog), and trace enrichment through the OpenTelemetry SDK, are both left as follow-ups.

Additional Notes

Jira ticket: APMLP-1512

🤖 Generated with Claude Code

@PerfectSlayer PerfectSlayer added type: feature Enhancements and improvements tag: ai generated Largely based on code generated by an AI or LLM comp: openfeature OpenFeature labels Oct 1, 2026
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
• Patch Coverage: 79.11%
• Overall Coverage: 58.73% (-0.54%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: e48cce4 | Docs | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.00 s 13.85 s [+0.3%; +1.8%] (maybe worse)
startup:insecure-bank:tracing:Agent 12.95 s 12.95 s [-0.7%; +0.7%] (no difference)
startup:petclinic:appsec:Agent 17.09 s 16.79 s [+0.9%; +2.7%] (maybe worse)
startup:petclinic:iast:Agent 17.03 s 17.08 s [-1.3%; +0.7%] (no difference)
startup:petclinic:profiling:Agent 16.06 s 16.80 s [-8.7%; -0.1%] (maybe better)
startup:petclinic:sca:Agent 17.02 s 16.72 s [+0.8%; +2.8%] (maybe worse)
startup:petclinic:tracing:Agent 16.26 s 16.29 s [-1.3%; +0.9%] (no difference)

Commit: e48cce43 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@PerfectSlayer PerfectSlayer added the tag: override groovy enforcement Override the "Enforce Groovy Migration" check label Oct 1, 2026

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

comp: openfeature OpenFeature tag: ai generated Largely based on code generated by an AI or LLM tag: override groovy enforcement Override the "Enforce Groovy Migration" check type: feature Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant