From e975b22eb916ce5cb4b670171f599d63ddac2649 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Thu, 12 Mar 2026 16:14:10 +0100 Subject: [PATCH 1/3] test(evaluators): add edge case scenarios for nested $ref resolution Adds @evaluator-ref-edge-cases tagged scenarios covering: - Tags existing 'Evaluator reuse' scenario with @evaluator-refs - Adds nested $ref: evaluator 'is_privileged' references 'is_ballmer' to verify recursive resolution works correctly - Tests that nested resolution via different context paths both work Addresses: https://github.com/open-feature/flagd/issues/1875 Signed-off-by: Simon Schrottner Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- flags/evaluator-refs.json | 31 +++++++++++++++++++++++++++++-- gherkin/targeting.feature | 13 +++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/flags/evaluator-refs.json b/flags/evaluator-refs.json index faad954..f6ad8f3 100644 --- a/flags/evaluator-refs.json +++ b/flags/evaluator-refs.json @@ -35,6 +35,24 @@ "no" ] } + }, + "nested-ref-targeted-flag": { + "state": "ENABLED", + "variants": { + "privileged": "privileged", + "standard": "standard", + "none": "none" + }, + "defaultVariant": "none", + "targeting": { + "if": [ + { + "$ref": "is_privileged" + }, + "privileged", + "standard" + ] + } } }, "$evaluators": { @@ -42,8 +60,17 @@ "==": [ "ballmer@macrosoft.com", { - "var": [ - "email" + "var": ["email"] + } + ] + }, + "is_privileged": { + "or": [ + {"$ref": "is_ballmer"}, + { + "==": [ + "admin", + {"var": ["role"]} ] } ] diff --git a/gherkin/targeting.feature b/gherkin/targeting.feature index 5dd7ae2..e62b241 100644 --- a/gherkin/targeting.feature +++ b/gherkin/targeting.feature @@ -10,6 +10,7 @@ Feature: Targeting rules And a stable flagd provider # evaluator refs + @evaluator-refs Scenario Outline: Evaluator reuse Given a String-flag with key "" and a default value "fallback" And a context containing a key "email", with type "String" and with value "ballmer@macrosoft.com" @@ -20,6 +21,18 @@ Feature: Targeting rules | some-email-targeted-flag | hi | | some-other-email-targeted-flag | yes | + @evaluator-refs @evaluator-ref-edge-cases + Scenario Outline: Nested evaluator ref resolution + Given a String-flag with key "nested-ref-targeted-flag" and a default value "fallback" + And a context containing a key "", with type "String" and with value "" + When the flag was evaluated with details + Then the resolved details value should be "" + Examples: + | context_key | context_value | value | + | email | ballmer@macrosoft.com | privileged | + | role | admin | privileged | + | email | other@example.com | standard | + # custom operators # @fractional-v1: legacy float-based bucketing (abs(hash) / i32::MAX * 100) # @fractional-v2: high-precision integer bucketing ((hash * totalWeight) >> 32) From eee9ff503c5237580e8edef1e3331ddae85aa585 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Mon, 30 Mar 2026 16:04:28 +0200 Subject: [PATCH 2/3] test(evaluator-refs): mirror nested ref edge case scenarios to evaluator gherkin suite Adds the nested $ref resolution scenario and is_privileged evaluator ref from the SDK-level gherkin to the evaluator suite, with matching flag definitions (nested-ref-targeted-flag + is_privileged) in evaluator/flags/testkit-flags.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner --- evaluator/flags/testkit-flags.json | 18 ++++++++++++++++++ evaluator/gherkin/evaluator-refs.feature | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/evaluator/flags/testkit-flags.json b/evaluator/flags/testkit-flags.json index 268e905..f8d2b6c 100644 --- a/evaluator/flags/testkit-flags.json +++ b/evaluator/flags/testkit-flags.json @@ -474,6 +474,18 @@ ["two", 50] ] } + }, + "nested-ref-targeted-flag": { + "state": "ENABLED", + "variants": { + "privileged": "privileged", + "standard": "standard", + "none": "none" + }, + "defaultVariant": "none", + "targeting": { + "if": [{"$ref": "is_privileged"}, "privileged", "standard"] + } } }, "$evaluators": { @@ -482,6 +494,12 @@ "ballmer@macrosoft.com", {"var": ["email"]} ] + }, + "is_privileged": { + "or": [ + {"$ref": "is_ballmer"}, + {"==": ["admin", {"var": ["role"]}]} + ] } } } diff --git a/evaluator/gherkin/evaluator-refs.feature b/evaluator/gherkin/evaluator-refs.feature index 0d8467d..fd404a3 100644 --- a/evaluator/gherkin/evaluator-refs.feature +++ b/evaluator/gherkin/evaluator-refs.feature @@ -13,3 +13,16 @@ Feature: Evaluator evaluator refs | key | value | | some-email-targeted-flag | hi | | some-other-email-targeted-flag | yes | + + @evaluator-ref-edge-cases + Scenario Outline: Nested evaluator ref resolution + Given an evaluator + And a String-flag with key "nested-ref-targeted-flag" and a fallback value "fallback" + And a context containing a key "", with type "String" and with value "" + When the flag was evaluated with details + Then the resolved details value should be "" + Examples: + | context_key | context_value | value | + | email | ballmer@macrosoft.com | privileged | + | role | admin | privileged | + | email | other@example.com | standard | From 963cb3bb01f8ec87cbf24ffde96c5b2bb323b07d Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Mon, 30 Mar 2026 16:14:30 +0200 Subject: [PATCH 3/3] fix(evaluator-refs): inline is_ballmer logic in is_privileged, remove nested $ref Addresses toddbaert's review concern: nested $ref resolution relies on JSON key declaration order, which is non-deterministic when serialised by a server (see open-feature/flagd#1875). Inlining the is_ballmer condition directly into is_privileged eliminates the dependency and ensures deterministic behaviour across all conformance implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Schrottner --- evaluator/flags/testkit-flags.json | 2 +- flags/evaluator-refs.json | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/evaluator/flags/testkit-flags.json b/evaluator/flags/testkit-flags.json index f8d2b6c..2d0256f 100644 --- a/evaluator/flags/testkit-flags.json +++ b/evaluator/flags/testkit-flags.json @@ -497,7 +497,7 @@ }, "is_privileged": { "or": [ - {"$ref": "is_ballmer"}, + {"==": ["ballmer@macrosoft.com", {"var": ["email"]}]}, {"==": ["admin", {"var": ["role"]}]} ] } diff --git a/flags/evaluator-refs.json b/flags/evaluator-refs.json index f6ad8f3..1b22a48 100644 --- a/flags/evaluator-refs.json +++ b/flags/evaluator-refs.json @@ -66,7 +66,12 @@ }, "is_privileged": { "or": [ - {"$ref": "is_ballmer"}, + { + "==": [ + "ballmer@macrosoft.com", + {"var": ["email"]} + ] + }, { "==": [ "admin",