77 lines
3.9 KiB
Markdown
77 lines
3.9 KiB
Markdown
# ADR 0009: Resolve Sibling Inheritance After Source Assembly
|
|
|
|
## Status
|
|
|
|
Accepted and implemented. The [configuration contract](../config.md#sibling-inheritance)
|
|
owns current behavior. The completed implementation plan is preserved in Git
|
|
history at `83c59ea`.
|
|
|
|
## Date
|
|
|
|
2026-09-29
|
|
|
|
## Context
|
|
|
|
Named configuration mappings often share settings while retaining individual
|
|
overrides. ConfigKit already distinguishes strict composition of independent
|
|
source contributions from recursive overlay between explicit precedence tiers.
|
|
Doing another untracked merge in applications would lose omission, source
|
|
context, and historical explanation information. A shared structural operation
|
|
must preserve the same presence and provenance model as the rest of loading.
|
|
|
|
Inheritance also interacts with source precedence, nested namespaces, version
|
|
ownership, and secrets. Resolving it before source assembly would validate
|
|
superseded references and copy values that a later tier should replace. Fully
|
|
resolving nested relationships inside a reusable parent would bind them to the
|
|
wrong sibling scope when copied into a child.
|
|
|
|
## Decision
|
|
|
|
Reserve `extends` as a built-in input key on mappings. A string names one exact
|
|
sibling mapping; null cancels the relationship. Complete source acquisition,
|
|
strict composition, selected overlay, and CLI precedence first. Then resolve
|
|
each effective relationship in the parser-independent document tree, before
|
|
typed defaults and decoding. A child recursively overlays its own payload on
|
|
its resolved parent using the existing mapping-combination rules. This creates
|
|
neither a source tier nor a configurable merge strategy.
|
|
|
|
Resolve enclosing sibling chains before nested relationships. Reuse memoized
|
|
parent templates with unresolved nested instructions; evaluate those instructions
|
|
at each destination. Preserve original source applications separately from
|
|
structural transfer/control evidence. Effective origins carry concrete
|
|
source-to-destination derivation, and inspection projects relevant inheritance
|
|
events between source replay and typed reconciliation. Inherited input counts as
|
|
explicit presence, while direct replacement retains its own effective origin.
|
|
|
|
The existing main-input version check remains at its original point. Reject
|
|
structural contributions or directive consumption affecting its protected path.
|
|
Classify sensitivity at corresponding source and destination paths and retain
|
|
historical redaction. Secret references remain unresolved input until the
|
|
existing lookup point. Keep all machinery behind the root-owned public facade.
|
|
|
|
## Alternatives considered
|
|
|
|
- **Application-owned inheritance after `Load`.** Leaves every consumer to
|
|
recreate ordering, presence, provenance, error reporting, and redaction after
|
|
ConfigKit has already declared a result complete.
|
|
- **Resolve each source before precedence assembly.** Makes superseded
|
|
references active and can copy a parent definition before higher-priority
|
|
input finishes changing it.
|
|
- **Resolve nested relationships in a cached parent subtree.** Shares more
|
|
ready-made output but binds nested sibling lookups to the parent's scope,
|
|
giving incorrect values at a child destination.
|
|
- **Registered collections, configurable keywords, or multiple-parent merge
|
|
modes.** Increase public setup and semantic branches without a requirement
|
|
that warrants diverging from one structural rule.
|
|
|
|
## Consequences
|
|
|
|
Consumers can load a configuration once and inspect direct, inherited,
|
|
defaulted, and application-derived values through the existing result surfaces.
|
|
`extends` is no longer an ordinary application field, so existing configurations
|
|
using that key as data must migrate. Expanding many children can materialize
|
|
substantially more output than the input contains; projection and retained-history
|
|
budgets bound that work without charging copies as newly acquired sources.
|
|
Applications still own domain validation, entry selection, and runtime resource
|
|
use.
|