feat(ffe): send the split serial id on exposure events [EX-3425] - #4135
Conversation
The exposures intake uses the serial id to find the holdout an allocation comes from. The compiler rewrites a holdout into an ordinary allocation before an SDK receives it, so the serial id is the only link back to it. Carry the serial id from the evaluation result through the exposure buffer into the sidecar FFI struct. Serial ids are zero-based per organization, so 0 is a real value and cannot signal absence; the value travels with a separate presence flag, matching the existing FfeResult convention. Advance libdatadog to 0c0c60b96, which adds the two fields to ddog_FfeExposure and owns serialization, the wire key, and exposure deduplication. Regenerate the affected headers with make cbindgen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
39b2adc to
13f46a7
Compare
|
Benchmarks [ tracer ]Benchmark execution time: 2026-08-25 19:37:57 Comparing candidate commit 13f46a7 in PR branch Found 4 performance improvements and 0 performance regressions! Performance is the same for 190 metrics, 0 unstable metrics.
|
Description
Sends the split serial id on the exposure events that
dd-trace-phpemits. The exposures intake uses the serial id to find the holdout an allocation comes from. The compiler rewrites a holdout into an ordinary allocation before an SDK receives it, so the serial id is the only link back to it.The serial id travels from the evaluation result, through the exposure buffer, into the sidecar FFI struct. Serial ids are zero-based per organization, so
0is a real value and cannot signal absence. The value therefore carries a separate presence flag, matching the existingFfeResultconvention in this file.tracer/functions.cresult.serial_idandresult.has_serial_idinto the recordertracer/ffe.cddog_FfeExposuretracer/ffe.hlibdatadog0c0c60b96components-rs/common.h,components-rs/sidecar.h,Cargo.lockSerialization, the wire key, and exposure deduplication live in libdatadog and are done there: DataDog/libdatadog#2402. That PR also fixed the deduplication cache, which compared only allocation key and variant, so a serial id that appeared or changed on an otherwise unchanged assignment was suppressed.
The submodule bump is required, not incidental:
ddog_FfeExposuregains its two fields in0c0c60b96, so the header and the compiled Rust struct must move together.components-rs/sidecar.handCargo.lockare generated output, regenerated here withmake cbindgen. Their churn is accumulated drift rather than a consequence of this change. The checked-in headers were last regenerated in 018f212, and the submodule pointer has advanced twice since then (#4118, #4123) without a regeneration, so this run sweeps up everything in between. Concretely,sidecar.hgains two additiveddog_sidecar_send_trace_v1_*declarations from 69df7ed9b, which nothing in this repo calls, andCargo.lockgains thezripcrates. Reviewingtracer/plus the three added lines incommon.hcovers the whole behavioural change.This overlaps #4125, which bumps to a commit that predates
0c0c60b96; whichever lands second needs a rebase.No validation is applied to the value. The flag configuration layer owns that.
Testing
PHP 8.3 debug on
bookworm, submodule at0c0c60b96:make -j4 alllinksffe.oandfunctions.owith no new warningsmake test_c TESTS=tests/ext/ffepasses 6/6, none skippedserialId: 0reportsserialId=0withdoLog=true, a split omitting it reportsnull, andflush_ffe_exposures()hands the batch to the sidecarNo test here covers the buffer-to-FFI hop. The exposure buffer is not observable from PHP, and no test in this repo asserts an exposure reaching the agent. Cross-language coverage comes from system-tests, where
Test_FFE_Exposure_Serial_Idand the three serial-id caching classes already exist;manifests/php.ymlgets flipped offmissing_feature (EX-3425)in a follow-up once this ships.Reviewer checklist
This description was generated by Claude.