Finalize native comparison ADRs and clarify declaration contracts
This commit is contained in:
@@ -71,8 +71,8 @@ schemas for implemented operations.
|
|||||||
|
|
||||||
CommandKit supplies shared handlers with predictable meanings and discovers their
|
CommandKit supplies shared handlers with predictable meanings and discovers their
|
||||||
availability from registration. Each enabled operation needs its own data
|
availability from registration. Each enabled operation needs its own data
|
||||||
contract: comparison needs safe snapshots, catalogs need enumeration, and profile
|
contract: comparison needs supported native comparison results, catalogs need
|
||||||
display needs safe execution-target inspection.
|
enumeration, and profile display needs safe execution-target inspection.
|
||||||
|
|
||||||
The [scope model](0009-configuration-scopes.md) and
|
The [scope model](0009-configuration-scopes.md) and
|
||||||
[comparison policy](0008-semantic-configuration-diff.md) describe related
|
[comparison policy](0008-semantic-configuration-diff.md) describe related
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ A writer failure can leave a partial report and returns operational failure. The
|
|||||||
outcome identifies incomplete delivery. Custom handler output remains
|
outcome identifies incomplete delivery. Custom handler output remains
|
||||||
application-owned. [ADR 0007](0007-native-yaml-reports.md) covers `config show` report
|
application-owned. [ADR 0007](0007-native-yaml-reports.md) covers `config show` report
|
||||||
preparation; [ADR 0008](0008-semantic-configuration-diff.md) defines successful
|
preparation; [ADR 0008](0008-semantic-configuration-diff.md) defines successful
|
||||||
comparison, including differences and coverage gaps.
|
comparison outcomes.
|
||||||
|
|
||||||
## Alternatives considered
|
## Alternatives considered
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,6 @@ allows a failure in one scope to prevent combined display. Explicit single-scope
|
|||||||
display remains available for a narrower view.
|
display remains available for a narrower view.
|
||||||
|
|
||||||
Additional structured schemas are compatibility contracts owned by CommandKit.
|
Additional structured schemas are compatibility contracts owned by CommandKit.
|
||||||
Native concatenation can use existing writers; semantic comparison separately
|
Native concatenation can use existing writers; semantic comparison uses the owning
|
||||||
requires the safe structured data described in
|
library's supported comparison API under
|
||||||
[ADR 0008](0008-semantic-configuration-diff.md).
|
[ADR 0008](0008-semantic-configuration-diff.md).
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# ADR 0008: Compare semantic snapshots with explicit sensitivity gaps
|
# ADR 0008: Delegate effective configuration comparison to owning libraries
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@@ -6,72 +6,79 @@ Accepted.
|
|||||||
|
|
||||||
## Date
|
## Date
|
||||||
|
|
||||||
2026-10-06
|
2026-10-06; revised 2026-10-11.
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
Configuration comparison helps operators understand changes in final effective
|
ConfigKit provides a native configuration comparison capability. Exposing it
|
||||||
values across roots and overlays. Formatting, authored file layout, and provenance
|
through CommandKit gives applications a consistent operator interface and reduces
|
||||||
identifiers are different properties from effective-value equality. Sensitivity
|
repeated command, selection, and reporting infrastructure. ConfigKit remains the
|
||||||
classification also limits the values available for inspection.
|
authority for the meaning and disclosure of its comparison results.
|
||||||
|
|
||||||
Meaningful comparison requires structured effective snapshots with per-path
|
|
||||||
sensitivity data from the owning libraries. The comparison policy must preserve
|
|
||||||
value semantics while making limited coverage visible to operators.
|
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
For a scope declaring safe comparison support, `config diff` compares two
|
### Comparison ownership
|
||||||
independently resolved effective configurations. CommandKit checks that capability
|
|
||||||
before acquisition. Providers supply captured results through the owning
|
|
||||||
libraries' supported public inspection APIs.
|
|
||||||
|
|
||||||
Compare values using the owning library's safe structured inspection semantics,
|
For ConfigKit-backed scopes declaring comparison support, `config diff` exposes
|
||||||
including defaults and recorded domain resolution. Preserve the distinctions
|
ConfigKit's native comparison API. CommandKit checks capability availability before
|
||||||
among absent values, null, empty mappings, and empty sequences. Mappings are
|
acquisition and coordinates selection, acquisition, adaptation, presentation,
|
||||||
compared recursively; ordered sequences are compared as whole values.
|
and invocation outcomes.
|
||||||
|
|
||||||
For each path, use the union of the two sides' sensitivity classifications to
|
Integrations delegate comparison to their owning libraries' supported public
|
||||||
protect both before and after presentation. A value classified on either side
|
APIs. ConfigKit owns its comparison semantics and disclosure rules. CommandKit
|
||||||
receives the corresponding safe treatment in both snapshots. Hidden values
|
follows the public contract of the ConfigKit version it adopts. When an adopted
|
||||||
produce explicit comparison gaps with their paths and supported reasons.
|
upstream revision changes those semantics, the changes flow through to
|
||||||
|
CommandKit's integration. Upstream remains authoritative as the capability evolves.
|
||||||
|
|
||||||
Equality conclusions cover the comparable data. A comparison with gaps reports
|
Application-supplied providers retain ownership of their implementation and
|
||||||
its limited coverage alongside observed differences. A complete comparison with
|
loading effects. [ADR 0012](0012-typed-configuration-comparison-pairs.md) governs
|
||||||
an empty difference set supports an equality conclusion for the inspected
|
paired selections, provider contracts, and typed input/shared-state lifetimes.
|
||||||
selection. Redaction masks are presentation data; classification metadata
|
|
||||||
determines comparison coverage.
|
|
||||||
|
|
||||||
Text and YAML reports include differences and coverage gaps. The exact report
|
### Safe disclosure and presentation
|
||||||
schema belongs in the [CLI reference](../cli.md) when implemented. Selection
|
|
||||||
syntax, inheritance rules, and detailed change records are outside the scope
|
|
||||||
of this decision.
|
|
||||||
|
|
||||||
A completed comparison returns success whether it finds differences or gaps;
|
Adapt and present native comparison results in accordance with the adopted
|
||||||
load, comparison, and writer failures use the operational failure classification in
|
upstream API's disclosure contract. The integration carries the upstream results
|
||||||
[ADR 0005](0005-invocation-outcomes.md).
|
and relevant metadata through its public provider boundary.
|
||||||
|
|
||||||
|
CommandKit owns report presentation and may summarize or transform the returned
|
||||||
|
safe comparison data for different operator needs. Reports may vary in format,
|
||||||
|
organization, and detail while respecting safe disclosure and the evidence
|
||||||
|
provided by the comparison. Each report's documented meaning defines the
|
||||||
|
conclusions an operator can draw from it.
|
||||||
|
|
||||||
|
Report formats, schemas, and rendering choices belong in the
|
||||||
|
[CLI reference](../cli.md) when implemented. They can evolve independently of
|
||||||
|
this ownership decision under the [release policy](../policy/release.md).
|
||||||
|
|
||||||
|
### Invocation outcomes
|
||||||
|
|
||||||
|
A completed comparison returns success regardless of whether differences are
|
||||||
|
reported. Load, comparison, and writer
|
||||||
|
failures use the operational failure classification in
|
||||||
|
[ADR 0005](0005-invocation-outcomes.md). Applications may use comparison results
|
||||||
|
to make their own domain decisions.
|
||||||
|
|
||||||
## Alternatives considered
|
## Alternatives considered
|
||||||
|
|
||||||
| Alternative | Analysis |
|
| Alternative | Analysis |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Rendered YAML line comparison | Reuses native display output. Formatting and masking become part of change interpretation. |
|
| Compare safe snapshots in CommandKit | Gives CommandKit direct control over comparison, but requires it to maintain equality and sensitivity logic and account for values already withheld from snapshots. Native comparison keeps those responsibilities with the owning library. |
|
||||||
| Compare masks as literal strings | Uses visible snapshot bytes directly. Equal masks express equal presentation while hidden values remain uncertain. |
|
| Compare rendered configuration text | Reuses existing output, but formatting and masking affect the apparent differences. Native comparison supplies evidence grounded in the library's effective-value model. |
|
||||||
| Use one side's sensitivity policy | Simplifies classification selection. A value's disclosure treatment depends on which snapshot supplies that policy. |
|
| Leave comparison commands entirely to applications | Preserves application flexibility, but repeats selection, acquisition coordination, and presentation infrastructure across consumers. Integration providers retain application control within the common command system. |
|
||||||
| Fetch secret values for comparison | Gives access to additional equality evidence. Comparison acquires sensitive material and additional confidentiality responsibilities. |
|
| Return a distinct status when differences are found | Supports assertion-oriented scripts, but couples successful inspection with a policy judgment about the result. The selected outcome model leaves that judgment to consumers. |
|
||||||
| Element-by-element sequence diff | Gives detailed collection changes. Stable element identity and alignment need another comparison contract. |
|
|
||||||
| A distinct status for observed differences | Supports assertion-oriented scripts. Inspection completion and change detection share an outcome signal. |
|
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
Operators receive meaningful effective-value changes with explicit uncertainty
|
CommandKit supplies consistent comparison commands while relying on owning
|
||||||
where sensitivity limits comparison. Whole-sequence comparison keeps
|
libraries for comparison semantics and safe disclosure. Dependency adoption
|
||||||
implementation scope focused at the cost of less detailed collection changes.
|
includes adapting the integration and its documentation to upstream changes.
|
||||||
|
New library integrations
|
||||||
|
are assessed through their supported comparison contracts; each scope can expose
|
||||||
|
its available capabilities independently under
|
||||||
|
[ADR 0009](0009-configuration-scopes.md).
|
||||||
|
|
||||||
Diff support depends on safe snapshots preserving value semantics and sensitivity.
|
Reports can serve different operator needs using the same native comparison
|
||||||
CommandKit applies this comparison policy to scopes declaring that capability.
|
data. Their level of detail may differ, and sensitivity rules may limit what
|
||||||
Other operations and families can be integrated independently under
|
can be shown. Maintaining the boundary between comparison evidence and report
|
||||||
[ADR 0004](0004-standard-inspection-surface.md).
|
presentation allows those reports to evolve while preserving library ownership
|
||||||
|
and consumer control.
|
||||||
Applications can use the successful report as input to domain decisions or future
|
|
||||||
assertion workflows.
|
|
||||||
|
|||||||
@@ -9,148 +9,140 @@ input/state lifetimes. Partially supersedes
|
|||||||
consequence during the unreleased prototype transition, and refines its
|
consequence during the unreleased prototype transition, and refines its
|
||||||
convenient composition principle.
|
convenient composition principle.
|
||||||
|
|
||||||
|
Refined by [ADR 0012](0012-typed-configuration-comparison-pairs.md) for
|
||||||
|
two-selection configuration comparison and its input/state lifetime. The
|
||||||
|
single-selection lifecycle and other decisions remain in force.
|
||||||
|
|
||||||
## Date
|
## Date
|
||||||
|
|
||||||
2026-10-10
|
2026-10-10
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
Optional integration modules need to assemble complete standard families through
|
Applications declare domain commands, while optional integrations assemble
|
||||||
public core contracts. Applications also declare their own commands and groups.
|
standard command families. A common construction and installation model reduces
|
||||||
Different construction and installation paths would add repeated error checks
|
repeated error checks and registration plumbing. Integrations need public typed
|
||||||
and registration plumbing, weakening CommandKit's infrastructure-reduction goal.
|
composition contracts to assemble those families while preserving core and
|
||||||
The current implementation is an unreleased prototype with no downstream
|
backend boundaries.
|
||||||
consumers. Its declarations are evidence to evaluate, without compatibility
|
|
||||||
obligations that would constrain the selected API.
|
|
||||||
|
|
||||||
Declaring an optional integration is distinct from installing it. Broad references
|
Declaration and installation have different responsibilities. An optional family
|
||||||
to reserved standard families in ADR 0001 do not specify when an optional name
|
claims a namespace when installed; selecting a dependency alone should leave the
|
||||||
becomes reserved. Dependency selection alone should not consume an application
|
application's command surface unchanged. During execution, scope-specific CLI
|
||||||
namespace or install commands.
|
inputs and application-owned shared state also have distinct lifetimes. Making
|
||||||
|
those lifetimes explicit avoids accidental aliasing between selected scopes.
|
||||||
|
|
||||||
Configuration inspection can select several scopes. Those scopes may share an
|
At the time of this decision, the implementation was an unreleased prototype
|
||||||
application-owned cache while receiving different selector values. Combining
|
with no downstream consumers. Its API shapes carried no compatibility obligations
|
||||||
selector storage and shared state in one context obscures their distinct
|
that would constrain the selected design.
|
||||||
lifetimes and can cause scope-specific inputs to alias. Separate input and state
|
|
||||||
types make those lifetimes explicit.
|
|
||||||
Integrations also need to compose typed bindings without accessing private core
|
|
||||||
parsers and setters or exposing backend structures.
|
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
### Uniform captured declarations
|
### Declaration capture and reuse
|
||||||
|
|
||||||
Applications and integrations construct the same opaque core command declarations
|
Applications and integrations construct the same opaque core command declarations
|
||||||
and install them through core application construction or registration. Initial
|
and install them through core application construction or registration. Initial
|
||||||
integrations provide complete-family factories and focused conveniences; they do
|
integrations provide complete-family factories and focused conveniences through
|
||||||
not add separate integration-specific installation APIs. Suite/provider types
|
that common installation API. Suite and provider types remain integration-owned.
|
||||||
remain integration-owned rather than becoming a universal core provider model.
|
|
||||||
|
|
||||||
Factories capture metadata, bindings, capability selections, selector
|
Factories eagerly capture metadata, bindings, capability selections, selector
|
||||||
applicability, and callback references eagerly. They copy the declaration
|
applicability, and callback references. They copy the declaration collections
|
||||||
collections needed so later edits to the source metadata do not change a returned
|
needed to isolate returned commands from later edits to source metadata.
|
||||||
command. Construction errors remain attached to the declaration and are reported
|
Construction errors remain attached for installation to report. This model uses
|
||||||
at installation. There is no public deferred preparation lifecycle or untyped
|
eager declarations with public typed composition; a deferred preparation lifecycle
|
||||||
integration payload.
|
and untyped integration payload are outside the selected API.
|
||||||
|
|
||||||
Core installation validates the whole batch before registry mutation, including
|
Declarations may be reused across applications with independent registry and
|
||||||
|
invocation state. Callback references and captured application objects retain
|
||||||
|
caller ownership. Reuse provides no deep-copy or concurrent-dispatch guarantee.
|
||||||
|
Application helpers performing other fallible work may still return errors.
|
||||||
|
|
||||||
|
### Installation and retained errors
|
||||||
|
|
||||||
|
Core validates each installation batch before registry mutation, checking
|
||||||
retained errors, bindings, placement, and collisions. Failed application
|
retained errors, bindings, placement, and collisions. Failed application
|
||||||
construction returns no usable application; failed later registration leaves the
|
construction returns no usable application; failed later registration preserves
|
||||||
existing registry intact. This atomicity applies to one installation call, not
|
the existing registry. Atomicity covers one installation call. Separate calls
|
||||||
separate calls or arbitrary effects in caller code. Report retained errors with
|
and arbitrary callback effects retain their own lifetimes.
|
||||||
useful command context and preserve supported wrapped error identity without
|
|
||||||
requiring a particular aggregate-error representation.
|
|
||||||
|
|
||||||
An explicit absence declaration contributes no command, help entry, or namespace
|
Report retained errors with useful command context and preserve supported wrapped
|
||||||
claim. Installation checks its attached errors before skipping it. A zero command
|
error identity. The aggregate-error representation remains an implementation
|
||||||
declaration remains invalid. Integrations define their own empty-suite semantics:
|
choice.
|
||||||
the initial configuration suite needs at least one named scope, while a valid
|
|
||||||
definition suite with no capabilities is absent. Metadata-only configuration
|
|
||||||
scopes remain discoverable. A nil loader supplied to an adapter is invalid wiring;
|
|
||||||
narrowing its capability list does not erase that error.
|
|
||||||
|
|
||||||
Declarations may be installed in multiple applications with independent registry
|
An explicit absence declaration contributes no command, help entry, or namespace.
|
||||||
and invocation state. Callback references and the objects they capture remain
|
Installation checks attached errors before skipping it. A zero command declaration
|
||||||
application-owned; declaration reuse neither deep-copies those objects nor
|
remains invalid. Integrations define their own empty-suite semantics: the initial
|
||||||
establishes concurrent-dispatch support. Application helpers performing other
|
configuration suite needs at least one named scope, and metadata-only scopes
|
||||||
fallible work may still return errors.
|
remain discoverable. A definition suite with no capabilities contributes nothing.
|
||||||
|
|
||||||
### Optional-family namespace lifetime and placement
|
Binding validation applies to generated command declarations. Unused selector
|
||||||
|
bindings in an absent family are ignored; explicitly retained adapter-construction
|
||||||
|
errors still reach installation. A nil loader supplied to an adapter remains
|
||||||
|
invalid wiring even if its capabilities are subsequently cleared.
|
||||||
|
|
||||||
Core construction always reserves help and version. An optional standard family
|
### Namespace ownership and placement
|
||||||
owns its complete root namespace when a real family declaration is installed.
|
|
||||||
An import or absent declaration reserves nothing. An application may use that
|
|
||||||
name while the family is uninstalled, but later installation then fails with a
|
|
||||||
collision. Application registration after standard-family installation fails in
|
|
||||||
the same way. Neither order merges groups, replaces handlers, or permits private
|
|
||||||
application operations beneath an installed standard family.
|
|
||||||
|
|
||||||
Standard-family declarations carry root-only placement metadata. Core rejects
|
Core construction reserves help and version. An optional standard family owns
|
||||||
their installation below another group. Placement is a public declaration
|
its complete root namespace upon installation. Imports and absent declarations
|
||||||
property, not authentication of the declaring package or a core allowlist of
|
claim nothing. An application may occupy an uninstalled family name; installing
|
||||||
integration names. A real empty root-only group still claims its namespace and
|
a conflicting declaration then fails in either registration order. Installation
|
||||||
obeys placement checks; explicit absence does neither.
|
preserves existing handlers and group ownership. Private application operations
|
||||||
|
remain outside installed standard families.
|
||||||
|
|
||||||
### Separate typed input from shared acquisition state
|
Standard families carry root-only placement metadata, which core enforces when
|
||||||
|
they are nested beneath another group. Placement is a public declaration property;
|
||||||
|
its enforcement is independent of package identity or a list of integration names.
|
||||||
|
A real empty root-only group claims its namespace and obeys placement checks.
|
||||||
|
Explicit absence contributes no node to place.
|
||||||
|
|
||||||
|
### Input and shared-state lifetimes
|
||||||
|
|
||||||
Integration suites distinguish typed CLI input from typed shared acquisition
|
Integration suites distinguish typed CLI input from typed shared acquisition
|
||||||
state. Configuration inspection initializes and populates one input per selected
|
state. Ordinary configuration inspection initializes one input per selected scope,
|
||||||
scope, applying only applicable selector bindings, and initializes shared state
|
applies its applicable selector bindings, and initializes shared state once for
|
||||||
once for the selected inspection invocation. Named definition inspection uses
|
the inspection invocation. Input validation receives the scope identity and its
|
||||||
one input and one shared state. Providers receive both explicitly.
|
typed input. Named definition inspection uses one input and one shared state.
|
||||||
Configuration input validation receives the selected scope identity together
|
Providers receive both explicitly. ADR 0012 refines this lifecycle for comparison
|
||||||
with its applicable typed input.
|
pairs with two selections of one scope.
|
||||||
|
|
||||||
Availability preflight and applicable input checks precede shared-state
|
Availability preflight and applicable input checks precede shared-state
|
||||||
initialization and acquisition. A failed check stops that path; later input
|
initialization and acquisition. Failures may stop later input factories.
|
||||||
factories need not run. Construction, installation, help, version, and scope
|
Construction, installation, help, version, and scope discovery leave suite
|
||||||
discovery invoke neither input/state factories nor acquisition providers.
|
input/state factories and acquisition providers uninvoked.
|
||||||
|
|
||||||
An omitted factory supplies its type's zero value, including nil for a pointer.
|
An omitted factory supplies its type's zero value, including nil pointers.
|
||||||
Applications supply initialization when their accessors or providers need it.
|
Applications provide initialization needed by their accessors and providers;
|
||||||
CommandKit does not allocate arbitrary pointer types, clone arbitrary application
|
providers may intentionally accept nil. Allocation of application objects,
|
||||||
graphs, repair aliases returned by factories, or reject a provider that accepts
|
cloning, and aliases returned by factories remain caller responsibilities.
|
||||||
nil intentionally. Core-owned parsed collections remain independent when applied
|
Core-owned parsed collections stay independent when applied to separate inputs.
|
||||||
to separate inputs. Caller-owned objects and callback effects retain their own
|
Caller-owned objects and callback effects retain their own lifetimes.
|
||||||
lifetimes.
|
|
||||||
|
|
||||||
Provide a narrow typed core binding-composition contract to capture converted
|
### Typed binding composition
|
||||||
values and apply a selected binding subset to an initialized input. Preserve
|
|
||||||
binding identity, defaults, and presence without string-based handler lookup or
|
|
||||||
exposure of private setters, parser state, or backend objects. Copying a binding
|
|
||||||
preserves its identity; constructing a lookalike binding does not.
|
|
||||||
|
|
||||||
Execution-required checks apply to the selected subset, so an app-only selector
|
Core provides a narrow typed contract to capture converted values and apply a
|
||||||
does not become required for an engine-only scope request. Missing required input
|
selected binding subset to initialized input. It preserves binding identity,
|
||||||
is a usage failure. An invalid binding selection or destination is a wiring
|
defaults, and presence while keeping private setters, parser state, and backend
|
||||||
failure, classified as operational when encountered at invocation. Those
|
objects behind their existing boundaries. A copied binding retains its identity;
|
||||||
categories remain identifiable through supported wrapping; assembly-detectable
|
a newly constructed lookalike has its own identity.
|
||||||
metadata defects remain installation errors. Both invocation failures stop before
|
|
||||||
shared-state initialization and acquisition. This composition is part of the
|
Execution-required checks apply to the selected subset. Missing required input
|
||||||
existing typed-input model, not another parser or a raw-argument handler API.
|
is a usage failure; invalid binding selection or destination is a wiring failure
|
||||||
|
with operational classification at invocation. These categories remain identifiable
|
||||||
|
through supported wrapping and stop execution before shared-state initialization
|
||||||
|
and acquisition. Metadata defects detectable during assembly of generated
|
||||||
|
commands remain installation errors under the validation boundary above.
|
||||||
|
|
||||||
### Relationship to earlier decisions
|
### Relationship to earlier decisions
|
||||||
|
|
||||||
No compatibility wrappers or downstream migration guide are required for this
|
For the unreleased prototype transition covered by this decision, compatibility
|
||||||
unreleased prototype transition. This replaces
|
wrappers and a downstream migration guide were unnecessary. This exception to
|
||||||
ADR 0010's consumer-migration consequence for this transition only. Changes to
|
ADR 0010's migration consequence is limited to that transition. Changes to
|
||||||
published contracts remain governed by the [release policy](../policy/release.md).
|
published contracts follow the [release policy](../policy/release.md).
|
||||||
|
|
||||||
ADR 0001 continues to govern dispatcher ownership, explicit instance registries,
|
ADR 0001 retains dispatcher, registry, typed-input, and application-ownership
|
||||||
typed bindings, presence, and application/domain boundaries. This decision
|
principles. ADR 0010 governs module boundaries and dependency direction, with
|
||||||
clarifies that optional-family namespace ownership begins upon installation.
|
[ADR 0003](0003-public-facade.md) governing deliberate exports and backend isolation
|
||||||
It refines the construction and installation mechanics left open there and
|
within that scope. ADRs 0004 through 0009 retain their operation, grammar, report,
|
||||||
distinguishes integration input from shared state.
|
and outcome decisions. Go declarations and GoDoc own exact implemented signatures.
|
||||||
It does not change the grammar, report formats, supported operation inventory,
|
|
||||||
or outcome/delivery rules in ADRs 0004 through 0009.
|
|
||||||
|
|
||||||
ADR 0010 continues to govern separate core/integration module contracts and
|
|
||||||
dependency direction. Integration factories return core declarations through
|
|
||||||
supported public composition contracts. Deliberate exports, private
|
|
||||||
implementation state, and backend isolation remain governed by
|
|
||||||
[ADR 0003](0003-public-facade.md) as scoped by ADR 0010. Exact exported signatures
|
|
||||||
belong in Go declarations and GoDoc when implemented; this record owns the
|
|
||||||
architectural choices rather than an implementation inventory.
|
|
||||||
|
|
||||||
## Alternatives considered
|
## Alternatives considered
|
||||||
|
|
||||||
@@ -166,22 +158,15 @@ architectural choices rather than an implementation inventory.
|
|||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
Consumers assemble domain commands and optional families visibly through one
|
Consumers assemble domain commands and optional families through one installation
|
||||||
installation boundary. Integrations remain convenient without private core
|
boundary. Eager assembly errors reach that boundary before provider acquisition.
|
||||||
access. Errors identified during eager assembly are observed at installation,
|
Namespace collisions remain explicit choices for the application to resolve.
|
||||||
before provider acquisition.
|
|
||||||
|
|
||||||
Installing an optional family can fail if the application already uses its root
|
Separate input and state types make initialization and sharing visible. Focused
|
||||||
name; the application decides which declaration to install. Installed standard
|
conveniences support simple applications, while typed composition gives
|
||||||
families retain their ownership and root placement in either registration order.
|
integrations the public contracts needed to assemble their families.
|
||||||
|
|
||||||
Composed suites use two types and explicit initialization when needed. The
|
The [architecture policy](../policy/architecture.md) owns normative boundaries;
|
||||||
context-free application-configuration convenience hides unused suite machinery
|
roadmaps own implementation status and sequencing. Application loading, cache
|
||||||
for simple consumers. The public typed-composition seam adds a deliberate core
|
design, startup, domain validation, callback effects, and process exit remain
|
||||||
contract while keeping implementation and backend state private.
|
consumer responsibilities.
|
||||||
|
|
||||||
The [architecture policy](../policy/architecture.md) owns normative boundaries.
|
|
||||||
Implementation status and sequencing remain in the roadmaps. These choices
|
|
||||||
govern CommandKit's declarations and calls; application loading, cache design,
|
|
||||||
startup, domain validation, callback effects, and process exit remain consumer
|
|
||||||
choices.
|
|
||||||
|
|||||||
108
docs/adr/0012-typed-configuration-comparison-pairs.md
Normal file
108
docs/adr/0012-typed-configuration-comparison-pairs.md
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# 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.
|
||||||
Reference in New Issue
Block a user