Repository navigation
feat(ffe): add future-experiments-only opt-out mode - #2710
Conversation
📚 Documentation Check Results📦
|
🔒 Cargo Deny Results📦
|
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: ec56508 | Docs | View more details | Give us feedback! |
BenchmarksComparisonBenchmark execution time: 2026-10-21 23:20:52 Comparing candidate commit ec56508 in PR branch Found 0 performance improvements and 4 performance regressions! Performance is the same for 10 metrics, 0 unstable metrics.
|
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | ec56508 | 1792624034 | leoromanovsky/experimentation-opt-out-future |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| single_flag_killswitch/rules-based | execution_time | 157.326ns | 160.002ns ± 2.112ns | 159.533ns ± 1.307ns | 161.103ns | 163.771ns | 166.304ns | 169.020ns | 5.95% | 1.218 | 1.604 | 1.32% | 0.149ns | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| single_flag_killswitch/rules-based | execution_time | [159.710ns; 160.295ns] or [-0.183%; +0.183%] | None | None | None |
Group 2
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | ec56508 | 1792624034 | leoromanovsky/experimentation-opt-out-future |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | execution_time | 34.655ms | 35.197ms ± 0.194ms | 35.196ms ± 0.117ms | 35.322ms | 35.526ms | 35.619ms | 35.676ms | 1.36% | -0.166 | -0.022 | 0.55% | 0.014ms | 1 | 200 |
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | throughput | 70074.576op/s | 71031.571op/s ± 391.582op/s | 71030.605op/s ± 236.042op/s | 71244.187op/s | 71717.747op/s | 72040.231op/s | 72140.179op/s | 1.56% | 0.198 | -0.004 | 0.55% | 27.689op/s | 1 | 200 |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | execution_time | 194.594ms | 195.693ms ± 0.402ms | 195.673ms ± 0.285ms | 195.968ms | 196.336ms | 196.687ms | 197.092ms | 0.72% | 0.172 | 0.277 | 0.20% | 0.028ms | 1 | 200 |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | throughput | 5073.785op/s | 5110.056op/s ± 10.482op/s | 5110.555op/s ± 7.450op/s | 5117.159op/s | 5127.387op/s | 5132.139op/s | 5138.898op/s | 0.55% | -0.158 | 0.264 | 0.20% | 0.741op/s | 1 | 200 |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | execution_time | 846.527µs | 848.839µs ± 1.193µs | 848.641µs ± 0.690µs | 849.481µs | 851.156µs | 851.882µs | 852.203µs | 0.42% | 0.652 | -0.009 | 0.14% | 0.084µs | 1 | 200 |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | throughput | 117343.000op/s | 117808.217op/s ± 165.476op/s | 117835.471op/s ± 95.756op/s | 117922.430op/s | 118042.259op/s | 118086.997op/s | 118129.771op/s | 0.25% | -0.646 | -0.019 | 0.14% | 11.701op/s | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | execution_time | [35.170ms; 35.224ms] or [-0.076%; +0.076%] | None | None | None |
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | throughput | [70977.302op/s; 71085.841op/s] or [-0.076%; +0.076%] | None | None | None |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | execution_time | [195.638ms; 195.749ms] or [-0.028%; +0.028%] | None | None | None |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | throughput | [5108.603op/s; 5111.508op/s] or [-0.028%; +0.028%] | None | None | None |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | execution_time | [848.673µs; 849.004µs] or [-0.019%; +0.019%] | None | None | None |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | throughput | [117785.284op/s; 117831.151op/s] or [-0.019%; +0.019%] | None | None | None |
Group 3
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | ec56508 | 1792624034 | leoromanovsky/experimentation-opt-out-future |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sdk_test_data/rules-based | execution_time | 265.089µs | 271.484µs ± 12.794µs | 268.379µs ± 1.378µs | 270.538µs | 284.356µs | 322.862µs | 402.747µs | 50.07% | 6.899 | 59.354 | 4.70% | 0.905µs | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| sdk_test_data/rules-based | execution_time | [269.711µs; 273.257µs] or [-0.653%; +0.653%] | None | None | None |
Group 4
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | ec56508 | 1792624034 | leoromanovsky/experimentation-opt-out-future |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | execution_time | 31.818ms | 31.977ms ± 0.070ms | 31.980ms ± 0.045ms | 32.024ms | 32.064ms | 32.168ms | 32.219ms | 0.75% | 0.052 | 0.493 | 0.22% | 0.005ms | 1 | 200 |
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | throughput | 77592.844op/s | 78182.333op/s ± 170.138op/s | 78173.631op/s ± 110.205op/s | 78288.436op/s | 78464.615op/s | 78572.217op/s | 78572.418op/s | 0.51% | -0.036 | 0.467 | 0.22% | 12.031op/s | 1 | 200 |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | execution_time | 203.781ms | 204.818ms ± 1.608ms | 204.307ms ± 0.191ms | 204.531ms | 209.738ms | 209.869ms | 209.921ms | 2.75% | 2.643 | 5.257 | 0.78% | 0.114ms | 1 | 200 |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | throughput | 4763.699op/s | 4882.670op/s ± 37.552op/s | 4894.594op/s ± 4.575op/s | 4898.562op/s | 4903.612op/s | 4905.785op/s | 4907.232op/s | 0.26% | -2.637 | 5.234 | 0.77% | 2.655op/s | 1 | 200 |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | execution_time | 703.565µs | 705.292µs ± 1.263µs | 705.252µs ± 0.447µs | 705.698µs | 706.325µs | 706.575µs | 720.550µs | 2.17% | 8.812 | 104.830 | 0.18% | 0.089µs | 1 | 200 |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | throughput | 138782.781op/s | 141785.759op/s ± 249.983op/s | 141793.368op/s ± 89.860op/s | 141881.121op/s | 142036.628op/s | 142116.547op/s | 142133.221op/s | 0.24% | -8.656 | 102.384 | 0.18% | 17.676op/s | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | execution_time | [31.967ms; 31.986ms] or [-0.030%; +0.030%] | None | None | None |
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | throughput | [78158.753op/s; 78205.913op/s] or [-0.030%; +0.030%] | None | None | None |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | execution_time | [204.595ms; 205.041ms] or [-0.109%; +0.109%] | None | None | None |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | throughput | [4877.465op/s; 4887.874op/s] or [-0.107%; +0.107%] | None | None | None |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | execution_time | [705.117µs; 705.467µs] or [-0.025%; +0.025%] | None | None | None |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | throughput | [141751.114op/s; 141820.404op/s] or [-0.024%; +0.024%] | None | None | None |
Baseline
Baseline benchmark details
Group 1
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | 0200047 | 1792534561 | leoromanovsky/experimentation-opt-out-immediate |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| single_flag_killswitch/rules-based | execution_time | 157.780ns | 160.676ns ± 2.374ns | 160.523ns ± 1.748ns | 161.769ns | 164.681ns | 168.435ns | 170.222ns | 6.04% | 1.479 | 2.922 | 1.47% | 0.168ns | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| single_flag_killswitch/rules-based | execution_time | [160.347ns; 161.005ns] or [-0.205%; +0.205%] | None | None | None |
Group 2
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | 0200047 | 1792534561 | leoromanovsky/experimentation-opt-out-immediate |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | execution_time | 34.216ms | 34.497ms ± 0.118ms | 34.495ms ± 0.087ms | 34.584ms | 34.669ms | 34.733ms | 34.811ms | 0.92% | -0.088 | -0.315 | 0.34% | 0.008ms | 1 | 200 |
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | throughput | 71816.353op/s | 72470.401op/s ± 247.867op/s | 72475.249op/s ± 183.087op/s | 72656.875op/s | 72913.243op/s | 73046.364op/s | 73064.996op/s | 0.81% | 0.106 | -0.313 | 0.34% | 17.527op/s | 1 | 200 |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | execution_time | 179.731ms | 180.539ms ± 0.345ms | 180.564ms ± 0.255ms | 180.789ms | 181.062ms | 181.360ms | 181.638ms | 0.60% | 0.019 | -0.148 | 0.19% | 0.024ms | 1 | 200 |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | throughput | 5505.449op/s | 5538.989op/s ± 10.588op/s | 5538.217op/s ± 7.800op/s | 5546.779op/s | 5557.435op/s | 5560.710op/s | 5563.864op/s | 0.46% | -0.008 | -0.155 | 0.19% | 0.749op/s | 1 | 200 |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | execution_time | 839.845µs | 842.156µs ± 1.003µs | 842.193µs ± 0.761µs | 842.918µs | 843.880µs | 844.179µs | 844.758µs | 0.30% | 0.132 | -0.600 | 0.12% | 0.071µs | 1 | 200 |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | throughput | 118377.160op/s | 118743.083op/s ± 141.449op/s | 118737.593op/s ± 107.334op/s | 118855.069op/s | 118958.215op/s | 119017.479op/s | 119069.522op/s | 0.28% | -0.127 | -0.603 | 0.12% | 10.002op/s | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | execution_time | [34.481ms; 34.514ms] or [-0.047%; +0.047%] | None | None | None |
| flagevaluation_evp/payloads/scale/2500flags_500users_20fields | throughput | [72436.049op/s; 72504.753op/s] or [-0.047%; +0.047%] | None | None | None |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | execution_time | [180.491ms; 180.587ms] or [-0.026%; +0.026%] | None | None | None |
| flagevaluation_evp/payloads/stress/10flags_1000users_250fields | throughput | [5537.522op/s; 5540.457op/s] or [-0.026%; +0.026%] | None | None | None |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | execution_time | [842.016µs; 842.295µs] or [-0.017%; +0.017%] | None | None | None |
| flagevaluation_evp/payloads/typical/100flags_50users_10fields | throughput | [118723.480op/s; 118762.687op/s] or [-0.017%; +0.017%] | None | None | None |
Group 3
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | 0200047 | 1792534561 | leoromanovsky/experimentation-opt-out-immediate |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sdk_test_data/rules-based | execution_time | 257.222µs | 262.976µs ± 12.642µs | 259.665µs ± 1.292µs | 261.753µs | 276.438µs | 312.822µs | 388.313µs | 49.54% | 6.588 | 53.767 | 4.80% | 0.894µs | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| sdk_test_data/rules-based | execution_time | [261.224µs; 264.728µs] or [-0.666%; +0.666%] | None | None | None |
Group 4
| cpu_model | git_commit_sha | git_commit_date | git_branch |
|---|---|---|---|
| Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz | 0200047 | 1792534561 | leoromanovsky/experimentation-opt-out-immediate |
| scenario | metric | min | mean ± sd | median ± mad | p75 | p95 | p99 | max | peak_to_median_ratio | skewness | kurtosis | cv | sem | runs | sample_size |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | execution_time | 31.164ms | 31.417ms ± 0.093ms | 31.423ms ± 0.061ms | 31.481ms | 31.551ms | 31.601ms | 31.774ms | 1.12% | -0.126 | 0.718 | 0.30% | 0.007ms | 1 | 200 |
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | throughput | 78680.024op/s | 79575.986op/s ± 236.314op/s | 79560.404op/s ± 155.192op/s | 79738.173op/s | 80015.467op/s | 80166.984op/s | 80220.695op/s | 0.83% | 0.150 | 0.697 | 0.30% | 16.710op/s | 1 | 200 |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | execution_time | 188.755ms | 189.968ms ± 1.621ms | 189.452ms ± 0.249ms | 189.714ms | 194.688ms | 195.093ms | 195.241ms | 3.06% | 2.495 | 4.625 | 0.85% | 0.115ms | 1 | 200 |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | throughput | 5121.877op/s | 5264.423op/s ± 43.996op/s | 5278.388op/s ± 6.936op/s | 5284.540op/s | 5291.277op/s | 5295.277op/s | 5297.864op/s | 0.37% | -2.485 | 4.588 | 0.83% | 3.111op/s | 1 | 200 |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | execution_time | 694.462µs | 695.882µs ± 0.740µs | 695.850µs ± 0.506µs | 696.363µs | 697.141µs | 697.844µs | 698.112µs | 0.33% | 0.357 | -0.182 | 0.11% | 0.052µs | 1 | 200 |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | throughput | 143243.509op/s | 143702.627op/s ± 152.852op/s | 143709.124op/s ± 104.483op/s | 143810.904op/s | 143939.697op/s | 143975.662op/s | 143996.259op/s | 0.20% | -0.352 | -0.189 | 0.11% | 10.808op/s | 1 | 200 |
| scenario | metric | 95% CI mean | Shapiro-Wilk pvalue | Ljung-Box pvalue (lag=1) | Dip test pvalue |
|---|---|---|---|---|---|
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | execution_time | [31.404ms; 31.430ms] or [-0.041%; +0.041%] | None | None | None |
| flagevaluation_evp/coalescer/scale/2500flags_500users_20fields | throughput | [79543.235op/s; 79608.736op/s] or [-0.041%; +0.041%] | None | None | None |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | execution_time | [189.743ms; 190.192ms] or [-0.118%; +0.118%] | None | None | None |
| flagevaluation_evp/coalescer/stress/10flags_1000users_250fields | throughput | [5258.326op/s; 5270.521op/s] or [-0.116%; +0.116%] | None | None | None |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | execution_time | [695.780µs; 695.985µs] or [-0.015%; +0.015%] | None | None | None |
| flagevaluation_evp/coalescer/typical/100flags_50users_10fields | throughput | [143681.443op/s; 143723.811op/s] or [-0.015%; +0.015%] | None | None | None |
|
Consolidated into #2698, which now includes immediate and future-experiments-only modes and pins DataDog/ffe-system-test-data#52. GitHub marked this stacked PR as merged when its commit was fast-forwarded into the #2698 branch. These changes have not merged into main. |
What does this PR do?
Adds
FutureExperimentsOnlyevaluation and an enum-based C entry point using the existingdd_experimentation_opt_out_atcontext attribute. The existing immediate-mode C interface remains unchanged.Motivation
Customers can stop participation in future experiments while allowing older allocations to continue evaluation. Allocations activated at or after the subject's opt-out time are skipped; missing or null activation does not qualify an allocation as older.
Additional Notes
Stack: immediate opt-out #2698 → this PR → Ruby native integration on dd-trace-rb #6521.
This adds
randomizationActivatedAtdecoding with per-flag error isolation and pins shared fixtures #52.The cutoff matches Go #5700 and Java #12950; it does not establish previous subject enrollment or change evaluation telemetry.
How to test the change?
Tests cover all three modes, nanosecond boundaries, timezone offsets, malformed input, unknown activation, ordinary fallback, exposure selection, and both C entry points.
The shared suite exercises 361 baseline cases, 26 immediate cases, and 42 future cases.
Packaged C-example execution and Ruby process-level system tests remain pending because local disk space is exhausted.