Repository navigation
feat: Split summary counters and suppress individual events for override-affected evaluations - #452
Merged
Merged
Conversation
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
September 25, 2026 22:51
e2df553 to
e4d05bb
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
September 25, 2026 22:51
89f544e to
be39b66
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
September 28, 2026 20:36
e4d05bb to
09915cc
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
September 28, 2026 20:36
be39b66 to
6ff51f4
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
October 1, 2026 23:43
09915cc to
4f4c242
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 1, 2026 23:44
6ff51f4 to
e0dd518
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
October 3, 2026 00:46
4f4c242 to
54278dc
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 3, 2026 00:46
e0dd518 to
356fee9
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
October 3, 2026 01:54
54278dc to
0dee958
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 3, 2026 01:54
356fee9 to
de05ef4
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
October 8, 2026 16:54
0dee958 to
18341e8
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 8, 2026 16:54
de05ef4 to
aae4984
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
October 13, 2026 22:12
18341e8 to
45c6daa
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
2 times, most recently
from
October 16, 2026 21:40
db462f2 to
21046ad
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 28, 2026 22:18
21046ad to
d5133ec
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
2 times, most recently
from
October 28, 2026 22:53
0b2876b to
d02bf8a
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 28, 2026 23:28
d02bf8a to
1cd5585
Compare
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 1cd5585. Configure here.
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
October 29, 2026 16:49
1cd5585 to
e58b756
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
November 3, 2026 23:58
0a4c8b7 to
827c4e2
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
November 3, 2026 23:58
e58b756 to
11d2d5c
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
November 4, 2026 19:20
11d2d5c to
bd01623
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
2 times, most recently
from
November 4, 2026 19:48
40612a6 to
8023cbc
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
2 times, most recently
from
November 4, 2026 20:47
178e890 to
a9b7419
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
November 4, 2026 20:47
8023cbc to
65c2ed1
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
November 4, 2026 22:55
a9b7419 to
1fb2959
Compare
keelerm84
approved these changes
Nov 5, 2026
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
November 6, 2026 23:47
1fb2959 to
725a09b
Compare
kinyoklion
force-pushed
the
rlamb/overrides-ruby-store-overlay
branch
from
November 6, 2026 23:47
a9befc7 to
1005ed0
Compare
kinyoklion
marked this pull request as ready for review
November 6, 2026 23:53
Base automatically changed from
rlamb/overrides-ruby-store-overlay
to
feat/overrides
November 6, 2026 23:56
kinyoklion
added a commit
that referenced
this pull request
Nov 6, 2026
<!-- TERMAG_PR_BODY_BEGIN --> ## Summary This PR is stacked on #450 because it uses the override marker, the evaluator marking, and the reason indicator that PR adds. This change adds the override layer that the OVERRIDE specification describes: a runtime-mutable collection of flag and segment definitions that takes precedence over LaunchDarkly data at the store read boundary, populated by an override source through a sink. With no override source configured the SDK behaves exactly as before. The file-based source, the events changes, and the contract test service follow in later PRs. `LaunchDarkly::Interfaces::Overrides::OverrideSource` and `OverrideSink` define how a source supplies complete snapshots to the SDK. The sink accepts data model objects or hashes in the flag and segment data model. The SDK marks the entries itself. `Impl::Overrides::Layer` holds marked entries in an immutable hash that is swapped on update, so the layer holds exactly one snapshot at any instant and reads are lock-free. `Impl::Overrides::Overlay` sits at the store read boundary: a read for a key returns the override entry when one exists and the LaunchDarkly entry otherwise, an enumeration is the union with the override entry winning, and initialization status is the base store's alone. `Impl::Overrides::Sink` applies snapshots and notifies flag change listeners of every flag whose merged-view evaluation may have changed, including flags that depend on an overridden prerequisite or segment. It computes dependency edges over both the old and the new merged view, as the Go reference does. `DataSystem::ConfigBuilder#overrides` accepts one override source builder, the same `build(sdk_key, config)` protocol as the data source builders. The FDv2 data system builds the source at construction, so an invalid configuration raises from `LDClient.new` like other invalid component configuration. It starts the source before its run loop, so the initial load is in effect before the constructor returns. An exception from the source's `start` does not prevent the client from starting: the SDK logs it, stops the source, removes any snapshot the source supplied, and the client runs without overrides (the SDK's own file source does not raise from `start`; a custom source could). It serves reads through the overlay. When the client closes, the sink stops accepting snapshots before the source is stopped, and an exception from `stop` is logged. An offline client builds no source and logs a warning that the configured source is not started. The client consults the override store before the not-initialized short-circuit. An overridden flag is served before LaunchDarkly data arrives, read from the override store itself, and a flag that is not overridden still returns the client-not-ready default, even when a store without an init marker holds LaunchDarkly data for it. `all_flags_state` reads through the overlay. Before initialization, when the store is not initialized and the override store holds flags, it returns a state of those flags alone, read from the override store, with a once-per-client warning; with no override flags the state is invalid, as it is without a source. Without a source this state is empty, because the SDK reports no flags before the store is initialized, so the override flags only add to what it reports; overrides never remove a flag from the state. A failure of the base store to list its flags propagates through the overlay, and `all_flags_state` logs it as without a source. Without a source the state is then invalid and empty; with override flags it holds those flags and stays invalid, so the overrides only add to it. A client-side SDK bootstrapped from the state uses its flags whatever `$valid` says (js-client-sdk 3.x and the 4.x browser SDK only log a warning), so the overridden values still reach it. A wrong-type migration result keeps the marking of the evaluation it replaces. When the evaluator raises for a flag that came from the override store, `variation_detail` and `all_flags_state` report the `EXCEPTION` error reason with `override_affected` set, from the flag's own marker. This also fixes a pre-existing crash: `all_flags_state` raised `NoMethodError` when an evaluation raised, because the failed flag has no evaluation state; it now reports that flag with no prerequisites. The marker is read only from the SDK's model objects: a custom store can return a flag as a plain hash, as the `FeatureStore` interface documents, and such a flag never came from the override store, so its failed evaluation still returns the unmarked `EXCEPTION` result instead of raising. A value-only override expands, through the file loading code from #449, into a flag that is on and serves its single value by fallthrough, which reports the FALLTHROUGH reason kind as the specification describes. The OVERRIDE specification's test vectors (`spec/fixtures/override-vectors/vectors.json`) run as a spec through the full client stack, checking value, variation index, and reason under the vectors' comparison rules. The vectors' per-evaluation summary marker is asserted once the event processor carries the marking, in the events PR. LaunchDarkly changes reach override dependents. `Layer` keeps a dependency graph of its entries in each snapshot, and `Store` expands every changed LaunchDarkly item through both its own graph and the layer's, to a fixpoint. A change to a prerequisite flag or a segment that an override entry references therefore notifies that entry's flag, the same way dependent flags are notified for LaunchDarkly data, and a chain may cross between LaunchDarkly data and overrides any number of times. The FDv2 store's defect that seeded its dependency fan-out with symbol keys, while `Impl::DependencyTracker` indexes dependents under string keys, is fixed on `main` by #470, which the stack's base now includes. The fan-out helper here also compares keys as strings, which the fixpoint needs in any case, and the store spec keeps the #470 specs beside this PR's specs for the override layer. Verification: specs for the layer (marking, replacement, snapshot atomicity under concurrent writers), the overlay (precedence, union, deleted base items, base failure, initialization), the sink (added, removed, changed, and unchanged entries, dependency fan-out through prerequisites and nested segments, both merged views, no-listener path, base failure, serialized updates), the FDv2 wiring (construction, start order, overlay reads, stop, offline, availability unaffected), the client (not-ready gate, all-flags state, change notifications through the flag tracker, migration marker, lifecycle), and the specification vectors. Full suite and RuboCop are clean, and the full suite passes on JRuby 9.4 (the specs wait on queues without `Queue#pop`'s timeout, which Ruby 3.1 and JRuby 9.4 lack). Each new spec was checked against a deliberate defect in the code it covers. The existing FDv1 and FDv2 file data sources keep their current behavior. This series does not change them; the override feature is additive. [SDK-3249](https://launchdarkly.atlassian.net/browse/SDK-3249) [SDK-3249]: https://launchdarkly.atlassian.net/browse/SDK-3249?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > **feat: Add the override store, overlay, and data system wiring** > > Adds experimental, runtime flag/segment overrides: `DataSystem::ConfigBuilder#overrides` accepts an `OverrideSource` builder, FDv2 builds `Layer` + `Overlay` + `Sink`, wires `Store` to cross-graph dependency notifications, and extends evaluator/reason plumbing so prerequisites, segments, and client APIs respect override markers while still documenting that the surface is experimental. > > **Highlights** > > - New override layer modules (`Impl::Overrides::{Layer,Overlay,Sink}`) plus `Interfaces::Overrides` contracts mark model objects, merge overrides ahead of LD data, and fan-out flag-change listeners using merged dependency graphs. > - `EvaluationReason`, evaluator state, prerequisite records, migrations, and `LDClient` paths (`variation_detail`, `all_flags_state`) now propagate `overrideAffected`, handle uninitialized stores by consulting pure override snapshots, and keep JSON compatibility by emitting the bit only when true. > - FDv2 data system starts/stops override sources safely (offline skip, resilient `start`/`stop`), exposes `override_items`, and coordinates with `Store` via external dependency graphs; specs/vectors cover layer semantics, notifier behavior, client flows, and file-data reloader timing fixes on coarse clocks. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1005ed0. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> The all-flags report keeps an override-affected flag's `trackEvents`, `trackReason`, and `debugEventsUntilDate` in this PR; #452 turns them off (OVERRIDE Requirement 1.4.1.1) together with the rest of the event policy for override-affected evaluations. <!-- TERMAG_PR_BODY_END --> <!-- termag: box=i-0575d1c54853058d7 project=Overrides --> <sub>Opened from termag</sub>
…ide-affected evaluations Carries the override-affected marking from evaluation into analytics events, as the OVERRIDE specification requires. - `EvalEvent` and `record_eval_event` carry an `override_affected` flag. The client sets it from the evaluation result for the evaluated flag, from each prerequisite record's own marking for prerequisite evaluations, and from the flag's own marker when an evaluation raises. An unknown flag is never marked. - The event dispatcher produces no individual feature event and no debug event for a marked evaluation, whatever the flag's configuration requests. Marked evaluations appear in summary events only. - The summarizer keys counters by version, variation, and the marker, so override-affected and other evaluations of the same flag, variation, and version accumulate into separate counters. The summary event writes `overrideAffected: true` on the marked counters only, like the existing `unknown` marker. - `all_flags_state` presents an override-affected flag with `trackEvents` false, `trackReason` false, and no `debugEventsUntilDate`. The flag, its value, its version, and its reason stay in the state. The specification vectors now also check the summary marker the client hands to the event processor for each evaluation. Flag overrides are currently experimental and subject to change.
…raises When the evaluator raises in all_flags_state there is no evaluation result, so the state kept trackEvents, trackReason, and debugEventsUntilDate for an overridden flag. The flag's own override marker now decides, as it does for the reason and for the event of a single evaluation.
…jects A custom store can return a flag as a plain hash, as the FeatureStore interface documents. When its evaluation raised, the error event and the all_flags_state tracking fallback called override? on the hash and raised NoMethodError. Both now use the helper that reads the marker only from an object that has it, so such a failure is unmarked and keeps the flag's tracking, as before overrides.
kinyoklion
force-pushed
the
rlamb/overrides-ruby-events
branch
from
November 6, 2026 23:58
725a09b to
e2e01d8
Compare
kinyoklion
added a commit
that referenced
this pull request
Nov 10, 2026
<!-- TERMAG_PR_BODY_BEGIN --> ## Summary This PR is stacked on #452 because it supplies the override store that the earlier PRs add, and its client-level spec relies on the marked reasons and events they produce. This change adds `LaunchDarkly::Integrations::FileData.override_source`, the file-based override source that the OVERRIDE specification defines. It is configured with `LaunchDarkly::DataSystem::ConfigBuilder#overrides`: ```ruby overrides = LaunchDarkly::Integrations::FileData.override_source(paths: ["/etc/launchdarkly/overrides.json"]) config = LaunchDarkly::Config.new(data_system_config: LaunchDarkly::DataSystem.default.overrides(overrides).build) ``` The source reads one or more JSON or YAML files in the file data source document format (`flags`, `flagValues`, `segments`) and supplies complete snapshots to the SDK's override store. Its options are `paths` (required, non-empty strings in precedence order; a path listed more than once is logged and the repeats are ignored; on Windows, where file names ignore case, paths that differ only in case count as the same path), `duplicate_keys_handling` (`:fail`, the default, or `:ignore`, which keeps the first file's entry), `change_detection` (`:polling`, the default, or `:watching` through the optional `listen` gem), and `poll_interval` (default 1 second, raised to the 1 second minimum with a warning). Invalid options raise `ArgumentError` when the client is created, the same way other invalid component configuration is reported. Unlike the Go reference, an unrecognized `duplicate_keys_handling` value and an unknown option key are rejected rather than defaulted, because the specification treats invalid configuration as a construction error and an emergency mechanism should fail loudly. Behavior comes from the shared file data code added in #449: - The format comes from each file's name, as sdk-specs #272 recommends: a name that ends in `.yaml` or `.yml`, in any case, is YAML, and any other file, including one with no extension, is JSON. The existing file data sources read every file with the YAML parser, which also reads most JSON; the override source does not, so a YAML document in a `.json` file, or JSON with a `#` comment or a trailing comma, does not load. Files must be UTF-8; a UTF-16 file, as Windows PowerShell 5.1 writes with `>`, fails to load with a clear message and keeps the overrides in effect. - An empty JSON file is not a valid document: it fails to load and the overrides in effect stay. To remove a file's overrides, delete the file or write `{}`. - Override files can be rewritten in place. When the source finds a file whose overrides are in effect empty (or, for YAML, with only a comment or `---`), it holds the file back and keeps the overrides in effect until the new content is written: until the file has stayed so, unwritten, for one retry delay (1 second), and for at most five retry delays while it keeps being rewritten. Changes to the other files wait with it, since a reload applies all files or none. The mechanism is described in #449; the public docs say only what an application needs. - A configured file that does not exist contributes no overrides, so a file can be created later and deleting a file removes its overrides; a file that exists but cannot be read or parsed fails that reload and keeps the last good overrides, with a logged failure and a retry; a rewrite with identical content is not reapplied; the initial load completes before the client constructor returns. A `flagValues` entry expands into a flag that is on and serves the value by fallthrough, so the evaluation reports the FALLTHROUGH reason kind. Every applied change is logged at Info with the overrides in effect and what each file supplied, and the reloader's log lines for this source, including the hold's debug lines, carry a `FileOverrideSource` prefix. The `override_source` docs say how the format is chosen, that files must be UTF-8, that comments and repeated keys in JSON depend on the application's `json` gem, that files can be rewritten in place, how to remove a file's overrides, that an empty JSON file is not a valid document, and that replacing a YAML file in one operation avoids briefly applying a partly written file. ## Testing - Specs for the builder (defaults, absolute paths, every invalid option, `listen` requirement, poll interval clamping), the initial load (merge, fallthrough-form expansion, YAML, missing file, all files missing, malformed file, duplicate keys under both handlings), the Info log format, polling change detection (change, appearance, deletion, malformed edit with recovery, identical rewrite, stop, stop before start), watching change detection (change, appearance, deletion), and a client-level check of serving and reloading overrides through `LDClient`. - The specs rewrite override files in place with real, deliberately slow writes. End-to-end specs check that the source never supplies a snapshot without the override, and that a client never serves the LaunchDarkly value, while a JSON or YAML file is rewritten in place with a 300 ms pause, with polling and watching change detection; also for a YAML file whose leading comment is written before the pause, for five rewrites about a second apart with the default timing, for a JSON file and a YAML file that stay empty, and for files that are UTF-16 or not valid UTF-8, at startup and at runtime. - The in-place rewrite handling was reviewed in eight rounds as #479 (multi-agent and Bugbot reviews); see #449 for the mutation check (67 mutants, 60 killed, 7 equivalent) and the loops (10 runs in a row on Ruby 3.2 and on JRuby 9.4, no failures). - The `flag overrides` suite of sdk-test-harness (3.2.0-alpha.13, built from #515, whose override files are rewritten in place and have no extension) passes against the test service of #454: 79 tests ran, all passed. - Full suite and RuboCop are clean, apart from `can be automatically loaded by Bundler.require`, which needs write access to the system gem directory on the test machine. Each new spec was checked against a deliberate defect in the code it covers. The existing FDv1 and FDv2 file data sources keep their current behavior. This series does not change them; the override feature is additive. [SDK-3249](https://launchdarkly.atlassian.net/browse/SDK-3249) [SDK-3249]: https://launchdarkly.atlassian.net/browse/SDK-3249?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- TERMAG_PR_BODY_END --> <!-- termag: box=i-0575d1c54853058d7 project=Overrides --> <sub>Opened from termag</sub> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > Adds **`LaunchDarkly::Integrations::FileData.override_source`** so operators can load **flag and segment overrides from local JSON/YAML files** that take precedence over LaunchDarkly at evaluation time, wired through **`DataSystem::ConfigBuilder#overrides`**. The new **`FileOverrideSource`** reuses the shared **`FileData::Reloader`** (with **`skip_missing_paths`**, **`skip_unchanged`**, polling or optional `listen` watching) and logs applied overrides with a **`FileOverrideSource:`** prefix. > > **`Reloader`** gains a configurable **`log_prefix`** (default `[LDClient]`) and logs unexpected errors directly instead of **`Util.log_exception`**. > > Documentation examples for custom data systems now use **`data_system_config:`** and **`.build`** on **`DataSystem`** builders instead of the old **`data_system:`** shape. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 46b384f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
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
This PR is stacked on #451 because it uses the override store and the marking that PR wires into the client.
This change carries the override-affected marking from evaluation into analytics events, as the OVERRIDE specification requires. Event handling keys on the marking scalar that the client hands to the event processor, not on the evaluation reason.
EvalEventandrecord_eval_eventgain anoverride_affectedflag. The client sets it from the evaluation result for the evaluated flag, from each prerequisite record's own marking for prerequisite evaluations, and from the flag's own marker when an evaluation raises. An unknown flag is never marked.The event dispatcher produces no individual feature event and no debug event for a marked evaluation, whatever the flag's configuration requests. Marked evaluations appear in summary events only. The summarizer keys counters by version, variation, and the marker, so override-affected and other evaluations of the same flag, variation, and version accumulate into separate counters. The summary event writes
overrideAffected: trueon the marked counters only, following the existingunknownmarker. Event ingestion must accept that property on summary counters before release.all_flags_statepresents an override-affected flag withtrackEventsfalse,trackReasonfalse, and nodebugEventsUntilDate, so a consumer bootstrapped from the state sends no individual events for it. The flag, its value, its version, and its reason stay in the state. When an evaluation raises, there is no evaluation result, so the flag's own override marker decides, as it does for the reason and for the event of a single evaluation.The specification vectors now also check the summary marker the client hands to the event processor for each evaluation.
Verification: processor specs (no feature event, no debug event, marked counter, counter split, unmarked counters unchanged, marked prerequisite record), summarizer spec (split by marker), client specs (record arguments for direct, segment, prerequisite, unknown, and error cases; all-flags tracking fields including experiment tracking and details-only-for-tracked), and end-to-end payload specs through the real event processor (index plus marked summary only for an overridden flag, individual events for an unaffected prerequisite inside a marked evaluation, ordinary events when nothing is overridden). Full suite and RuboCop are clean. Each new spec was checked against a deliberate defect in the code it covers.
The existing FDv1 and FDv2 file data sources keep their current behavior. This series does not change them; the override feature is additive.
SDK-3249
Note
Overview
Analytics now threads an
override_affectedmarker from evaluations intoEvalEvent/record_eval_event. The client sets it from the evaluation result (and per-prerequisite marking for prereq records; flag-store marker on errors).Event pipeline: Override-affected evals still hit summary counters and index events, but no feature or debug events are emitted even when tracking or debug mode is on. The summarizer buckets counts by version, variation, and the marker; summary payloads add
overrideAffected: trueonly on marked counters.all_flags_state: For override-affected flags,trackEvents,trackReason, anddebugEventsUntilDateare cleared so bootstrapped clients do not send individual events; values/reasons stay present.Specs cover processor, summarizer, client wiring, OVERRIDE vectors (
summaryOverrideAffected), and end-to-end payloads, plusRecordingEventProcessorfor tests.Reviewed by Cursor Bugbot for commit e2e01d8. Bugbot is set up for automated code reviews on this repo. Configure here.
Opened from termag