From bff9528f6336f0b8d9aca96b45ea717a8fb94e7c Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Wed, 25 Mar 2026 20:53:41 -0400 Subject: [PATCH 1/2] fix(03-01): compute correct reason in DDEvaluator instead of hardcoding TARGETING_MATCH - Add Split parameter to resolveVariant for three-way reason computation - Return STATIC for flags with no rules and no shards (simple flags) - Return SPLIT for flags with no rules but with shards (shard-based flags) - Return TARGETING_MATCH for flags with rules (rule-based flags) - Update 9 test assertions: 7 to STATIC, 2 to SPLIT --- .../trace/api/openfeature/DDEvaluator.java | 12 ++++++++--- .../api/openfeature/DDEvaluatorTest.java | 20 ++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java index 44cd1fc9efe..aa840e38639 100644 --- a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java +++ b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java @@ -121,7 +121,7 @@ public ProviderEvaluation evaluate( for (final Split split : allocation.splits) { if (isEmpty(split.shards)) { return resolveVariant( - target, key, defaultValue, flag, split.variationKey, allocation, context); + target, key, defaultValue, flag, split.variationKey, allocation, split, context); } else { if (targetingKey == null) { return error(defaultValue, ErrorCode.TARGETING_KEY_MISSING); @@ -136,7 +136,7 @@ public ProviderEvaluation evaluate( } if (allShardsMatch) { return resolveVariant( - target, key, defaultValue, flag, split.variationKey, allocation, context); + target, key, defaultValue, flag, split.variationKey, allocation, split, context); } } } @@ -332,6 +332,7 @@ private static ProviderEvaluation resolveVariant( final Flag flag, final String variationKey, final Allocation allocation, + final Split split, final EvaluationContext context) { final Variant variant = flag.variations.get(variationKey); if (variant == null) { @@ -351,7 +352,12 @@ private static ProviderEvaluation resolveVariant( final ProviderEvaluation result = ProviderEvaluation.builder() .value(mapValue(target, variant.value)) - .reason(Reason.TARGETING_MATCH.name()) + .reason( + !isEmpty(allocation.rules) + ? Reason.TARGETING_MATCH.name() + : !isEmpty(split.shards) + ? Reason.SPLIT.name() + : Reason.STATIC.name()) .variant(variant.key) .flagMetadata(metadataBuilder.build()) .build(); diff --git a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java index 3df51d1bde3..4cb1a2c26a8 100644 --- a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java +++ b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java @@ -5,6 +5,8 @@ import static dev.openfeature.sdk.Reason.DEFAULT; import static dev.openfeature.sdk.Reason.DISABLED; import static dev.openfeature.sdk.Reason.ERROR; +import static dev.openfeature.sdk.Reason.SPLIT; +import static dev.openfeature.sdk.Reason.STATIC; import static dev.openfeature.sdk.Reason.TARGETING_MATCH; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -231,7 +233,7 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("simple-string") .targetingKey("") - .result(new Result<>("test-value").reason(TARGETING_MATCH.name()).variant("on")), + .result(new Result<>("test-value").reason(STATIC.name()).variant("on")), new TestCase<>("default") .flag("non-existent-flag") .targetingKey("user-123") @@ -243,15 +245,15 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("simple-string") .targetingKey("user-123") - .result(new Result<>("test-value").reason(TARGETING_MATCH.name()).variant("on")), + .result(new Result<>("test-value").reason(STATIC.name()).variant("on")), new TestCase<>(false) .flag("boolean-flag") .targetingKey("user-123") - .result(new Result<>(true).reason(TARGETING_MATCH.name()).variant("enabled")), + .result(new Result<>(true).reason(STATIC.name()).variant("enabled")), new TestCase<>(0) .flag("integer-flag") .targetingKey("user-123") - .result(new Result<>(42).reason(TARGETING_MATCH.name()).variant("forty-two")), + .result(new Result<>(42).reason(STATIC.name()).variant("forty-two")), new TestCase<>("default") .flag("rule-based-flag") .targetingKey("user-premium") @@ -261,7 +263,7 @@ private static List> evaluateTestCases() { .flag("rule-based-flag") .targetingKey("user-basic") .context("email", "john@gmail.com") - .result(new Result<>("basic").reason(TARGETING_MATCH.name()).variant("basic")), + .result(new Result<>("basic").reason(STATIC.name()).variant("basic")), new TestCase<>("default") .flag("numeric-rule-flag") .targetingKey("user-vip") @@ -287,11 +289,11 @@ private static List> evaluateTestCases() { .result( new Result<>("default") // Result depends on shard calculation - either match or default - .reason(TARGETING_MATCH.name(), DEFAULT.name())), + .reason(SPLIT.name(), DEFAULT.name())), new TestCase<>(0) .flag("string-number-flag") .targetingKey("user-123") - .result(new Result<>(123).reason(TARGETING_MATCH.name()).variant("string-num")), + .result(new Result<>(123).reason(STATIC.name()).variant("string-num")), new TestCase<>("default") .flag("broken-flag") .targetingKey("user-123") @@ -342,7 +344,7 @@ private static List> evaluateTestCases() { .targetingKey("user-123") .result( new Result<>("tracked-value") - .reason(TARGETING_MATCH.name()) + .reason(STATIC.name()) .variant("tracked") .flagMetadata("allocationKey", "exposure-alloc") .flagMetadata("doLog", true)), @@ -416,7 +418,7 @@ private static List> evaluateTestCases() { .flag("shard-matching-flag") .targetingKey("specific-key-that-matches-shard") .result( - new Result<>("shard-matched").reason(TARGETING_MATCH.name()).variant("matched")), + new Result<>("shard-matched").reason(SPLIT.name()).variant("matched")), new TestCase<>("default") .flag("future-allocation-flag") .targetingKey("user-123") From 0917bdecf329d6567c9684876eb026a44557d135 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Wed, 25 Mar 2026 23:05:44 -0400 Subject: [PATCH 2/2] style: apply spotless formatting --- .../datadog/trace/api/openfeature/DDEvaluator.java | 13 +++++++++---- .../trace/api/openfeature/DDEvaluatorTest.java | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java index aa840e38639..504a5157449 100644 --- a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java +++ b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java @@ -136,7 +136,14 @@ public ProviderEvaluation evaluate( } if (allShardsMatch) { return resolveVariant( - target, key, defaultValue, flag, split.variationKey, allocation, split, context); + target, + key, + defaultValue, + flag, + split.variationKey, + allocation, + split, + context); } } } @@ -355,9 +362,7 @@ private static ProviderEvaluation resolveVariant( .reason( !isEmpty(allocation.rules) ? Reason.TARGETING_MATCH.name() - : !isEmpty(split.shards) - ? Reason.SPLIT.name() - : Reason.STATIC.name()) + : !isEmpty(split.shards) ? Reason.SPLIT.name() : Reason.STATIC.name()) .variant(variant.key) .flagMetadata(metadataBuilder.build()) .build(); diff --git a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java index 4cb1a2c26a8..97f49e79422 100644 --- a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java +++ b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java @@ -217,7 +217,7 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("simple-string") // no .targetingKey() -- null by default - .result(new Result<>("test-value").reason(TARGETING_MATCH.name()).variant("on")), + .result(new Result<>("test-value").reason(STATIC.name()).variant("on")), // Null targeting key on sharded flag must return TARGETING_KEY_MISSING new TestCase<>("default") .flag("shard-flag") @@ -417,8 +417,7 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("shard-matching-flag") .targetingKey("specific-key-that-matches-shard") - .result( - new Result<>("shard-matched").reason(SPLIT.name()).variant("matched")), + .result(new Result<>("shard-matched").reason(SPLIT.name()).variant("matched")), new TestCase<>("default") .flag("future-allocation-flag") .targetingKey("user-123")