Goal
Make Context.config_provenance report the actual winning source for every nested leaf.
Background
The batteries-included profile promises recursive merging and dotted-path provenance. The recursive branch currently calls _merge_mapping() with the global provenance map but without the parent prefix, then updates the correctly-prefixed paths afterward:
|
def _merge_mapping( |
|
target: dict[str, Any], |
|
provenance: dict[str, str], |
|
incoming: Mapping[str, Any], |
|
source: str, |
|
) -> None: |
|
for key, value in incoming.items(): |
|
if not isinstance(key, str): |
|
raise ConfigurationError("Configuration keys must be strings.") |
|
previous = target.get(key) |
|
if isinstance(previous, Mapping) and isinstance(value, Mapping): |
|
_merge_mapping(target[key], provenance, value, source) |
|
provenance.update(_leaf_provenance(value, source, key)) |
|
continue |
|
for path in tuple(provenance): |
|
if path == key or path.startswith(f"{key}."): |
|
del provenance[path] |
|
target[key] = dict(value) if isinstance(value, Mapping) else value |
|
provenance.update(_leaf_provenance(value, source, key)) |
.
A merge of {"host": "top", "db": {"host": "one"}} from user, followed by {"db": {"host": "two"}} from project, leaves the value of top-level host unchanged but changes its provenance to project. The resulting map incorrectly reports host=project and db.host=project.
Scope
- Carry the complete dotted prefix through recursive merges.
- Remove stale provenance only inside the replaced subtree.
- Cover recursive mapping-to-mapping, mapping-to-scalar, scalar-to-mapping, and sibling keys with the same leaf name.
Acceptance Criteria
- The reproduction above keeps
host=user and sets only db.host=project.
Context.config_provenance agrees with the final value at every leaf.
- Existing precedence and consumer-owned configuration semantics do not change.
- Regression tests exercise at least three nested levels and repeated leaf names.
Validation
Run the batteries-included configuration tests and the full Python suite.
Non-Goals
Do not add a new precedence model or configuration source.
Project Fields
- Status: Backlog
- Priority: P1
- Area: Python
- Initiative: v1.0 Readiness
- Size: S
Ownership
Goal
Make
Context.config_provenancereport the actual winning source for every nested leaf.Background
The batteries-included profile promises recursive merging and dotted-path provenance. The recursive branch currently calls
_merge_mapping()with the global provenance map but without the parent prefix, then updates the correctly-prefixed paths afterward:base-cli/lib/python/base_cli/config.py
Lines 102 to 120 in 8a93d22
A merge of
{"host": "top", "db": {"host": "one"}}fromuser, followed by{"db": {"host": "two"}}fromproject, leaves the value of top-levelhostunchanged but changes its provenance toproject. The resulting map incorrectly reportshost=projectanddb.host=project.Scope
Acceptance Criteria
host=userand sets onlydb.host=project.Context.config_provenanceagrees with the final value at every leaf.Validation
Run the batteries-included configuration tests and the full Python suite.
Non-Goals
Do not add a new precedence model or configuration source.
Project Fields
Ownership