5.9 KiB
ADR 0012: Prepare typed selection pairs for configuration comparison
Status
Accepted. Refines ADR 0011 for two-selection configuration comparison; its other decisions remain in force. ADR 0008 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.
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 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.