Skip to content

test(openfeature): use canonical FFE fixtures - #19390

Open
leoromanovsky wants to merge 13 commits into
mainfrom
leo.romanovsky/ffe-canonical-fixtures-20260512
Open

test(openfeature): use canonical FFE fixtures#19390
leoromanovsky wants to merge 13 commits into
mainfrom
leo.romanovsky/ffe-canonical-fixtures-20260512

Conversation

@leoromanovsky

@leoromanovsky leoromanovsky commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Description

Motivation

Use the shared FFE fixture corpus so Python does not maintain a drifting copy of evaluator behavior. This also corrects two evaluator bugs exposed by the canonical cases: invalid regular expressions and variant values that do not match the declared flag type must resolve with PARSE_ERROR, while other invalid flag configurations retain the provider's existing default behavior.

The initial submodule approach made fresh clones and local test runs depend on recursive submodule setup. This revision follows the checked-in snapshot workflow merged in dd-trace-dotnet: tests work immediately after cloning, while an automated job keeps the snapshot linked to the canonical repository.

Canonical fixture implementations are also merged in dd-trace-java, dd-trace-go, and libdatadog.

Changes

  • Replace the ffe-system-test-data submodule with ordinary checked-in fixture files at the same source commit, f3da9ae.
  • Add a stdlib-only updater that validates refs and fixture JSON, rejects symlinks, normalizes file permissions, and copies files according to a consumer-owned disallow list.
  • Add a weekly/manual workflow that checks canonical main and opens a signed draft PR only when allowed fixture contents change.
  • Read the canonical configuration and evaluation cases from the checked-in snapshot and assert both values and reasons.
  • Return PARSE_ERROR for invalid regex and declared-variant-type mismatches without invalidating the rest of the UFC.
  • Remove submodule-specific Dependabot and test-runner configuration.

Decisions

  • Keep this PR on its existing canonical fixture revision so the migration from submodule to snapshot does not silently add new evaluator requirements.
  • Let future fixture updates arrive as isolated draft PRs. New cases may intentionally make those PRs red when they expose downstream evaluator bugs; the tracer fix is made in that update PR before it is merged.
  • Keep the copy disallow list in dd-trace-py, so this repository controls which upstream files become part of its test tree.
  • Generate a SOURCE.md containing the exact upstream commit instead of maintaining Git metadata in the test directory.

Testing

  • scripts/run-tests --venv 1cdebe0 -- -s -- tests/internal/test_update_ffe_fixtures.py — 12 passed on Python 3.13.
  • scripts/run-tests --venv 14fc413 -- -s -- tests/openfeature/test_provider_fixtures.py tests/openfeature/test_provider.py — 673 passed, 2 skipped on Python 3.13.
  • scripts/lint checks — passed.
  • Ran the updater twice at f3da9ae; the second run reported changed=false.
  • Dry-ran the updater against current canonical main (ea8b5cc) and confirmed it exposes the expected follow-up evaluator gaps rather than bundling them into this migration.

Risks

The snapshot adds checked-in test data, but it is test-only. The scheduled workflow receives repository write access only through the scoped STS policy and uses it to create a signed draft PR when fixture contents change.

Additional Notes

The fixture update flow is:

  1. Add or change a case in DataDog/ffe-system-test-data.
  2. The weekly job fetches canonical main, validates and compares the allowed snapshot contents, and exits without a PR when nothing changed.
  3. When fixtures changed, it opens or updates a signed draft PR with the source SHA.
  4. OpenFeature CI runs the new cases. If they expose a Python evaluator bug, that PR remains red until the implementation is corrected; otherwise it can be reviewed and merged as a fixture-only update.

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codeowners resolved as

Resolved from the full PR diff against main using the target branch CODEOWNERS file.
CODEOWNERS team requests not listed below are not required by the current file set.

.github/chainguard/self.update-ffe-fixtures.create-pr.sts.yaml          @DataDog/python-guild @DataDog/apm-core-python
.github/workflows/update-ffe-fixtures.yml                               @DataDog/python-guild @DataDog/apm-core-python
scripts/update-ffe-fixtures.py                                          @DataDog/python-guild
src/native/ffe.rs                                                       @DataDog/apm-core-python
tests/internal/test_update_ffe_fixtures.py                              @DataDog/apm-core-python
tests/openfeature/ffe-system-test-data/SOURCE.md                        @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-boolean-false-assignment.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-boolean-one-of-matches.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-comparator-operator-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-disabled-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-empty-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-empty-string-variation.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-falsy-value-assignments.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-flag-with-empty-string.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-integer-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-invalid-shard-bounds-isolation.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-kill-switch-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-malformed-flag-isolation.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-microsecond-date-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-missing-split-shards-isolation.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-new-user-onboarding-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-no-allocations-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-null-operator-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-null-targeting-key.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-numeric-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of-default.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-of-7-empty-targeting-key.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-regex-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-start-and-end-date-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-unknown-fields-tolerance.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-case-unknown-operator-isolation.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-flag-that-does-not-exist.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-json-config-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-no-allocations-flag.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-special-characters.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/evaluation-cases/test-string-with-special-characters.json  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/ffe-system-test-data/ufc-config.json                  @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/test_provider.py                                      @DataDog/feature-flagging-and-experimentation-sdk
tests/openfeature/test_provider_fixtures.py                             @DataDog/feature-flagging-and-experimentation-sdk

@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Jul 30, 2026

Copy link
Copy Markdown

Pipelines  Tests

Unblock PR with BitsAI

⚠️ Warnings

🚦 9 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-py | build linux serverless: [amd64, cp315-cp315, v126532274-233089d-musllinux_1_2_x86_64, 1]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux serverless: [arm64, cp315-cp315, v113741357-d2b8243-manylinux2014_aarch64, 1]   View in Datadog   GitLab

DataDog/apm-reliability/dd-trace-py | build linux: [amd64, cp315-cp315, v113741238-d2b8243-manylinux2014_x86_64]   View in Datadog   GitLab

View all 9 failed jobs.

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 7a20072 | Docs | Datadog PR Page | Give us feedback!

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Jul 30, 2026

Copy link
Copy Markdown

Circular import analysis

⚠️ Existing circular imports

There are 5 circular imports that already exist on the base branch and have not been changed by this PR.

ddtrace.contrib.internal.pytorch._distributed -> ddtrace.contrib.internal.pytorch._rank_root -> ddtrace.contrib.internal.pytorch._distributed
ddtrace.contrib.internal.django.patch -> ddtrace.contrib.internal.django.response -> ddtrace.contrib.internal.django.patch
ddtrace.llmobs -> ddtrace.llmobs._evaluators -> ddtrace.llmobs._evaluators.format -> ddtrace.llmobs._experiment -> ddtrace.llmobs
ddtrace.errortracking._handled_exceptions.bytecode_injector -> ddtrace.errortracking._handled_exceptions.callbacks -> ddtrace.errortracking._handled_exceptions.collector -> ddtrace.errortracking._handled_exceptions.bytecode_reporting -> ddtrace.errortracking._handled_exceptions.bytecode_injector
ddtrace.appsec._asm_request_context -> ddtrace.appsec._iast._iast_request_context_base -> ddtrace.appsec._iast._iast_env -> ddtrace.appsec._iast.reporter -> ddtrace.appsec._exploit_prevention.stack_traces -> ddtrace.appsec._asm_request_context

@leoromanovsky leoromanovsky added the changelog/no-changelog A changelog entry is not required for this PR. label Jul 30, 2026
gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/dd-trace-go that referenced this pull request Jul 31, 2026
## Motivation

Use the shared FFE fixture corpus. This prevents copied Go fixtures from drifting from other SDKs.

The same migration is merged in [Java](DataDog/dd-trace-java#11355) and [libdatadog](DataDog/libdatadog#1979). Related migrations are open for [Python](DataDog/dd-trace-py#19390), [JavaScript](DataDog/dd-trace-js#8441), [Ruby](DataDog/dd-trace-rb#5742), and [.NET](DataDog/dd-trace-dotnet#8616).

## Changes and Decisions

- Add `DataDog/ffe-system-test-data` as an OpenFeature test submodule.
- Read all canonical configuration and evaluation cases from the submodule.
- Parse and validate flags independently so one invalid flag does not reject valid neighbors.
- Assert canonical values and reasons, including temporal defaults and missing-flag errors.
- Initialize submodules in Go test workflows and configure weekly Dependabot updates.

Co-authored-by: leo.romanovsky <leo.romanovsky@datadoghq.com>
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 10, 2026

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

There are 255 dependency direction violations that already exist on the base branch and have not been changed by this PR.

Show existing violations (showing 5 of 255 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=134)
ddtrace.aiguard._api_client -×-> ddtrace.trace  (product:aiguard -> product:tracing, score=132)
ddtrace.llmobs._integrations.vertexai -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=132)
ddtrace.debugging._debugger -×-> ddtrace.trace  (product:debugging -> product:tracing, score=132)
ddtrace.llmobs._integrations.llama_index -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=132)

To see all violations, download the layers-base.json and layers-pr.json artifacts from this CI job and run:

uv run --script scripts/import-analysis/layers.py compare layers-base.json layers-pr.json

@pr-commenter

pr-commenter Bot commented Aug 10, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-08-14 06:04:58

Comparing candidate commit 7a20072 in PR branch leo.romanovsky/ffe-canonical-fixtures-20260512 with baseline commit 37d2e79 in branch main.

Found 0 performance improvements and 9 performance regressions! Performance is the same for 608 metrics, 10 unstable metrics.

scenario:httppropagationextract-datadog_tracecontext_tracestate_not_propagated_on_trace_id_no_match

  • 🟥 execution_time [+4.988µs; +5.215µs] or [+7.389%; +7.726%]

scenario:httppropagationinject-ids_only

  • 🟥 execution_time [+2.627µs; +2.811µs] or [+12.366%; +13.234%]

scenario:iastaspects-add_aspect

  • 🟥 execution_time [+7.299µs; +9.323µs] or [+7.353%; +9.393%]

scenario:iastaspects-lower_aspect

  • 🟥 execution_time [+43.240µs; +48.834µs] or [+18.630%; +21.040%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+111.896µs; +118.691µs] or [+27.403%; +29.067%]

scenario:iastaspectssplit-rsplit_aspect

  • 🟥 execution_time [+19.005µs; +22.004µs] or [+13.717%; +15.882%]

scenario:span-start

  • 🟥 execution_time [+1.195ms; +1.420ms] or [+7.434%; +8.829%]

scenario:telemetryaddmetric-1-count-metric-1-times

  • 🟥 execution_time [+321.729ns; +368.106ns] or [+12.354%; +14.134%]

scenario:tracer-small

  • 🟥 execution_time [+32.279µs; +34.910µs] or [+9.300%; +10.058%]

@leoromanovsky
leoromanovsky marked this pull request as ready for review August 10, 2026 20:21
@leoromanovsky
leoromanovsky requested review from a team as code owners August 10, 2026 20:21

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 19a708bce3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/native/ffe.rs
Comment on lines +314 to +315
EvaluationError::FlagConfigurationInvalid => {
ResolutionDetails::empty(Reason::Default)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve parse errors for other malformed conditions

When an enabled flag contains a condition parse failure other than an invalid regex—for example, GT with a string, ONE_OF with a scalar, IS_NULL with a non-boolean, or an invalid semantic version—the pinned libdatadog evaluator collapses the per-flag failure to FlagConfigurationInvalid. Because the new pre-scan only records regex and variation-value errors, this arm now makes the provider report DEFAULT without an error, whereas the parent implementation reported ERROR/PARSE_ERROR. Preserve the parse status for these cases or classify all equivalent parser failures before changing this mapping.

AGENTS.md reference: AGENTS.md:L11-L11

Useful? React with 👍 / 👎.

test_id = f"{fixture_file.replace('.json', '')}_{i}_{test_case.get('targetingKey', 'no_key')}"
all_test_cases.append((fixture_file, test_case, test_id))

assert all_test_cases, f"No FFE JSON fixtures found in {FIXTURES_DIR}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Initialize canonical fixtures in the standard test runner

In a fresh clone without --recurse-submodules, this directory is absent or empty, so collection reaches this assertion with no cases and the documented scripts/run-tests workflow cannot run the OpenFeature suite. The new tests/suitespec.yml variables cover the generated GitLab OpenFeature job, but neither scripts/run-tests nor another repository setup hook initializes the submodule, leaving local and other non-GitLab test runs broken unless contributors know an undocumented prerequisite. Have the standard runner initialize the pinned submodule or explicitly handle and document the requirement.

AGENTS.md reference: AGENTS.md:L8-L8

Useful? React with 👍 / 👎.

@brettlangdon brettlangdon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we get docs updates and agents.md/something llm focused updated as well?

I don't think this should have a big impact on anyone, since these fixtures should only get loaded when running the openfeature test suite, but I want it to be clear to people how to resolve the issue with the fact that they won't have the fixtures by default (no one is going to actually use git submodule command, especially if it isn't for their own files)

the concern is mostly, if someone changes something that impacts openfeature and they try to validate the test suite locally, then they will fail because the fixtures aren't present, what can we do to avoid that?

@brettlangdon brettlangdon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Rejecting only to prevent merging until we figure out the process we want in the other SDKs, but other than small improvements to local devex this lgtm

leoromanovsky added a commit to DataDog/dd-trace-dotnet that referenced this pull request Aug 14, 2026
## Motivation

Use the shared FFE fixture corpus so the .NET evaluator is checked
against the same behavior as the other tracer implementations. This
reduces fixture drift and gives us a repeatable way to expose and
correct evaluator bugs when new canonical cases are added.

The same fixture corpus is used by
[Java](DataDog/dd-trace-java#11355),
[libdatadog](DataDog/libdatadog#1979),
[Go](DataDog/dd-trace-go#4753),
[Python](DataDog/dd-trace-py#19390),
[JavaScript](DataDog/dd-trace-js#8441), and
[Ruby](DataDog/dd-trace-rb#5742).

## Changes

- Replace the legacy copied fixtures with a generated, checked-in
snapshot from `DataDog/ffe-system-test-data`.
- Record the exact upstream commit in `SOURCE.md`.
- Add a script that fetches, validates, and copies the canonical
configuration and evaluation cases.
- Add a weekly and manually dispatchable workflow that opens a signed
draft dependency PR only when fixture contents have changed.
- Parse flags independently so malformed flags do not reject valid
neighbors.
- Return `FLAG_NOT_FOUND` for missing flags and classify temporal,
static, and split allocations.
- Assert canonical values and reasons through the existing .NET
unit-test suite.

## Fixture update flow

When we add or change shared evaluator behavior, I imagine the flow
working like this:

1. Add the new configuration and evaluation cases to
[`DataDog/ffe-system-test-data`](https://github.com/DataDog/ffe-system-test-data)
and review the expected behavior there.
2. The weekly updater, or a manually dispatched run for a specific ref,
fetches the canonical repository and compares its fixture contents with
the checked-in .NET snapshot.
3. If nothing changed, the workflow exits without opening or updating a
PR.
4. If fixtures changed, the workflow copies them into this repository,
records the source commit, and opens a signed draft PR with the normal
dependency labels.
5. The .NET unit tests run against the updated cases. New tests may
intentionally fail when they catch an evaluator bug or unsupported
behavior.
6. Address those evaluator failures in the same dependency PR, keeping
the fixture expectations unchanged unless the shared expectation itself
is incorrect.
7. Merge the update once the .NET evaluator satisfies the new canonical
cases.

This keeps new behavior explicit and reviewable: fixture changes land in
the canonical repository first, and each tracer then gets a visible
compatibility PR rather than silently changing at build time.

## Decisions

- `DataDog/ffe-system-test-data` remains the canonical source of shared
evaluator behavior.
- Keep the generated snapshot checked in so local and CI unit tests do
not require network access or submodule initialization.
- Use a scheduled dependency-update workflow instead of a git submodule.
- Treat failures introduced by new canonical fixtures as useful
regression signals and fix the evaluator as part of accepting the
update.
- Do not create a PR when the canonical fixture contents are unchanged,
even if the upstream repository has unrelated commits.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/no-changelog A changelog entry is not required for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants