Repository navigation
feat: Add the override store, overlay, source interfaces, and data system wiring - #364
Draft
kinyoklion wants to merge 6 commits into
Draft
kinyoklion wants to merge 6 commits into
kinyoklion wants to merge 6 commits into
Conversation
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
September 28, 2026 20:39
aff3a67 to
ae86267
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
September 28, 2026 20:39
49ba8e2 to
d9e0211
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 1, 2026 23:43
ae86267 to
533647f
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 1, 2026 23:43
d9e0211 to
092ed5c
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 3, 2026 01:34
533647f to
511de7f
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 3, 2026 01:34
092ed5c to
716b005
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 3, 2026 01:52
511de7f to
33e2973
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 3, 2026 01:52
716b005 to
041e7a5
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 5, 2026 21:55
33e2973 to
22c3c01
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 5, 2026 21:55
041e7a5 to
91ecadb
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 5, 2026 22:12
22c3c01 to
426dbe4
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 5, 2026 22:12
91ecadb to
5d664c1
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 5, 2026 22:28
426dbe4 to
167a54a
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 5, 2026 22:28
5d664c1 to
c875758
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 5, 2026 23:56
167a54a to
6894b3d
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 5, 2026 23:56
c875758 to
8ad94ca
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 13, 2026 21:03
6894b3d to
f0fca10
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 13, 2026 21:03
8ad94ca to
b47e5ff
Compare
…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.
A definition whose dependencies cannot be computed, such as a prerequisite without a key or a segment match on a value that is not a string, is logged and contributes no dependency edges, so every directly changed key is still notified. A failure to determine or deliver the notifications is logged instead of reaching the override source.
…uit and dispose on a failed start Before the client is initialized, an evaluation proceeds only when the override layer holds the flag; otherwise it takes the same path as without an override source. The exception paths of evaluation and of the all-flags state keep the override indicator when the definition came from the layer. An override source whose Build or Start throws fails the client constructor after the components created so far are disposed.
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-model-evaluator
branch
from
October 13, 2026 22:13
f0fca10 to
f083d90
Compare
kinyoklion
force-pushed
the
rlamb/overrides-dotnet-override-layer
branch
from
October 13, 2026 22:13
b47e5ff to
0864b85
Compare
…n changes A flag override can reference LaunchDarkly data: a rule that matches a LaunchDarkly segment, or a prerequisite that is a LaunchDarkly flag. DataSourceUpdatesImpl computes flag change notifications from a dependency tracker built from LaunchDarkly data alone, so when such a segment or flag changed, the flags whose overrides depend on it were not notified. The override layer now keeps the dependency edges of its own entries, rebuilt on every replacement, and the data source updates ask it for the override entries that depend on a changed item. The chain can cross in both directions, so each newly reached item is expanded through both sets of edges until nothing new is found. An entry whose references cannot be read contributes no edges, the same as the change computation skips it.
Member
Author
|
bugbot review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 625311a. Configure here.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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>)andDataSystemConfiguration.OverrideSource. At most one source is accepted.IOverrideSource(Start(IOverrideSink),IDisposable) andIOverrideSink.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):OverrideLayerholds 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.OverrideOverlayimplements 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.OverrideSinkapplies 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 layer first, so an overridden flag is served before the client has LaunchDarkly data while a flag the layer does not hold takes exactly the path it took before this feature. An evaluation that fails with an unexpected exception keeps the marking when the flag came from the layer. A malformed override definition is logged and skipped during change computation so the other notifications still fire, and a source whose Build or Start throws leaves nothing started.
AllFlagsStatereads 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 hastrackEventsandtrackReasonoff and nodebugEventsUntilDate, 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.
SDK-3248
Follow-up from review
A LaunchDarkly change now notifies the flags whose overrides depend on it. The override layer keeps the dependency edges of its own entries, rebuilt on every replacement, and
DataSourceUpdatesImplexpands each changed LaunchDarkly item through both its own tracker and the layer's until nothing new is reached, so an override that matches a LaunchDarkly segment or has a LaunchDarkly prerequisite is notified like the LaunchDarkly flags that depend on it. An entry whose references cannot be read contributes no edges, the same as the change computation skips it.Note
Overview
Adds experimental flag overrides to the FDv2 data system so operators can force per-key flag/segment definitions that win over LaunchDarkly at read time, without affecting initialization or data-source status.
Configuration:
DataSystemBuilder.Overrides(...)andIOverrideSource/IOverrideSinkplug intoDataSystemConfiguration; the source starts synchronously before data sources and is skipped when offline.Runtime:
OverrideLayer+OverrideOverlaysit on the read-only store boundary;OverrideSinkapplies full snapshots and fans out flag change notifications (including dependency tracking across LaunchDarkly data and override entries viaIExternalDependencies).LdClientcan evaluate overridden flags before the client is initialized, adjustsAllFlagsState(override-only when needed, disables tracking fields whenoverrideAffected), and disposes cleanly on build/start failures.Tests: Unit coverage for layer/overlay/sink/builder/client plus OVERRIDE spec vectors in
override-vectors.json.Reviewed by Cursor Bugbot for commit 625311a. Bugbot is set up for automated code reviews on this repo. Configure here.