config: resolve Effective by folding per-loader layer trees#64
Open
bigbes wants to merge 1 commit into
Open
Conversation
Effective() resolved against the single merged tree, so a value set at a broad inheritance scope by a high-priority loader could lose to a value set at a narrow scope by a low-priority loader. Build now keeps each top-level collector's contribution as its own layer tree and Effective folds those layers in ascending-priority order: within a layer the deepest scope wins, across layers the higher-priority loader wins, and non-conflicting sub-keys from different loaders coexist. MergeAppend/MergeDeep keys compose across layers. A MultiCollector is folded into a single layer. MutableConfig mutations are mirrored into the layered view: Set/Merge/Update record values in a runtime overlay that outranks every loader, and Delete records a tombstone (and prunes the overlay) so the deleted contribution is suppressed from each layer's scope chain; re-setting a deleted path clears its tombstone. Snapshot deep-clones the layers, overlay, and tombstones. Configs not produced by a Builder (slices, Walk snapshots, effective sub-configs) keep the original single-tree resolution.
2d1187f to
d254f56
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.
Config.Effective/MutableConfig.Effective/EffectiveAllresolved a leaf entity against the single merged tree, so scope depth always dominated loader priority — e.g. an env var routed to the global scope lost to a YAML value set per instance.Builder.Buildnow keeps each top-level collector's contribution as its own layer tree, and effective resolution folds those layers in ascending-priority order: within a layer the deepest inheritance scope wins, across layers the higher-priority loader wins, and non-conflicting sub-keys from different loaders coexist.MergeAppend/MergeDeepkeys compose across layers; aMultiCollectorfolds into a single layer.MutableConfigmutations are mirrored into the layered view:Set/Merge/Updaterecord values in a runtime overlay that outranks every loader, andDeleterecords a tombstone (and prunes the overlay) so the deleted contribution is suppressed from each layer's scope chain — re-setting a deleted path clears its tombstone.Snapshotdeep-clones layers, overlay, and tombstones. Configs not produced by aBuilder(slices,Walksnapshots, effective sub-configs) keep the original single-tree resolution.Behavior change worth a minor-version bump; CHANGELOG updated. Covered by new tests in
config_test.go,inheritance_test.go,layered_extra_test.go, andmerge_tree_test.go;golangci-lint run ./...is clean.