Repository navigation
fix: Fail an override file load on a deleted entry, naming the file and the key - #493
Merged
Merged
Conversation
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 26ff32a. Configure here.
tanderson-ld
approved these changes
Nov 10, 2026
Base automatically changed from
rlamb/overrides-ruby-contract-tests
to
feat/overrides
November 10, 2026 23:35
…nd the key An override defines a flag or segment, and an override is removed by removing its entry or deleting its file, so an entry marked as deleted is a mistake in the file. The file override source now fails the reload of a file that contains a flag or segment entry marked as deleted, in the same way as a file that cannot be parsed: the overrides in effect stay, the failure is logged with the file and the key, and the retry applies. Before, the reload failed only through the sink's check, with a message that named neither the file nor the kind as users know it. The check runs through a new check_document option of the shared reloader, which only the override source sets. The sink still rejects a snapshot with a deleted flag or segment with ArgumentError, and now also logs the rejection at Error level, naming "flag" or "segment" and the key, so a custom source that supplies a snapshot after it has started cannot drop the rejection silently. The file data sources are unchanged: specs pin that they, and the reloader without a document check, still load entries marked as deleted.
kinyoklion
force-pushed
the
rlamb/overrides-ruby-reject-deleted
branch
from
November 10, 2026 23:36
26ff32a to
cbf2a1d
Compare
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.
Requirements
Related issues
This PR is stacked on #454 so that the PRs below it do not change. Its base is
rlamb/overrides-ruby-contract-tests.Describe the solution you've provided
Before:
ArgumentError, before the layer changed. Nothing logged the rejection when a custom source supplied the snapshot after it had started. The message used the internal kind namespace:the override features entry f is deleted.Unable to load flags: the override features entry f is deleted.After:
[LDClient] FileOverrideSource: Unable to load flags: flag "f" in /path/overrides.json is marked as deleted; remove the entry to remove its override. The check runs through a newcheck_documentoption of the shared reloader (impl/file_data/reloader.rb), and only the override source sets it.ArgumentErrorfor a snapshot with a deleted flag or segment. It now also logs the rejection at Error level, with "flag" or "segment" and the key:[LDClient] Rejected an override snapshot, keeping the overrides in effect: override flag "f" is marked as deleted; leave the flag out of the snapshot to remove its override. The whole snapshot is rejected, the layer is unchanged, and no change notifications are sent.deleted: falseis an ordinary definition and still loads.FileData.override_sourceandOverrideSink#set_overrideseach gain one sentence about entries marked as deleted.The ordinary file data sources (v1
FileDataSourceImpland FDv2FileDataSourceV2) are unchanged on purpose. Rejecting deleted entries there would be a breaking change, which is planned for a later major version. Neither of them uses the sharedimpl/file_dataengine. The new specs pin that both of them, and the reloader without a document check, still load entries marked as deleted.Tests added or changed:
spec/impl/overrides/sink_spec.rb: a deleted flag, and a deleted segment given as a model object, each reject the whole snapshot. The other entries are not applied, the layer is unchanged, nothing is notified, and the Error log names the kind and the key. Entries withdeleted: falseare accepted. The existing test's message expectations moved into these tests.spec/integrations/file_override_source_spec.rb: a deleted flag fails the initial load, and the log names the file and the key. On a running source, a deleted flag keeps the previous overrides, and the fix is applied. A deleted segment in a YAML file keeps every file's overrides, including a change to the other file, until the segment entry is fixed.deleted: falseloads. With a client, the override is still served, the log names the file, and the sink's rejection never appears because the source fails the load first.spec/impl/file_data/reloader_spec.rb: a document check that raises fails the load and keeps the last good result. The other files are still checked. Without a check, deleted entries are combined as before.spec/integrations/file_data_source_v2_spec.rb,spec/integrations/file_data_source_spec.rb: pins that the data sources still load entries marked as deleted.How I ran them (Ruby 3.2.3):
bundle exec rspec spec/impl/overrides spec/impl/file_data spec/integrations/file_override_source_spec.rb spec/integrations/file_data_source_v2_spec.rb spec/integrations/file_data_source_spec.rb: 312 examples, 0 failures.bundle exec rspec spec(database store specs skip by default): 1681 examples, 1 failure. The failure isspec/launchdarkly-server-sdk_spec.rb:5, theBundler.requireautoload test. Its inline bundler getsPermission deniedon/var/lib/gems/3.2.0/bundler.lockon this machine, so it is a local environment problem and unrelated to this change.deleted: falsetests pass. Two mutants also fail the expected tests: removing the sink's log line, and skipping segments in the file check.bundle exec rubocopon the changed files: no offenses.Describe alternatives you've considered
FileData.merge: merge does not know the file paths, and the ordinary data sources would share it once they move onto the engine. A per-document hook keeps the rule on the override path."": ...) reaches the sink, and the reloader retries every second. An Error line from the sink on each retry would repeat what the reloader already logs once. So only the deleted-item rejection, which the file source never reaches now, is logged by the sink.Additional context
Separate follow-up, not fixed here: the v1 file data source has its own bug.
LDClient.newraisesNoMethodErrorwhen a file has an entry marked as deleted, becausedependency_tracker.rb:60checksdeletedonly on a hash. Line 70 then reads the prerequisites of a deleted model, which are nil. The same happens onmain. The v1 pin in this PR writes to a data store without an update sink, so it does not touch that path.Opened from termag
Note
Overview
Adds a
check_documenthook toFileData::Reloaderso each parsed file can be validated before merge; aMergeErrorfrom the hook fails the reload like a parse error and keeps the last good snapshot.The file override source wires this to
reject_deleted_entries, which rejects files containing flag or segment entries withdeletedset (other than false/null), logging errors that name the file path and key. Override sink still rejects full snapshots with deleted items but now uses user-facing "flag"/"segment" wording and logs an ERROR when rejecting, so custom sources get visibility too.Public docs for
FileData.override_sourceandOverrideSink#set_overridesnote that deleted entries fail loads / are rejected. v1 and FDv2 file data sources are unchanged and still accept deleted entries (pinned by new specs).Reviewed by Cursor Bugbot for commit cbf2a1d. Bugbot is set up for automated code reviews on this repo. Configure here.