feat(ffe): add runtime-backed PHP feature flag evaluation#3906
feat(ffe): add runtime-backed PHP feature flag evaluation#3906leoromanovsky wants to merge 15 commits into
Conversation
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 782f622 | Docs | Datadog PR Page | Give us feedback! |
|
Benchmarks [ tracer ]Benchmark execution time: 2026-05-24 04:07:22 Comparing candidate commit 78e9f65 in PR branch Found 0 performance improvements and 1 performance regressions! Performance is the same for 193 metrics, 0 unstable metrics. scenario:MessagePackSerializationBench/benchMessagePackSerialization
|
…stone-1-runtime-evaluation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e55ebb976b
ℹ️ 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".
| EvaluationError::FlagDisabled => (ERROR_NONE, REASON_DISABLED), | ||
| EvaluationError::DefaultAllocationNull => (ERROR_NONE, REASON_DEFAULT), |
There was a problem hiding this comment.
Preserve disabled/default results instead of null coercion
For a disabled flag this returns error_code = 0 with value_json = "null", but ResultMapper::map() treats any zero-error result as a real variation value and then fails to coerce null to the requested type, converting disabled flags into TYPE_MISMATCH errors instead of returning the caller default with EvaluationReason::DISABLED. The same path affects DefaultAllocationNull; handle these no-assignment cases before decoding or surface an error/default signal that the PHP mapper can distinguish.
Useful? React with 👍 / 👎.
Brings the PHP FFE diagram convention to the M1 PR. Each subsequent PR in the stack (#3909, #3910, #3911) already carried its own stack + system diagram; #3906 was missing them. Mirrors the format used by the rest of the stack: - `stack-pr3906.mmd` — the 4-PR stack with #3906 badged as current and the downstream layers shown as "future". - `system-pr3906.mmd` — the target end-to-end architecture with M1's scope (UserCode, OpenFeature Client, DataDogProvider, DDTrace FeatureFlags Client, NativeEvaluator, Remote Config client) highlighted, and everything from the Hook layer onward dashed. All conventions match the other branches: quoted YAML titles (to keep `#PR-number` out of the YAML comment parser), `flowchart TD` orientation, rendered with `-w 2400 -H 2400 --scale 3 -b white`.
Motivation
This PR adds real server-side PHP feature flag evaluation backed by Remote Config and the
libdatadognative evaluator. PHP 7 gets a Datadog API, PHP 8 can use the optional OpenFeature bridge, and both paths use the same live runtime evaluator.This is intentionally the evaluation layer only. Exposure delivery, exposure caching, and evaluation metrics land in the later hook, exposure, and metrics PRs.
Shared planning doc: https://docs.google.com/document/d/1NvMfTpZWLBlFmEFNjdnlMyeVpy5l7KD8qujGFco6w2w/edit?tab=t.0
Decisions
productionRuntime=falseremains a temporary guardrail while the hook, exposure delivery, and evaluation metrics layers are incomplete. The final production-ready PHP FFE stack should not ship with that warning enabled.bool,int,float,string) into the native evaluator. Nested arrays, objects, and null attribute values are dropped at the boundary.DDTrace\Testing\ffe_load_configexists only for local/canonical fixture tests.Where this PR fits in the stack
This is the bottom layer of the 4-PR stack. #3909 adds the shared hook, while #3910 (EVP exposures) and #3911 (OTLP metrics) build on top of that hook.
Where this PR fits in the target system
This PR contributes the in-PHP evaluation surface:
UserCode->OpenFeature Client(PHP 8) /DDTrace FeatureFlags Client(PHP 7 + 8), theDDTrace OpenFeature DataDogProvider, theNativeEvaluatorFFI bridge into libdatadog, and the Remote Config client for theFFE_FLAGSproduct.Changes
libdatadogFFE evaluator path and keeps PHP user-facing APIs as thin adapters over the native runtime.DDTrace\FeatureFlagsevaluation through live Remote Config.DDTrace\OpenFeatureprovider bridge.DataDog/ffe-system-test-datasubmodule and a native-runtime PHPT loop overufc-config.jsonandevaluation-cases/*.json.Not Included
Validation
php vendor/bin/phpunit --config phpunit.xml tests/api/Unit/FeatureFlags tests/OpenFeature/DataDogProviderTest.php: 29 tests / 87 assertions.make test_featureflags: 8 tests / 29 assertions.MAX_TEST_PARALLELISM=1 TESTS=tests/ext/ffe/native_bridge_evaluate.phpt make test_c: 1/1 passed.MAX_TEST_PARALLELISM=1 TESTS=tests/ext/ffe/system_test_data_evaluate.phpt make test_c: 1/1 passed.make test_internal_api_randomized: passed.Dogfooding Validation
See DataDog/ffe-dogfooding#68.
Ran the PHP 7 and PHP 8 servers locally; observed correct evaluations.