Repository navigation
Conversation
DataDogProvider(flag_selection={"tags": [...], "key_patterns": [...]})
asks the agentless configuration endpoint for only the selected flags.
The selection is canonicalized (Unicode White_Space trim, dedupe, UTF-8
byte order) and validated against the 31-value, 200-byte and 8192-byte
URL limits before it is sent; an invalid selection loads every flag and
logs the reason. The first provider to start fetching claims the
process selection until the last provider shuts down. The ignored-
selection response header is sanitized and reported once per reason
after the configuration is applied, with flag_selection.dropped and
flag_selection.ignored counts. The fixture script also copies the
shared flag-selection vectors from the pinned snapshot.
Jira: FFL-3571
Environment: Datadog workspace
Codeowners resolved asResolved from the full PR diff against |
Dependency direction analysis
|
BenchmarksBenchmark execution time: 2026-11-06 18:52:23 Comparing candidate commit e9b1ba2 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 20 metrics, 0 unstable metrics.
|
Description
Jira: FFL-3571
Stacked on #21571, which fixes evaluation of contexts with nested attributes and pins the fixture snapshot to ffe-system-test-data
e8777633. The base branch ismark.cai/FFL-3624, so this diff shows only flag selection; it retargets tomainonce #21571 merges.Motivation
Services that use only part of an organization's flags still download, parse and hold the whole flag configuration. Flag selection lets a service ask the agentless configuration endpoint for only the flags it needs, by tag or by key pattern, so it transfers and keeps less configuration. Without a selection nothing changes.
This brings the server Python provider in line with the client SDKs: the browser (
@datadog/openfeature-browser2.2.0, openfeature-js-client#426) for option semantics, canonicalization, limits, request encoding and log strings, and iOS (dd-sdk-ios#3344) and Android (dd-sdk-android#4031) for sanitizing the ignored-selection response header. The two counts correspond to the client SDKs' flag selection dropped and ignored debug events.Changes
DataDogProvider(flag_selection={"tags": [...], "key_patterns": [...]}): a keyword-only constructor argument, canonicalized once in__init__(the caller's lists are copied). No environment variable.ddtrace/internal/openfeature/_flag_selection.py:White_Spacewith an explicit character set (notstr.strip(), which also strips U+001C to U+001F), drops empty values and duplicates, and sorts by UTF-8 bytes.malformed_selection(a top level that is not a mapping; a list that is not a list, tuple, set or frozenset, so a barestris rejected; a non-strelement,Noneincluded; a surrogate code point), thentoo_many_values(more than 31 values in a list), theninvalid_key_patternandinvalid_tag(more than 200 UTF-8 bytes).selected_flag_tags/selected_flag_key_patternsquery parameter, tags first, encoded withquote(value, safe=""), and merged into the existing query, including a custom base URL's. When the whole request URL, fragment included, would exceed 8192 bytes, the request goes out without the selection and reportstoo_many_values.flag_selection was not sent (<reason>: <limit>). Loading the full flag configuration.once per provider initialization;flag_selection was ignored by the server (<reason>). Loaded the full flag configuration.once per process per reason, after the configuration is applied.flag_selection.droppedandflag_selection.ignoredcounts in thetracersnamespace, tagged only withreason, once per process per reason._agentless_source.py: readsDD-Flag-Selection-Ignoredonly when a selection was sent and the response is a 200, never on a 304, an error or a request without a selection. An empty value is absent; anything other than one of the five known reasons byte for byte (malformed_selection,too_many_values,invalid_key_pattern,invalid_tag,tag_load_failed) is reported asunknown, including trailing whitespace or a comma-joined repeated header._source_selection.py: with flags delivered through Remote Config and a selection set, logs one warning per process (flag_selection is not supported when flags are delivered through Remote Config. Loading the full flag configuration.) and loads the full configuration.scripts/update-ffe-fixtures.pyalso copies and checksflag-selection/selection-vectors.json, so the pinned snapshot now includes the shared selection vectors.Decisions
tagsandkey_patterns. Unknown keys,keyPatternsincluded, are ignored, as the browser ignores unknown keys.malformed_selectionlimit text is the browser's sentence with this SDK's names:flag_selection must be a dict with optional tags and key_patterns string arrays.DD-Flag-Selection-Ignoredis read only on a 200 because that is the only 2xx status this source applies.flag_selection.droppedis counted where the "not sent" error is logged, that is, for the provider whose own selection could not be sent. A later provider with a different selection gets only the second-selection warning.Testing
tests/openfeature/test_flag_selection.py:safe="";tests/internal/test_update_ffe_fixtures.py: the selection vectors are copied, symlinks are rejected, and the vectors are validated.Validation Evidence
Dogfooding and system-tests validation have not run yet. They need the ffe-dogfooding Python app to pass the selection through and the parametric
ffe_startwiring for Python; both are follow-ups that build on this branch.Risks
Additional Notes
The
flag_selection.droppedandflag_selection.ignoredmetric names are new.