Record input destination decision and baseline
This commit is contained in:
70
docs/adr/0011-input-destinations.md
Normal file
70
docs/adr/0011-input-destinations.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# ADR 0011: Place Configuration Inputs at Mapping Destinations
|
||||
|
||||
## Status
|
||||
|
||||
Accepted. The [input-destinations roadmap](../roadmap/input-destinations.md)
|
||||
owns implementation status and the [implementation plan](../roadmap/implementation.md)
|
||||
owns sequencing and completion evidence.
|
||||
|
||||
## Date
|
||||
|
||||
2026-10-14
|
||||
|
||||
## Context
|
||||
|
||||
Consumers assembling collections of independently authored configuration
|
||||
fragments need each source to contribute beneath a selected application path.
|
||||
Requiring consumers to rewrite source documents or merge completed values would
|
||||
separate placement from ConfigKit's existing composition, precedence, source
|
||||
identity, and inspection behavior. Placement should remain part of the ordinary
|
||||
loading lifecycle and preserve the root-owned public facade.
|
||||
|
||||
## Decision
|
||||
|
||||
Add an optional `Destination Path` to root-owned `Input` and expose the effective
|
||||
destination on existing `SourceInfo` records. The empty path means the existing
|
||||
application root. A non-empty destination is a sequence of literal mapping keys;
|
||||
explicit sequence-index segments are invalid. Existing reserved structural keys
|
||||
remain reserved, while keys that merely contain their spelling remain ordinary
|
||||
keys.
|
||||
|
||||
Acquire and interpret each source using its original physical identity and
|
||||
source-local directives, then place its application body before strict
|
||||
composition and the existing final lifecycle. Imported application bodies
|
||||
inherit the input destination. Placement applies to main and underlay inputs;
|
||||
ordinary root loading, selected overlays, and CLI inputs retain root placement.
|
||||
The main-owned version rule continues to check its effective application path
|
||||
at its existing lifecycle point.
|
||||
|
||||
Placement preserves authored node locations and source identity. Introduced
|
||||
mapping structure belongs to the contributing source and uses that document's
|
||||
root location as its source-coordinate fallback. A present empty mapping
|
||||
materializes its destination; an absent `NoSource` contributes nothing. The
|
||||
result continues through the existing strict composition, overlay, inheritance,
|
||||
typed loading, diagnostics, provenance, history, sensitivity, and resource
|
||||
context mechanisms.
|
||||
|
||||
The added exported fields preserve keyed and zero-value struct use. Callers
|
||||
using unkeyed composite literals for `Input` or `SourceInfo` must migrate to
|
||||
keyed literals. Treat this feature as minor-release work; select the version and
|
||||
document the compatibility impact during separately authorized release
|
||||
preparation, consistent with the release policy.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- **Rewrite or merge sources in consumers.** This makes each consumer reproduce
|
||||
placement, strict composition, source attribution, and inspection semantics.
|
||||
- **Add a separate loading entry point or public wrapper type.** This creates a
|
||||
parallel API for a behavior that belongs to existing per-input loading.
|
||||
- **Load each fragment as a complete application before placement.** This runs
|
||||
defaults, decoding, resolution, and validation on incomplete fragments rather
|
||||
than once on the assembled application.
|
||||
|
||||
## Consequences
|
||||
|
||||
Consumers can assemble contributions at effective mapping paths in one ordinary
|
||||
layered load and inspect each source's placement through existing source
|
||||
records. Paths, conflicts, and later application operations use the placed
|
||||
structure while source coordinates and relative-resource contexts continue to
|
||||
identify their original sources. Public field additions require release-note
|
||||
guidance for callers using unkeyed literals.
|
||||
@@ -123,7 +123,7 @@ completion evidence. Planning baseline: `6353598`.
|
||||
|
||||
## Stage 1 — Record the decision and capture the baseline
|
||||
|
||||
Status: planned. Scope: decision record and evidence, no feature code.
|
||||
Status: complete. Scope: decision record and evidence, no feature code.
|
||||
|
||||
1. Read the roadmap, request, relevant policies, and ADRs 0001, 0003, 0006,
|
||||
0008, and 0009. Inspect the owners identified in the roadmap and the function
|
||||
@@ -142,8 +142,40 @@ Status: planned. Scope: decision record and evidence, no feature code.
|
||||
as minor-release work; select a version and write its note only during
|
||||
separately authorized release preparation.
|
||||
|
||||
Validate: local-link test and whitespace checks. Done: baseline evidence and
|
||||
the decision are recorded; implemented contracts remain unchanged.
|
||||
Validated: `./scripts/check.sh` (go1.26.8 linux/amd64) passed on candidate
|
||||
`d3d468a8b47d780787fca329ff65b107d98ca59f`; this includes formatting,
|
||||
whitespace, local documentation links, tests, vet, and build. The planning
|
||||
baseline `6353598bd6cce2eb78a5fe990e144cc0cadf1280` is present in history. The
|
||||
worktree was clean before this stage.
|
||||
|
||||
Coverage located for later destination work:
|
||||
|
||||
- Root and equivalent source loading: `TestEquivalentSourceFormsPreserveInputSemantics`
|
||||
(`facade_equivalence_test.go`) and
|
||||
`TestFacadeLayeredZeroUnderlaysMatchesOrdinaryLoad` (`facade_layered_test.go`).
|
||||
- Strict underlays and group budgets: `TestGroupedLoadStrictConflictsRepetitionAndBudgets`
|
||||
and `TestGroupedLoadPrecedenceSourceOrderAndSingleLifecycle`
|
||||
(`internal/engine/load_request_test.go`).
|
||||
- Version ownership and imported claims: `TestLoadRejectsImportConflictsAndFragmentVersions`
|
||||
(`internal/engine/imports_test.go`) and version-path coverage in
|
||||
`internal/engine/load_test.go`.
|
||||
- Repeated physical sources: `TestRepeatedImportsAcrossTiersAndReaderConsumption`
|
||||
(`facade_equivalence_test.go`).
|
||||
- History and source contexts: `TestUnderlayHistoryRetainsLaterMappingContributors`
|
||||
(`facade_underlay_origins_test.go`) and
|
||||
`TestFacadeSourceContextsFollowOriginsWithoutQueryIO`
|
||||
(`facade_resource_context_test.go`).
|
||||
- Detached records: `TestLoadMetadataReflectsDefaultsInputAndDetachedRecords`
|
||||
(`internal/engine/load_test.go`) and
|
||||
`TestMetadataQueriesReturnDetachedRecords` (`internal/engine/metadata_test.go`).
|
||||
|
||||
The decision is recorded in [ADR 0011](../adr/0011-input-destinations.md).
|
||||
Compatibility assessment: adding the two public fields breaks callers using
|
||||
unkeyed literals for `Input` or `SourceInfo`; keyed and zero-value use remains
|
||||
compatible. The release policy permits the intentional pre-1.0 contract change
|
||||
in a minor release when the release note states impact and migration. Version
|
||||
selection and release-note preparation remain out of scope until separately
|
||||
authorized. No feature code or current behavior contract changed.
|
||||
|
||||
## Stage 2 — Add private destination normalization and wrapping
|
||||
|
||||
|
||||
Reference in New Issue
Block a user