109 lines
5.9 KiB
Markdown
109 lines
5.9 KiB
Markdown
|
|
# ADR 0012: Prepare typed selection pairs for configuration comparison
|
||
|
|
|
||
|
|
## Status
|
||
|
|
|
||
|
|
Accepted. Refines [ADR 0011](0011-captured-declarations-and-installation.md) for
|
||
|
|
two-selection configuration comparison; its other decisions remain in force.
|
||
|
|
[ADR 0008](0008-semantic-configuration-diff.md) governs native comparison and
|
||
|
|
report presentation.
|
||
|
|
|
||
|
|
## Date
|
||
|
|
|
||
|
|
2026-10-11
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
Native effective-configuration comparison needs two completed loads. ConfigKit
|
||
|
|
requires results of the same configuration type, which an ordinary inspection
|
||
|
|
view does not expose for pairwise comparison. A generic adapter can retain that
|
||
|
|
type without introducing result assertions or a universal core provider model.
|
||
|
|
|
||
|
|
ADR 0011 separates a selected scope's typed input from shared acquisition state.
|
||
|
|
A comparison selects the same scope twice, potentially with different roots or
|
||
|
|
overlays. Reusing one input obscures which selection a provider receives; creating
|
||
|
|
separate shared state loses the invocation-wide lifetime chosen for inspection.
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
### Selections and provider ownership
|
||
|
|
|
||
|
|
Comparison selects one scope and prepares an earlier/left selection and a
|
||
|
|
later/right selection. Omitted right selection fields inherit the corresponding
|
||
|
|
left field and supplied state. An explicit right override, including an empty
|
||
|
|
value, replaces that field. Providers retain interpretation of omitted defaults
|
||
|
|
and explicit empty values. Applicable domain selector values are shared between
|
||
|
|
the two sides initially; independent per-side domain selectors may be considered
|
||
|
|
for a concrete consumer need.
|
||
|
|
|
||
|
|
Equal selections are allowed. CommandKit does not skip acquisition merely because
|
||
|
|
their selection values are equal: caller-owned loading may produce different
|
||
|
|
effective results. Exact flag spellings belong in the CLI reference when
|
||
|
|
implemented.
|
||
|
|
|
||
|
|
Use a narrow optional comparison provider owned by the integration. Its request
|
||
|
|
groups each side's selection with its typed input and supplies one shared state
|
||
|
|
value separately. The provider returns acquired native comparison results
|
||
|
|
with diagnostics and an error through the existing acquisition convention.
|
||
|
|
Reuse useful upstream public record types rather than duplicating them solely
|
||
|
|
to rename fields. Exact exported signatures belong in Go declarations and GoDoc.
|
||
|
|
|
||
|
|
The typed ConfigKit adapter invokes the supplied loader for each reached side
|
||
|
|
and passes the successful typed results to `configkit.Diff`. It retains the
|
||
|
|
configuration type inside that adapter, without reflection, result type
|
||
|
|
assertions, private core access, or a comparison-facet framework. Applications
|
||
|
|
may supply their own pair provider through the same integration contract.
|
||
|
|
|
||
|
|
Declared capabilities determine required wiring. A comparison-only scope needs
|
||
|
|
its comparison provider, without an unrelated ordinary acquisition callback.
|
||
|
|
Ordinary operations continue to use their ordinary acquisition provider.
|
||
|
|
Retained adapter construction errors still apply when capabilities are narrowed.
|
||
|
|
Other scopes and families need not support comparison under
|
||
|
|
[ADR 0009](0009-configuration-scopes.md).
|
||
|
|
|
||
|
|
### Typed input and shared state lifetime
|
||
|
|
|
||
|
|
Capture comparison declarations and applicable selector bindings under ADR 0011.
|
||
|
|
Convert supplied flag values through core once, including on help paths; applying
|
||
|
|
the values to both inputs does not parse them again.
|
||
|
|
|
||
|
|
After availability preflight, initialize each reached side's typed input
|
||
|
|
separately, apply the same applicable captured selector values, and check that
|
||
|
|
input with the selected scope identity and that side's selection. Finish both
|
||
|
|
input checks before initializing shared state once and invoking the pair
|
||
|
|
provider. Failures may stop later factories or loads. Construction, installation,
|
||
|
|
help, version, and scope discovery invoke neither input/state factories nor
|
||
|
|
acquisition/comparison providers.
|
||
|
|
|
||
|
|
Existing factory ownership rules remain unchanged: an omitted factory supplies
|
||
|
|
its type's zero value, including nil pointers. Separate factory calls do not
|
||
|
|
guarantee distinct caller-owned objects. CommandKit does not allocate arbitrary
|
||
|
|
pointer types, clone application graphs, repair caller aliases, or supply or
|
||
|
|
repair application caches. Core-owned parsed collections remain independent
|
||
|
|
when applied to the two inputs; callback effects remain caller-owned.
|
||
|
|
|
||
|
|
## Alternatives considered
|
||
|
|
|
||
|
|
| Alternative | Analysis |
|
||
|
|
| --- | --- |
|
||
|
|
| Symmetric independently resolved left/right selectors | Makes each side explicit and avoids inheritance. It adds vocabulary and repetition for common base-versus-overlay comparisons. |
|
||
|
|
| One typed input for both sides | Requires fewer factory calls, but obscures side-specific selection checks and leaves mutation isolation implicit. |
|
||
|
|
| Acquire a comparison facet with each ordinary view | Shares single-side acquisition across operations, but requires a public compatibility contract between heterogeneous facets and additional handle or assertion machinery. |
|
||
|
|
| Separate shared state for each side | Isolates acquisition state, but loses the invocation-wide sharing already selected for inspection. Applications can choose isolation within their own pair provider if needed. |
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
|
||
|
|
Pair preparation has explicit input and state lifetimes while ordinary inspection
|
||
|
|
keeps its existing lifecycle. Generic result handling stays inside the integration
|
||
|
|
adapter; core gains no owning-library dependency or universal comparison model.
|
||
|
|
|
||
|
|
Shared state permits application-owned caches. A cache used by a pair provider
|
||
|
|
should distinguish selections and any input values affecting loading to avoid
|
||
|
|
reusing the left result for a different right selection. This is integration
|
||
|
|
guidance, not a CommandKit cache policy or guarantee about caller callbacks.
|
||
|
|
|
||
|
|
The [architecture policy](../policy/architecture.md) owns normative boundaries.
|
||
|
|
ADR 0008 governs delegation to upstream comparison semantics, safe disclosure,
|
||
|
|
and CommandKit's presentation responsibility. This decision does not add a new
|
||
|
|
equality engine or strengthen application
|
||
|
|
loading, object ownership, or concurrency contracts.
|