Skip to content

feat: Add the override store, overlay, source interfaces, and data system wiring - #364

Draft
kinyoklion wants to merge 1 commit into
rlamb/overrides-dotnet-model-evaluatorfrom
rlamb/overrides-dotnet-override-layer
Draft

kinyoklion wants to merge 1 commit into
rlamb/overrides-dotnet-model-evaluatorfrom
rlamb/overrides-dotnet-override-layer

Conversation

@kinyoklion

Copy link
Copy Markdown
Member

Summary

Adds the override store, the overlay at the store read boundary, the override source interfaces, and the data system wiring for flag overrides, as defined by the OVERRIDE specification. With this change an application can configure an override source on the FDv2 data system and have its flags and segments take precedence over LaunchDarkly data at evaluation time.

Configuration surface: DataSystemBuilder.Overrides(IComponentConfigurer<IOverrideSource>) and DataSystemConfiguration.OverrideSource. At most one source is accepted. IOverrideSource (Start(IOverrideSink), IDisposable) and IOverrideSink.SetOverrides(FullDataSet<ItemDescriptor>) follow the shape of the data source interfaces, so an application can supply a custom source the same way it supplies a custom data source. The SDK builds the source when the client is created, starts it before the data sources so that its initial load completes inside the client constructor, and disposes it with the client. A configuration error in the source propagates from the constructor like any other invalid component configuration. The source is not built when the client is offline. Without a configured source the SDK is unchanged.

The override layer (Internal/Overrides): OverrideLayer holds the entries as an immutable map swapped on every snapshot, marking copies of the supplied definitions so the source's own objects are never modified. OverrideOverlay implements the data system's read-only store: a read returns the override entry when one exists and the LaunchDarkly entry otherwise, an enumeration returns the union with override entries winning, and initialization status still comes from the base store. OverrideSink applies snapshots one at a time and computes the flags an update may have changed, including dependency fan-out through prerequisites and segments over both the old and the new merged views, then sends the same flag change notifications a LaunchDarkly change would.

Client behavior: the not-initialized short-circuit consults the override store first, so an overridden flag is served before the client has LaunchDarkly data while a non-overridden flag still returns the client-not-ready default. AllFlagsState reads through the overlay, so it includes override-only flags and, before initialization, returns a state built from overrides alone (with a warning logged once). A flag whose evaluation is override-affected keeps its value, version, and marked reason in the state but has trackEvents and trackReason off and no debugEventsUntilDate, because a consumer of the state must not send individual events for it. A wrong-type result keeps the marking on its reason.

The specification's test vectors run as a unit test against the full client stack (value, variation index, and reason; the summary-counter contribution is asserted once the events change lands). Unit tests cover the layer, overlay, sink, the builder, and the client behaviors above.

This PR is based on the branch of the model and evaluator marking change, which it depends on.

…stem wiring

Adds IOverrideSource and IOverrideSink, the DataSystemBuilder.Overrides
option, and the override layer: an immutable store of marked entries, an
overlay at the store read boundary that returns the override entry for a
key in preference to LaunchDarkly data, and a sink that applies snapshots
one at a time and sends flag change notifications for the flags an update
may have changed, with dependency fan-out through prerequisites and
segments.

The FDv2 data system builds the configured source, starts it before the
data sources so its initial load completes inside the client constructor,
and disposes it with the client. The client consults the override store
before its not-initialized short-circuit, so an overridden flag is served
before LaunchDarkly data arrives. AllFlagsState reads through the overlay
and presents override-affected flags with event tracking off. The OVERRIDE
specification's test vectors run as a unit test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant