Repository navigation
Conversation
The FDv2 streaming and polling requests, and the FDv1 fallback polling request, no longer send the filter query parameter. FDv2 already logged that payload filtering was unsupported and that the payload_filter_key option had no effect, but the requests still sent it. The behavior now matches the warning. The FDv1 data system keeps its payload filter support until the FDv1 removal deletes it. The contract tests no longer map the payloadFilter data system setting. The filtering capabilities stay, because only harness v2 tests them, against FDv1.
TestDataV2 gains use_preconfigured_flag, and FlagBuilderV2 gains migration_settings, sampling_ratio, exclude_from_summaries and a nested FlagMigrationSettingsBuilder. The v1 TestData has all of these, and v9 removes v1 TestData with the FDv1 data system, so TestDataV2 must cover them first. A preconfigured flag keeps its own version, as in v1 TestData, because tests use specific versions to check the evaluation and event output. A flag that replaces an existing flag gets the next version. A preconfigured flag also discards any stored builder for its key, so a later flag call starts from a new builder.
The shared spec config now gives the client an FDv2 data system with no sources, in place of the FDv1 null data source. Specs that need data use TestDataV2 as a synchronizer, and specs that need a persistent store use a hash-backed MockFeatureStore through the data system config. The end-to-end and environment ID specs poll the FDv2 endpoint with an FDv2 payload. On a 401, FDv2 turns the data source off at once and does not retry, so those specs now expect OFF, a single request and no full start wait, in place of the FDv1 retry behavior. The tracker specs use the V2 flag builder. The FDv2 store specs gain the flag change cases that only the FDv1 data source specs covered: flags that a full data set adds or removes, a deleted prerequisite, and a removed dependency. The nil SDK key and use_ldd fork specs still use FDv1 options, because they test FDv1 logic in LDClient. They change with that logic when FDv1 is removed.
|
Note Agent-authored comment. This finding comes from an automated multi-agent review of this PR (general / security / adversarial / spec-conformance agents, graded against
|
|
Note Agent-authored comment. From the same automated multi-agent review as the boundary-validation comment above, posted with the account owner's review and approval. Verified by executing the PR head. Replacement version clamp discards a higher provided version (
|
|
Note Agent-authored comment. Same automated multi-agent review as the two comments above, posted with the account owner's review and approval. Both halves of this were proven deterministically by executing the PR head (a blocking fake instance for the delivery ordering, and a direct store-level test for the missing version check). Out-of-order upsert delivery + no stale-version rejection in the FDv2 store = clients can stick on a stale flagTwo cooperating layers: Layer 1 — delivery is not serialized with commit. Both Layer 2 — the store accepts the regression. Concrete trigger in a test suite: a "reset these flags" helper racing a test body that updates the same key — the test then reads back the wrong variation with no error anywhere. Labeling, for fairness: the compute-inside/deliver-outside pattern is pre-existing in Suggested direction: cheapest correct fix for this PR is propagating upserts while holding the lock (the critical section is short — an enqueue per instance). The more robust fix, at FDv2-infra scope rather than this PR, is adding stale-version rejection to Proof specs for both layers fail today ( |
…rder use_preconfigured_flag and use_preconfigured_segment now convert the input to a new hash with symbol keys at every level, check it, and raise ArgumentError for an input that is not a valid flag or segment: nil or another type, a missing or empty key, a version that is not an integer, malformed JSON, or a data model error. Before, a hash parsed from JSON kept string keys below the top level and evaluated wrongly, and a malformed item was accepted and later made the whole initial data set fail to load while the data source reported VALID. Both methods also accept a JSON string, as v1 TestData did, and store a copy, so later changes to the caller's object have no effect. A preconfigured flag now keeps a provided version that is greater than the version of the flag it replaces, and otherwise gets the next version. This matches Go's TestDataV2 and the test data source spec, which requires the increment only when the provided version is not greater. Version 0 on a new flag becomes 1. update, use_preconfigured_flag and use_preconfigured_segment now hold a mutex across the change and its delivery to the data source instances. Before, two concurrent changes could reach an instance in the opposite order to the one in which they were made.
The previous commit normalized a preconfigured flag or segment with a JSON round trip. JSON.generate calls to_s on a value it cannot encode, so a Set, a Time or another object became a string with no error. A segment whose included keys were a Set then failed to match. NaN, Infinity, and a hash with the same key as a string and a symbol raised JSON::GeneratorError in place of ArgumentError. The item is now copied value by value. A Set becomes an array and a symbol value becomes a string, as in JSON. Any other value that JSON cannot hold, a value that is not finite, a hash key that is not a string or symbol, a repeated key, and nesting deeper than 100 levels raise ArgumentError. The delivery order spec now has a deadline for the first thread and always releases it, so a failure cannot hang the suite.
…r update FlagRuleBuilderV2#build put the builder's own clause array into the built flag. A rule builder that the test kept after update could then add clauses to the stored flag. This changed what later clients received without a version change or a delivered update. The build now copies each clause and its values.
|
Fixed in f4887c4 and aadae60. Agreed that |
|
Fixed in f4887c4, with Go's semantics: the stored version is |
|
Layer 1 is fixed in f4887c4. Layer 2, the missing stale-version rejection in |
|
Correction on layer 2: there won't be a separate PR. FDv2 guarantees upstream that payloads arrive in order, so TestDataV2 is a local source, so it has to keep that order itself. This PR fixes the order of changes between two updates. #491 fixes the other case, where a change made before a synchronizer starts was sent again after the initial data. |
TestDataV2 gains use_preconfigured_flag, and FlagBuilderV2 gains
migration_settings, sampling_ratio, exclude_from_summaries and a nested
FlagMigrationSettingsBuilder. The v1 TestData has all of these, and v9
removes v1 TestData with the FDv1 data system, so TestDataV2 must cover
them first.
A preconfigured flag keeps its own version, as in v1 TestData, because
tests use specific versions to check the evaluation and event output. A
flag that replaces an existing flag gets the next version. A
preconfigured flag also discards any stored builder for its key, so a
later flag call starts from a new builder.
The shared spec config now gives the client an FDv2 data system with no
sources, in place of the FDv1 null data source. Specs that need data use
TestDataV2 as a synchronizer, and specs that need a persistent store use
a hash-backed MockFeatureStore through the data system config.
The end-to-end and environment ID specs poll the FDv2 endpoint with an
FDv2 payload. On a 401, FDv2 turns the data source off at once and does
not retry, so those specs now expect OFF, a single request and no full
start wait, in place of the FDv1 retry behavior.
The tracker specs use the V2 flag builder. The FDv2 store specs gain the
flag change cases that only the FDv1 data source specs covered: flags
that a full data set adds or removes, a deleted prerequisite, and a
removed dependency.
The nil SDK key and use_ldd fork specs still use FDv1 options, because
they test FDv1 logic in LDClient. They change with that logic when FDv1
is removed.
Note
Overview
TestDataV2 now supports preconfigured flags the same way v1 did:
use_preconfigured_flagnormalizes JSON/hashes/models, validates via deserialization, applies version rules (keep higher version or bump), clears any stored builder for that key, and broadcasts under an update mutex so deliveries stay ordered. Segments share the same normalization path; subscribe replaces add_instance and hands synchronizers a snapshot in one step sosynconly queues changes after that baseline.TestDataSourceV2 uses a shared
fetch_resultfor initial loads;fetchsnapshots current data;syncsubscribes insidefetch_resultso pre-sync updates are not replayed. FlagBuilderV2 gains migration_settings, sampling_ratio, exclude_from_summaries, and a small FlagMigrationSettingsBuilder; rules now copy clause value arrays when building.Specs and mocks move from FDv1
data_sourcetodata_system_config(TestDataV2,fdv2_poll_payload, polling/streaming builders, SilentSynchronizer, MockFeatureStore). End-to-end and 401 cases expect FDv2 behavior (e.g. OFF, single request, no long init wait). Store specs add dependency/delete cases; test_data_v2 and migration specs cover the new APIs and ordering.Reviewed by Cursor Bugbot for commit c638040. Bugbot is set up for automated code reviews on this repo. Configure here.