diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index c64c8ec..0088633 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -2,7 +2,7 @@ **Base Policy Version:** 1.3 -**Last Updated**: 2026-10-10 +**Last Updated**: 2026-10-11 **Upstream Source:** [architecture.md](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/architecture.md) @@ -134,6 +134,14 @@ and input checks before shared state initialization and provider acquisition. Factories need not run after a failure and remain uninvoked during construction, installation, help, version, and scope discovery. +For two-selection configuration comparison, prepare and check each side's input +separately with its scope identity and selection, applying the same applicable +converted selector values to both. Finish both checks before initializing shared +state once and invoking the integration-owned pair provider under +[ADR 0012](../adr/0012-typed-configuration-comparison-pairs.md). Required provider +wiring follows declared capabilities; a comparison-only scope does not require +an unrelated ordinary acquisition callback. + Omitted input and state factories supply the respective type's zero value, including nil for pointers. Caller factories and callbacks retain responsibility for objects they return or reference; do not promise arbitrary deep copies, @@ -232,8 +240,10 @@ Concrete integration needs guide provider representations under Native report writers and safe inspection data preserve owning-library semantics. Loading all selected views before report output is a `config show` decision under [ADR 0007](../adr/0007-native-yaml-reports.md); other inspection operations define -their own output timing. Semantic comparison uses supported safe snapshots and -reports sensitivity gaps under [ADR 0008](../adr/0008-semantic-configuration-diff.md). +their own output timing. Semantic comparison delegates to supported owning-library +comparison APIs and retains paired safe disclosure and hidden-change metadata at +the provider boundary. Reports may present the reduced view selected by +[ADR 0008](../adr/0008-semantic-configuration-diff.md). ## Scope And Non-goals diff --git a/docs/roadmap/configkit.md b/docs/roadmap/configkit.md new file mode 100644 index 0000000..98e92f7 --- /dev/null +++ b/docs/roadmap/configkit.md @@ -0,0 +1,438 @@ +# Adopt ConfigKit v0.7.1 and expose native configuration comparison + +Status: proposed feature roadmap; dependency adoption and `config diff` are not +implemented. The targeted delivery includes both, as requested by the user. +This document defines the selected end state; a subsequent staged +implementation plan will define execution order. + +## Purpose and authority + +Adopt ConfigKit's current loading and inspection improvements and expose its +native effective-configuration comparison through CommandKit. Operators should +be able to compare two selections of one configuration scope, including the +effect of a selected overlay, without applications writing duplicate CLI or +comparison infrastructure. + +The revised [ADR 0008](../adr/0008-semantic-configuration-diff.md) owns native +comparison and paired safe disclosure. [ADR 0009](../adr/0009-configuration-scopes.md) +owns scope selection and independent capabilities; [ADR 0011](../adr/0011-captured-declarations-and-installation.md) +owns captured declarations, typed input, and shared state, refined for comparison +pairs by [ADR 0012](../adr/0012-typed-configuration-comparison-pairs.md). The +[architecture policy](../policy/architecture.md) controls ownership and dependency +direction. The current ADR alignment edits remain uncommitted for user +review; this roadmap follows their agreed comparison direction. + +The repository is being developed as a pre-release alpha. Choose the simplest +coherent final API without preserving prototype shapes through compatibility +wrappers. Existing deliberately selected contracts still control; changes to +published releases follow the [release policy](../policy/release.md). + +This work consumes ConfigKit's supported public API. No upstream extension is +required for the selected comparison goal. ConfigKit owns comparison and safe +disclosure; CommandKit owns selection, coordination, adaptation, and presentation. + +## Current baseline + +| Owner | Current state | +| --- | --- | +| Core module | Go 1.26.0; captured commands, typed bindings, dispatch, outcomes, help, and version. No ConfigKit dependency. ReleaseKit v0.4.0 is the declared maintainer tool. | +| `integrations/ckconfig` | Requires ConfigKit v0.5.0. `Scope`, `Suite`, `FromConfigKit`, and `AppCommand` expose scopes/validate/show/sources/explain. No comparison operation or provider exists. | +| `integrations/ckprompt` | Directly requires ConfigKit v0.5.0 and PromptKit v0.12.0. Depends on ckconfig's public scope contracts and adapts engine configuration plus named definitions. | +| Deferred comparison | [DIFF-01](deferred.md#diff-01-semantic-configuration-comparison) records the target. Native semantics, selection syntax (OD-1), provider representation (OD-2), and the YAML-only report (OD-3) are accepted. | + +The existing ConfigKit adapter acquires a typed `*configkit.Result[T]` and exposes +its effective, source, and explanation facets through `View`. That generic +adapter is a useful place to retain typed results for comparison. `View` alone +does not supply two results of the same `T` to `configkit.Diff`. + +ConfigKit v0.7.1 identifies source commit +`6fffde4af8f31f99d3ee295c426eb3234cb0fb77`. Relative to the selected v0.5.0: + +- v0.6.0 reduces repeated loading, resolution, metadata, and inspection work. + Its Go 1.26.0 minimum is already met by CommandKit. +- v0.7.0 adds native frozen effective-value comparison. +- v0.7.1 changes the upstream maintainer tool to ReleaseKit v0.4.1, with no + runtime/API change from v0.7.0. + +The YAML dependency remains `go.yaml.in/yaml/v4 v4.0.0-rc.6`. Existing public +loading and inspection signatures are unchanged. The review found no apparent +adapter migration requirement for existing operations; that is static review +evidence, not a completed upgrade validation. See the pinned +[release notes](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/6fffde4af8f31f99d3ee295c426eb3234cb0fb77/docs/releases/v0.7.1.md) +and [comparison contract](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/6fffde4af8f31f99d3ee295c426eb3234cb0fb77/docs/config.md#effective-configuration-diffs). + +## Targeted end state + +### Dependencies and module boundaries + +Both integration modules select ConfigKit v0.7.1 and carry normal dependency +metadata for their actual graphs. Consumer Go minimums remain 1.26.0, the selected +release toolchain remains 1.26.8, and PromptKit remains v0.12.0 for this work. +Core continues to have no ConfigKit or optional-integration dependency. + +ConfigKit's declared tool requirement brings ReleaseKit v0.4.1 into the integration +module graphs. Reconcile that selection through normal Go module resolution and +accurate attribution. A combined development workspace can also select that +version. This does not by itself change the core module's separately declared +release tool or authorize release-launcher changes; assess core through its own +workspace-off graph. + +Independent module versions remain independent of upstream ConfigKit's version. +Release preparation uses appropriate unused versions under the existing policy, +without moving tags or claiming unpublished dependencies are available. + +### Ownership + +| Owner | Target responsibility | +| --- | --- | +| ConfigKit | Frozen effective-value equality, changed-region selection/order, sensitivity union, paired safe snapshots, hidden-change detection, and load semantics. | +| ckconfig | Comparison capability and provider contracts; typed ConfigKit adapter; `config diff` input preparation, acquisition coordination, reports, and upstream diagnostic adaptation. | +| Core | Existing declaration installation, flag conversion/presence, help, dispatch, cancellation context, and outcome/delivery mechanics. No comparison model or engine. | +| ckprompt | Continue existing integration behavior with the upgraded shared dependency and ckconfig API. Do not claim native PromptKit comparison support through this upgrade. | +| Consuming application | Configuration definitions, acquisition callback internals, loader/cache choices, domain interpretation, startup, and process exit. | + +### ConfigKit-backed comparison + +The `config` family exposes `diff` when at least one scope declares the capability. +Help and `config scopes` report actual availability. A scope can support comparison +independently of other operations; enabling comparison elsewhere does not require +every scope to support it. Unsupported selections fail as usage errors before +acquisition. + +`config diff` selects one scope, defaults to `app`, and does not accept +`--scope all`, as selected by ADR 0009. It compares earlier/left and later/right +effective configurations. Both file comparison and base-versus-overlay comparison +are supported through ordinary application loading choices. Exact side selection +and inheritance rules are accepted in OD-1 below. + +ConfigKit-backed adapters use the same supplied typed loader for existing +inspection and both comparison selections. They delegate equality and paired +disclosure to `configkit.Diff`; no rendered-YAML comparison or assertion on +mutable `Result.Config` is introduced. Convenience wiring remains simple: +`AppCommand` and `FromConfigKit` should provide native comparison alongside their +existing supported operations, with ordinary capability narrowing available. +The provider representation is accepted in OD-2. + +Declaration capture, metadata discovery, and help leave suite factories and +acquisition/comparison callbacks uninvoked. Invocation preparation uses original +typed binding identities and converted values, preserving explicit empty, false, +and zero selections. Supplied values are converted through core once, including +help paths; applying a value to both comparison inputs does not parse it twice. +Input/state timing for the pair is part of OD-2, rather than an implicit extension +of the existing one-selection lifecycle. + +### Comparison meaning and disclosure + +Retain ConfigKit's native changed-region records at the provider boundary, including +semantic paths, left/right `Present` and `Redacted` states, safe YAML values, and +`HiddenChanged`. The default report deliberately presents a reduced view under +OD-3 rather than exposing all native metadata. +The native contract owns detailed comparison semantics; the important operator +consequences are: + +- Changes reflect frozen effective load values, including defaults and recorded + domain resolution. Provenance or source-layout differences alone are not + effective changes. +- Compare final values, not source presence alone. Omitted and explicit-null + inputs may resolve equally for a typed field; an absent map key and a present + null-valued key can remain distinct in the final configuration. Nil and empty + containers also remain distinct. Mappings compare recursively; sequences report + atomic changed regions. +- Both sides receive the union of sensitivity from both loads. Structural + replacements can mask an entire region. +- A difference can exist even when its safe left/right YAML is identical. + `HiddenChanged` reports an actual concealed change; redaction alone does not. +- An empty successful diff supports equality within ConfigKit's inspected value + model. Typed secret references compare by configured name; credential rotation + behind an unchanged reference is outside that comparison. + +Reports use safe changed regions without inventing a coverage-gap inventory, +decoding redaction-marker text as metadata, identifying concealed members beyond +upstream disclosure, or adding separately rendered full configurations as if they +had received paired protection. Full paired document context and a sensitivity +audit are separate potential capabilities, not prerequisites here. + +### Reports, diagnostics, and outcomes + +Default `config diff` to one YAML document with `additions`, `changes`, and +`deletions`, as selected in OD-3. Use existing output streams. YAML is the only +supported report format, with explicit `--format yaml` accepted. The +view distinguishes deletion from null but omits separate redaction and concealed- +change metadata. Move the implemented report contract to the CLI reference. +ADR 0008 records this reduced view while retaining native metadata at the +provider boundary. Other commands retain their existing format defaults. + +Successful comparisons return success whether they find differences, concealed +changes, or none. No assertion status or separate exit code is added. Load and +comparison failures retain operational classification and supported error +identity; selection/input errors retain usage classification. Output failures +use existing delivery and incomplete-report semantics. + +The ConfigKit adapter retains diagnostics from the acquired results, including +warnings and any load failure encountered. Present them through existing core +diagnostic delivery; preserve meaningful left/right context when needed to +identify the failing selection without losing wrapped error identity. Retain +left-side warnings if the right load fails, and diagnostics from both successful +loads if native comparison fails. Finish acquisition and native comparison before +writing a successful diff report. Cancellation is checked at ordinary operation +boundaries; do not promise interruption inside a synchronous upstream call. + +## Work needed from the baseline + +These are work areas, not numbered implementation stages. Use the accepted +choices below to write the staged implementation plan. + +- **Dependency adoption:** upgrade both integration requirements, reconcile sums + and indirect/tool dependencies, and assess PromptKit v0.12.0 against the newly + selected ConfigKit version. Preserve distributed manifests without sibling + replacements or committed workspace files. +- **Capability and provider API:** extend ckconfig's operation/capture/validation + model for the selected comparison provider. Preserve retained adapter errors, + capability narrowing, metadata-only scopes, and validation only of bindings + used by generated commands. Do not require an ordinary acquisition provider + for a comparison-only scope if its selected pair provider is sufficient. +- **Typed preparation:** capture comparison selection metadata and applicable + selector lists once. Prepare/check the selected pair through core bindings, + with state and callback timing from the chosen lifecycle. Keep caller-owned + objects and aliases under existing ownership rules. +- **Native adaptation:** extend the typed ConfigKit adapter/convenience factory + to load the selected pair and call `configkit.Diff`. Reuse diagnostic adaptation + and ordinary error handling without introducing a generic provider framework, + global cache, or untyped result transport. +- **Command and reports:** generate the conditional `config diff` declaration, + integrate it with discovery/help, and render the chosen report contract using + native safe values. Preserve existing operation/report behavior. +- **Documentation and distribution:** update GoDoc, CLI/consumer guidance, + maintained examples, affected module notices and pinned ConfigKit links, and + relevant release notes as implementation lands. Include a maintained comparison + example that loads genuinely different selections through shared state, with + cache keys accounting for the selection and typed-input values used by its + loader. Review transitive tool notices + for the actual graph. Move DIFF-01's implemented portion out of deferred work; + retain unresolved future PromptKit comparison and unrelated proposals. +- **Validation evidence:** run each affected module's deterministic offline suite + and representative consumers. Check module/package boundaries independently + with workspace mode off. If CommandKit prerequisite versions remain unpublished, + use disposable alternate module files for local-source wiring evidence, as + described in the [development guide](../development.md#documentation-validation). + Do not fabricate future checksums or turn migration checks into permanent gates. + +Focused comparison coverage should protect the CommandKit boundary: capability +availability before callbacks, side selection/presence, chosen input/state +lifetime, native public and concealed changes, absent versus null values, and +empty successful comparisons. Include representative load/comparison errors, +diagnostics, cancellation, and output failure. Specifically cover left-side +warnings followed by a right-side load failure, and diagnostics from both loads +followed by a comparison failure. Verify that selection-aware caching does not +return the left result for the right selection. Include the three report +categories, explicit null versus deletion, concealed-only changes, and an +unchanged masked value inside a changed sequence. Existing inspection and composed +PromptKit behavior must continue to work. Reuse native collaborators and test +CommandKit's adaptation/reporting; do not duplicate ConfigKit's entire comparator +suite or impose performance thresholds. + +## Scope limits and completion + +This work delivers ConfigKit adoption and ConfigKit-backed `config diff`. +PromptKit upgrade/comparison/catalogs, JSON reports, per-element sequence matching, +resolved credential comparison, full paired document context, assertion mode, +provider caching, and core backend changes are outside this target. + +Completion means upgraded integration dependencies, usable native comparison +through declared scopes and convenience wiring, selected public API/CLI/report +contracts in their current owners, relevant maintained examples, accurate notices, +and sufficient boundary validation. No open choices may be silently converted into +contracts by implementation. Publication follows the existing release procedure +and is not performed by this planning pass. + +## Selected report design (OD-3) + +**Selected:** the default operator-facing output of `config diff` is a single YAML +document with three primary keys: `additions`, `changes`, and `deletions`. +Additions and changes preserve configuration hierarchy and contain only safe +right-side values; deletions are canonical JSON Pointer paths. For example: + +```yaml +additions: + server: + health_check: true +changes: + server: + port: 9090 + logging: + destination: null +deletions: + - /server/legacy_timeout +``` + +Classify each native difference by its presence fields: absent-left/present-right +is an addition, present-left/absent-right is a deletion, and present on both sides +is a change. Explicit null remains a value; do not encode deletion as null. +Changed sequences remain whole sequences, and native structural replacements +remain whole reported regions. Do not derive a second set of changes by comparing +rendered values or expanding atomic regions. + +Assemble additions and changes from ConfigKit's paired-safe right snapshots, +preserving YAML value types and semantic path components. Parsing and assembly +serve presentation only. Do not read unredacted configuration values or append +independently rendered full configurations. The result is a partial inspection +view, not a complete configuration or an automatically applicable patch. + +Omit separate `Redacted` and `HiddenChanged` metadata from this default view. +Every reported region changed, but a masked value within it need not have changed: +a public field in an atomic sequence may change while a secret remains unchanged. +A concealed-only change still appears in its native reported region even if the +safe snapshots are identical. Preserve native masks without interpreting marker +text; a literal public string resembling `[REDACTED]` remains an ordinary value. +The default report intentionally does not expose every distinction available in +the native records. A detailed metadata format can be considered separately if +needed; it is not required for this delivery. + +**Accepted edge-case treatment:** when a nonempty root mapping becomes an empty +mapping, report the native removed-key paths under `deletions`. The reduced report +need not add special metadata or a separate envelope solely to distinguish +exceptional whole-root empty/null transitions from an empty comparison. Ambiguity +in that case is acceptable to the user and is not a planning blocker. Native +comparison records retain their distinctions; ordinary field-level null values +and deletions retain the selected reporting rules. + +**Accepted format and empty-category treatment:** YAML is the only report format +for this delivery; a separate plain text report adds no needed operator value. +Always include all three keys in the order `additions`, `changes`, `deletions`. +Empty additions and changes render as `{}`; empty deletions render as `[]`. An +empty comparison therefore produces: + +```yaml +additions: {} +changes: {} +deletions: [] +``` + +This stable shape supports automated consumption without missing-key handling +and retains the accepted tolerance for exceptional whole-root ambiguity. Other +commands keep their existing formats. + +ADR 0008 records this selected presentation. Selection syntax and provider shape +are accepted below. No significant open decisions remain for this roadmap. + +**Alternatives considered:** a full difference envelope with left/right snapshots +and explicit presence, redaction, and hidden-change fields preserves all native +metadata, but is more verbose than the chosen operator view. Embedding parsed +values in that envelope avoids YAML strings but retains the record-oriented +layout. A right-side-only view without deletion paths cannot represent removals +unambiguously. The selected three-category document balances configuration-shaped +output with explicit removal reporting. + +Omitting empty categories would shorten the report but require consumers to +handle missing keys. A separate text report could label changes by path or group +them into sections, but YAML already provides readable operator output; another +renderer and presentation contract are unnecessary for this delivery. + +## Accepted Decisions + +### OD-1: How operators select the two sides + +**Accepted:** use existing `--config` and `--overlay` for the left side and +add `--against-config` and `--against-overlay` overrides for the right side. +Omitted right fields inherit the left field, including its supplied state; +explicit right values, including an empty string, replace it. Use the scope's +applicable typed domain selectors on both sides. This supports two files and +base-versus-overlay comparison while reusing familiar syntax and preserving +provider-owned defaults. Allow equal selections; they can produce a legitimate +empty diff without an invented requirement that an override be supplied. Do not +short-circuit acquisition merely because the selections are equal: caller-owned +loading may produce different effective results. + +For example, these show the accepted target syntax, not current commands: + +```text +app config diff --config before.yml --against-config after.yml +app config diff --config base.yml --against-overlay candidate +app config diff --config base.yml --overlay current --against-overlay "" +``` + +Right-side inheritance is field-by-field. Overriding only the configuration still +inherits the left overlay. For either selection field: + +| Left field | Right override | Effective right field | +| --- | --- | --- | +| Omitted | Omitted | Omitted, preserving provider defaults | +| Supplied value | Omitted | Same value and supplied state as left | +| Explicit empty string | Omitted | Explicit empty string, still supplied | +| Any value/state | Supplied value | Right value, supplied | +| Any value/state | Explicit empty string | Empty string, supplied | + +The provider continues to interpret an explicitly empty overlay through its +ordinary loading contract; CommandKit does not define empty as disabling overlays. +Shared domain selector values are the initial scope; +independent per-side domain selectors can be considered with a concrete consumer +need, without precluding them as future API work. + +**Alternative considered:** expose symmetric `--left-config`/`--right-config` and +`--left-overlay`/`--right-overlay` selections, resolving each side independently. +This makes two independent selections explicit and avoids inheritance rules. It +adds vocabulary beside existing configuration selectors and repeats flags for +the common single-base overlay workflow. It remains viable if symmetry is valued +more than reuse of familiar inspection syntax. + +### OD-2: Comparison provider and input/state lifetime + +**Accepted:** add a narrow optional scope comparison callback receiving +the pair's selections, separately prepared left/right typed inputs, and one +shared state value. Group each side's selection and input in a request value to +avoid several positional left/right arguments. Return +`commandkit.Acquired[[]configkit.Difference]` plus an error, following the existing +acquisition convention. Reuse upstream public record types rather than duplicate +them solely to rename fields. The selected target shape in ckconfig is: + +```go +type ComparisonSide[I any] struct { + Selection Selection + Input I +} + +type ComparisonRequest[I any] struct { + Left ComparisonSide[I] + Right ComparisonSide[I] +} + +// Accepted target field on Scope[I, S]: +// Compare func(context.Context, ComparisonRequest[I], S) (commandkit.Acquired[[]configkit.Difference], error) +``` + +These names and the callback shape are selected for implementation; they are not +implemented exports. ADR 0012 records paired provider ownership and input/state +lifetimes; this roadmap owns the target declarations until the Go API is implemented. + +The typed `FromConfigKit` adapter can retain its `T`, invoke the supplied loader +for each reached side, and call `configkit.Diff`. Existing single-view acquisition +remains responsible for ordinary operations. A comparison-only scope can supply +the pair callback without an unrelated `Acquire` callback. Declared capabilities +determine which callbacks must be wired. + +For a reached comparison, initialize each selection's `I` separately, apply the +same applicable captured selector values, and check it with that side's +`Selection`. Finish both input checks before initializing `S` once and invoking +the pair provider. Omitted factories still supply zero values, including nil +pointers; separate calls do not guarantee distinct caller objects. Later factories +or loads need not run after failure. Help/discovery remain free of these calls. +ADR 0012 records this two-selection specialization of ADR 0011's suite lifecycle, +and the architecture policy reflects it. Document the exact implemented API +contract in Go declarations and GoDoc when it lands. + +This keeps generic result handling inside the owning adapter and preserves +typed binding composition without reflection, private-core access, or result +type assertions. Shared state supports consumer caches whose keys distinguish +the effective selections and any typed-input values that affect loading. A cache +that stores only one configuration can incorrectly reuse the left result for the +right and report equality. Demonstrate correct keys in the maintained example; +CommandKit neither supplies nor repairs application caches. Cache policy and +factory objects remain caller-owned. + +**Alternative considered:** acquire a comparison-capable facet with each ordinary `View`, +then compare the two acquired facets. This shares single-side acquisition between +all operations and may suit providers already retaining typed results behind a +stable comparison handle. It requires a public way to establish compatibility +between two heterogeneous facets, and can lead to type assertions or extra +opaque-handle machinery. Consider it if representative non-ConfigKit consumers +demonstrate enough benefit to justify that additional contract. diff --git a/docs/roadmap/deferred.md b/docs/roadmap/deferred.md index 72ab221..4cb8f12 100644 --- a/docs/roadmap/deferred.md +++ b/docs/roadmap/deferred.md @@ -21,23 +21,26 @@ an idea here does not select its syntax, API, priority, or delivery date. ### DIFF-01: semantic configuration comparison Expose comparison of two independently resolved selections of one scope using -owning-library safe snapshots. [ADR 0008](../adr/0008-semantic-configuration-diff.md) -owns the accepted comparison semantics, sensitivity union, and coverage-gap -handling. The target includes text/YAML reports of differences and gaps; -completed comparisons can succeed even when they find either. +owning-library public comparison APIs. [ADR 0008](../adr/0008-semantic-configuration-diff.md) +owns native comparison, paired safe disclosure, and the reduced default report. +The target includes a YAML-only report of safe changed regions; completed +comparisons succeed whether or not they find differences. The initial review of ConfigKit v0.5.0 and PromptKit v0.12.0 did not find the -complete public snapshot/sensitivity contract needed for that target. Reassess -released upstream APIs when planning it; do not treat that historical review as -a claim about newer versions. Hidden-path metadata and supported gap reasons -must be available without fetching secrets. Rendered YAML and sibling internals -are not substitutes for an agreed public comparison representation. +public comparison support needed for that target. ConfigKit v0.7.0 introduced +`configkit.Diff`, retained in v0.7.1, which supplies native comparison and paired +safe changed-region snapshots. CommandKit still uses ConfigKit v0.5.0; dependency +adoption and comparison delivery are targeted by the +[ConfigKit roadmap](configkit.md). Assess PromptKit's supported +public comparison capabilities separately. Rendered YAML and sibling internals +are not substitutes for the owning library's public comparison contract. -Comparison selection syntax, context inheritance, and report layout remain -future design work. Earlier possibilities included right-side root/overlay -selection, shared versus independent domain context, and an optional assertion -mode. Those choices are unselected. Add public types and handlers when the -capability is supported, rather than exposing placeholders. +The ConfigKit roadmap records accepted selection syntax and the paired provider +API, with lifecycle recorded in +[ADR 0012](../adr/0012-typed-configuration-comparison-pairs.md). The selected report +shape is recorded in that roadmap. Independent per-side domain selectors and +an optional assertion mode remain outside that delivery. Add public types and +handlers with their implementation rather than exposing placeholders. ### CAT-01: PromptKit catalogs