feat(openfeature): emit server-side EVP flagevaluation#3984
feat(openfeature): emit server-side EVP flagevaluation#3984leoromanovsky wants to merge 20 commits into
Conversation
…ith PREP-01 libdatadog - Enable 'flagevaluation-evp' feature on datadog-ffe dep (FfeFlagEvaluationBatch type now compiled) - Fix components-rs/bytes.rs: update 4x VecMap::remove() -> remove_slow() for libdatadog compat post-commit 74284cac7 (VecMap API renamed); this unblocks compilation against the PREP-01 libdatadog ref
…patch - Two-tier aggregation in components-rs/ffe.rs: full→degraded→drop-counted with caps GLOBAL_CAP=131072/PER_FLAG_CAP=10000/DEGRADED_CAP=32768 - Killswitch DD_FLAGGING_EVALUATION_COUNTS_ENABLED (default: on) via evp_enabled() in Rust and isEvpEnabled() in EvaluationMetricRecorder.php - ddog_ffe_flush_flag_evaluation_batch() Rust C-export dispatches SidecarAction::FfeFlagEvaluationBatch via sidecar_blocking::enqueue_actions - ddtrace_ffe_flush_flag_evaluation_batch() C wrapper in tracer/ffe.c mirrors existing exposure/metric flush pattern with sidecar globals - RSHUTDOWN call added in tracer/ddtrace.c after existing flush calls - 11 Rust unit tests covering both tiers, overflow, drain, killswitch
…EVP aggregator race ddog_ffe_evaluate() records into the global EVP_AGGREGATOR; without EVP_TEST_LOCK the test ran concurrently with degraded_tier_overflow tests, causing dropped_degraded_overflow to be 2 instead of 1.
… + regen Cargo.lock Points dd-trace-php's libdatadog submodule at the local PREP-01 commit containing the flagevaluation EVP emitter (FfeFlagEvaluationBatch), so components-rs builds against it via the datadog-ffe path dep with the flagevaluation-evp feature. NOTE: 89a2ba7fc is local/unpushed — re-point to the merged upstream libdatadog SHA before any PR.
The Rust C-export ddog_ffe_flush_flag_evaluation_batch (components-rs/ffe.rs) was added without a matching prototype in the committed cbindgen header components-rs/datadog.h. tracer/ffe.c calls it, so PHP8's stricter toolchain fails with -Werror=implicit-function-declaration (ddtrace.so link Error 2). PHP7 only warned and linked, masking the bug. Prototype matches the Rust signature (SidecarTransport**/InstanceId*/QueueId*/CharSlice x3).
…ow drops The full-tier EVP flagevaluation drain previously emitted context: None and drained the degraded-overflow drop count silently. - Full tier now carries the pruned evaluation context (shared prune_context bounds: <=256 fields, string values >256 bytes skipped) plus context.dd.service, matching the degraded tier's cap enforcement. The pruned context is captured once per bucket at insertion and carried verbatim into the drained event. - The degraded-tier overflow drop counter is read-and-reset at drain and logged via tracing::warn when non-zero, so an undersized degradedCap is observable instead of a silent loss of legitimate counts.
…low surfacing - ddog_ffe_evaluate_populates_evp_aggregator_for_flush / _respects_killswitch: drive the real FFI entry point ddog_ffe_evaluate (the function the PHP/C layer calls) and assert it feeds the aggregator that the sidecar flush drains, closing the 'unit-green but emits nothing' gap that earlier tests left uncovered. - full_tier_event_carries_pruned_context / _prunes_oversized_string_values / _empty_context_emits_no_context_object: assert the full tier carries the pruned context and enforces the field/value bounds. - drain_resets_degraded_overflow_drop_counter: assert drain reads-and-resets the observable overflow drop counter.
…ncode-safe wire + reliable enqueue) Bump the libdatadog submodule to the bincode-safe flagevaluation fix (DataDog/libdatadog#2117): the worker->sidecar IPC is bincode, which the old serde_json::Value + skip_serializing_if wire types could not deserialize, so the sidecar silently dropped every batch. - Stringify the pruned full-tier context (JSON object string) at drain so the bincode wire stays plain; the sidecar flusher re-expands it into a JSON object for the POST. - Use sidecar_blocking::enqueue_actions_reliable for the one-shot RSHUTDOWN flush.
|
…2446-evp-flagevaluation-php # Conflicts: # libdatadog
Benchmarks [ tracer ]Benchmark execution time: 2026-06-20 02:12:53 Comparing candidate commit 9093fb9 in PR branch Some scenarios are present only in baseline or only in candidate runs. If you didn't create or remove some scenarios in your branch, this maybe a sign of crashed benchmarks 💥💥💥 Scenarios present only in candidate:
Found 0 performance improvements and 1 performance regressions! Performance is the same for 193 metrics, 0 unstable metrics.
|
…2446-evp-flagevaluation-php # Conflicts: # libdatadog
Motivation
PHP server-side flag evaluations need to emit aggregated EVP
flagevaluationpayloads through the native Rust/C and libdatadog sidecar path while preserving the existing OTel metric and exposure paths. The emitted events must match the live flageval-worker contract: schema-visible aggregation dimensions only, no OpenFeaturereason, bounded context before buffering, andtargeting_rule.keyonly when real targeting-rule metadata exists.Changes
reasonout of EVP payloads and aggregation keys.libdatadogto3350d4b55c0815143e656f334967e4e4b6dd11f5, which contains the shared flagevaluation sidecar delivery fixes.Decisions
reasonis not a hidden aggregate key.Validation Evidence
Validated with PHP SDK commit
9093fb9439fb34a69b0926df3c315435557e9abc, libdatadog commit3350d4b55c0815143e656f334967e4e4b6dd11f5, and the merged system-tests flagevaluation baseline plus the local singular-path/overflow contract fix.RUSTC_BOOTSTRAP=1 cargo check -p datadog-php- PASS.RUSTC_BOOTSTRAP=1 cargo test -p datadog-php ffe -- --nocapture- PASS, 23 passed../tooling/bin/build-debug-artifact gnu-aarch64-8.0-nts /Users/leo.romanovsky/gsd-workspaces/flag-evaluations-cross-sdk/system-tests-clean-php/binaries- PASS; produceddd-library-php-1.21.0-aarch64-linux-gnu.tar.gz.SYSTEM_TEST_BUILD_TIMEOUT=1800 ./build.sh --library php --weblog-variant apache-mod-8.0fromsystem-tests-clean-php- PASS on 2026-06-20.TEST_LIBRARY=php WEBLOG_VARIANT=apache-mod-8.0 ./run.sh +l php FEATURE_FLAGGING_AND_EXPERIMENTATION -k "test_flag_eval_evp"- PASS on 2026-06-20,8 passed, 2627 deselected in 60.08swithLibrary: php@1.21.0.payloads=30,events=10195, totalevaluation_count=12708;evp-degradation-flagemitted10001rows with totalevaluation_count=12000, including one degraded row withevaluation_count=2000and omittedtargeting_key/context.app-php7andapp-php8-openfeaturewithDD_EVP_PROXY_CONFIG_ADDITIONAL_ENDPOINTS={}; both returned 5/5 successful evaluations forffe-dogfooding-string-flag.server-evp-e2e-php7-1781931066-user-server-evp-e2e-php8-openfeature-1781931066-user-{ "total_count": null, "by_path": {} }.