Skip to content

[v1.0] Preserve correct provenance for nested configuration merges #263

Description

@codeforester

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

Metadata

Metadata

Assignees

Labels

bugSomething is not working

Type

No type

Projects

Status
Backlog

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions