Link the finalized registration backend design
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
|
||||
Status: module boundary accepted in ADR 0010; implementation planning remains
|
||||
in progress and no module extraction has begun. The consumer API is finalized
|
||||
and its ADR/architecture-policy alignment is complete. The next minor ReleaseKit
|
||||
release will support individual module releases; CommandKit adoption is pending.
|
||||
and its ADR/architecture-policy alignment is complete. The internal registration
|
||||
and execution design is finalized, including both composition-question resolutions.
|
||||
The next minor ReleaseKit release will support individual module releases;
|
||||
CommandKit adoption is pending.
|
||||
|
||||
## Purpose and authority
|
||||
|
||||
@@ -15,7 +17,9 @@ module dependencies. ConfigKit-only consumers should not acquire PromptKit.
|
||||
This roadmap records the targeted end state, selected module layout, and
|
||||
migration work. The finalized [registration API](registration-api.md) owns the
|
||||
selected declarations, installation semantics, and representative consumer
|
||||
examples. Neither document describes these changes as implemented.
|
||||
examples. The finalized [registration backend design](registration-backend.md)
|
||||
owns internal structure, shared installation/execution mechanics, and the resolved
|
||||
composition decisions. These documents describe the implementation target.
|
||||
[ADR 0010](../adr/0010-optional-integration-modules.md) owns the accepted module
|
||||
boundary and convenient registration principles; it partially supersedes
|
||||
[ADR 0003](../adr/0003-public-facade.md), whose remaining principles still apply.
|
||||
@@ -143,6 +147,16 @@ shapes merely because they already exist.
|
||||
Built-in help/version remain reserved; optional integration roots are owned
|
||||
when their real family is installed. ADR 0011 and the architecture policy now
|
||||
record that lifetime; implementation remains pending.
|
||||
- Use the finalized [internal registration and execution design](registration-backend.md).
|
||||
Built-ins, application commands, and integration families share one
|
||||
[installation path](registration-backend.md#one-installation-path-for-every-command)
|
||||
and typed compiler. Captured metadata and invocation state have distinct owners;
|
||||
the backend document defines the capture, binding, routing, and presentation
|
||||
mechanics without adding another integration installation API.
|
||||
- Apply the resolved [unused-binding validation boundary](registration-backend.md#resolved-unused-binding-validation-oq-1)
|
||||
and [scope-error handoff](registration-backend.md#resolved-scope-error-handoff-oq-2).
|
||||
The registration API incorporates the selected runnable-parent and scope-error
|
||||
attachment declarations. No absence-validation overload is selected.
|
||||
- Core diagnostics use a small CommandKit-owned severity type. Upstream
|
||||
diagnostic conversion belongs in the integrations, preserving selected
|
||||
classification, delivery, and error semantics without copying ConfigKit's
|
||||
@@ -205,10 +219,13 @@ with refinements recorded in ADR 0011. ADR 0010's consumer-migration consequence
|
||||
is superseded for the unreleased prototype transition. The architecture policy
|
||||
reflects the selected core/integration facades, installed-family ownership, and
|
||||
scope-aware configuration input validation. Earlier accepted decision text remains
|
||||
intact.
|
||||
intact. The internal backend design is also finalized; its runnable-child,
|
||||
scope-error attachment, and unused-binding decisions are incorporated into the
|
||||
API target. Both composition questions are resolved.
|
||||
|
||||
- Use the finalized [registration API](registration-api.md) and selected module
|
||||
layout as the implementation target before moving public symbols.
|
||||
layout together with the [backend design](registration-backend.md) as the
|
||||
implementation target before moving public symbols.
|
||||
- Inventory root exports, imports, private helper use, and family registration
|
||||
behavior. Use the inventory as evidence of responsibilities and coupling, not
|
||||
as a list of APIs to preserve. Implement final exports and ownership from the
|
||||
@@ -218,7 +235,8 @@ intact.
|
||||
core only, ConfigKit only, and both libraries. They define the target wiring,
|
||||
including combined configuration scopes and independent definition inspection;
|
||||
port them into maintained examples as implementation lands.
|
||||
- Prepare a staged implementation plan from this roadmap and the finalized API,
|
||||
- Prepare a staged implementation plan from this roadmap, the finalized API,
|
||||
and the finalized [backend design](registration-backend.md),
|
||||
preserving the unreleased-prototype organizing principle above.
|
||||
|
||||
Completion: the dependency direction, final API, and registration approach
|
||||
@@ -227,14 +245,21 @@ are concrete enough to implement without inventing a general plugin framework.
|
||||
### 2. Extract the integrations and isolate the core
|
||||
|
||||
- Establish the selected module layout, preserving the existing root import
|
||||
path for the core.
|
||||
path for the core. Use the backend document's [internal ownership boundaries](registration-backend.md#selected-internal-ownership)
|
||||
when organizing private declarations, bindings, registry, execution, neutral
|
||||
metadata, and the Cobra adapter.
|
||||
- Move configuration declarations, registration, handlers, reports, and
|
||||
ConfigKit adapters together. Move PromptKit declarations, handlers, reports,
|
||||
and its configuration-scope adapter into the PromptKit integration.
|
||||
- Replace access to root-private registry state and helpers with the smallest
|
||||
supported interactions needed by those integrations. Preserve duplicate
|
||||
registration handling and standard-family ownership; audit these boundaries
|
||||
rather than assuming package relocation preserves them automatically.
|
||||
- Use the shared installer and typed compiler for every command source, including
|
||||
built-in help/version. Replace direct registry writes, duplicated family
|
||||
collision checks, and integration-specific core state with the selected
|
||||
captured-declaration path. Integration factories use public core contracts,
|
||||
and `ckprompt` uses the selected scope-error attachment contract in `ckconfig`.
|
||||
- Follow the backend document's [integration preparation design](registration-backend.md#integration-preparation-without-parallel-execution-frameworks)
|
||||
for selected inputs and shared state. Preserve each operation's acquisition
|
||||
and report timing while removing repeated scope selection and mixed-context
|
||||
projection.
|
||||
- Implement core outcomes, diagnostics, bindings, and command declarations using
|
||||
the finalized API. Replace ConfigKit severity in core diagnostics
|
||||
with the selected CommandKit-owned type. Place report encoding and upstream
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
# Unified command registration API
|
||||
|
||||
Status: finalized API design; implementation is pending. The declarations,
|
||||
consumer examples, and design checks below define the selected target API.
|
||||
consumer examples, and design checks below define the selected target API,
|
||||
including the additions and clarifications selected in the finalized backend
|
||||
design.
|
||||
No implementation is authorized by this document alone.
|
||||
|
||||
## Purpose and authority
|
||||
@@ -23,7 +25,10 @@ boundaries and convenient integration registration.
|
||||
captured-declaration model, optional-family namespace lifetime, and separated
|
||||
input/shared-state lifetimes. The [architecture policy](../policy/architecture.md)
|
||||
reflects those boundaries. The [module roadmap](modules.md) tracks extraction
|
||||
work; this API design remains a target rather than implemented behavior.
|
||||
work. The finalized [backend design](registration-backend.md) owns internal
|
||||
structure and shared implementation mechanics. Its resolved composition choices
|
||||
are incorporated below; this API design remains a target rather than implemented
|
||||
behavior.
|
||||
|
||||
Design for the best consumer API without preserving current implementation
|
||||
signatures or machinery. Existing code can supply evidence and reusable work,
|
||||
@@ -109,8 +114,10 @@ A failed `New` yields no usable application. A failed `Register` leaves the
|
||||
existing registry intact. No rollback guarantee spans separate registration calls.
|
||||
|
||||
Declaration construction, installation, help, and version do not invoke provider
|
||||
acquisition or invocation input/context factories. They do not validate files,
|
||||
credentials, or application configuration. Invalid wiring fails at installation;
|
||||
acquisition or application/suite input/state factories. Built-in help may prepare
|
||||
its own private typed input through the common compiler, without initializing the
|
||||
target command or invoking its validation/execution callbacks. These paths do not
|
||||
validate files, credentials, or application configuration. Invalid wiring fails at installation;
|
||||
an upstream error returned by a valid provider remains an invocation result.
|
||||
|
||||
An originally nil loader remains invalid wiring even if an adapter would wrap
|
||||
@@ -171,8 +178,14 @@ The selected empty-suite behavior is:
|
||||
|
||||
Use an explicit `commandkit.NoCommand()` declaration for intentional absence.
|
||||
Core installation skips it. A zero-value `Command` remains invalid. Integration
|
||||
factories validate or retain wiring errors before representing an empty family
|
||||
as a no-op; absence must not swallow errors. A no-op does not reserve a namespace.
|
||||
factories retain adapter-construction errors before representing an empty family
|
||||
as a no-op. Validate bindings needed by generated commands; unused selector
|
||||
bindings are ignored when they contribute to no generated inspection command.
|
||||
Integration-owned scope identifiers, applicability references, and enabled-provider
|
||||
wiring still undergo validation. Ignoring unused bindings does not erase retained
|
||||
adapter errors. This is the selected [unused-binding resolution](registration-backend.md#resolved-unused-binding-validation-oq-1).
|
||||
A no-op does not reserve a namespace, and `NoCommand()` needs no validation-bearing
|
||||
overload or separate public declaration validator.
|
||||
|
||||
## Capture, reuse, and invocation inputs
|
||||
|
||||
@@ -273,6 +286,7 @@ type CommandSpec[I any] struct {
|
||||
Name string
|
||||
Summary string
|
||||
Description string
|
||||
Children []Command
|
||||
NewInput func() I
|
||||
Flags []Flag[I]
|
||||
Arguments []Argument[I]
|
||||
@@ -367,6 +381,17 @@ installed tree, extract its handlers, or append children after capture. Collecti
|
||||
in `CommandSpec`, groups, and defaults are captured as appropriate; runtime
|
||||
closure state and diagnostic writer effects remain caller-owned.
|
||||
|
||||
### Runnable parents and captured children
|
||||
|
||||
`CommandSpec.Children` combines a typed handler with child declarations. Capture
|
||||
its child-handle slice and apply the same immediate composition, collision, and
|
||||
installation placement checks used by `Group`. A runnable parent follows its
|
||||
handler and operand requirements on bare invocation; help describes the parent
|
||||
and children under [ADR 0006](../adr/0006-command-grammar.md). `Group` remains the
|
||||
convenience for a non-runnable parent. Neither form permits mutation or child
|
||||
append operations after capture. The [backend design](registration-backend.md#immutable-declaration-records)
|
||||
uses the same captured representation and installation path for both.
|
||||
|
||||
### Retained errors, placement, and no-ops
|
||||
|
||||
`WithError` returns a new captured declaration retaining a non-nil error alongside
|
||||
@@ -565,6 +590,8 @@ func FromConfigKit[I, S, T any](
|
||||
load func(context.Context, Selection, I, S) (*configkit.Result[T], error),
|
||||
) Scope[I, S]
|
||||
|
||||
func WithScopeError[I, S any](scope Scope[I, S], err error) Scope[I, S]
|
||||
|
||||
func Command[I, S any](suite Suite[I, S]) commandkit.Command
|
||||
|
||||
func AppCommand[T any](
|
||||
@@ -581,9 +608,11 @@ validation diagnostics at invocation time, preserving current selected reports
|
||||
and classifications rather than implementing a second configuration engine.
|
||||
|
||||
An empty selector scope list applies to all registered scopes; a nonempty list
|
||||
identifies its applicable registered scopes. Unknown identifiers and reserved
|
||||
standard-flag collisions are declaration errors. Scope identifiers, capability
|
||||
selection, defaults, and aggregate availability follow
|
||||
identifies its applicable registered scopes. Unknown scope identifiers are
|
||||
declaration errors. Bindings used by generated commands undergo core validation,
|
||||
including standard-flag collisions; unused selector bindings follow the selected
|
||||
absence/unused-binding rule above. Scope identifiers, capability selection,
|
||||
defaults, and aggregate availability follow
|
||||
[ADR 0009](../adr/0009-configuration-scopes.md). Non-applicable selectors are not
|
||||
applied to a scope's input; this adds no new unused-selector rejection policy.
|
||||
`CheckInput` receives the registered name of each requested scope alongside its
|
||||
@@ -605,6 +634,21 @@ arguments nor demands a forwarding wrapper from the caller. A nil loader becomes
|
||||
a retained `config`/`app` declaration error. The full suite is used for composition;
|
||||
there is no incremental scope append operation after installation.
|
||||
|
||||
### Retained scope errors
|
||||
|
||||
`ckconfig.WithScopeError` returns a scope retaining a non-nil construction error
|
||||
alongside earlier causes, leaving the original scope unchanged. A nil error
|
||||
preserves the scope. Retained causes preserve supported `errors.Is`/`errors.As`
|
||||
identity across scope copies and narrowing of `Operations`. The family factory
|
||||
collects those issues into its command declaration before capability selection
|
||||
can discard them; no acquisition callback runs to discover a construction error.
|
||||
|
||||
`ckprompt.ConfigScope` uses this public operation to retain original loader errors
|
||||
without accessing private `ckconfig` state. It otherwise declares the ordinary
|
||||
scope fields and capabilities. The [scope-error resolution](registration-backend.md#resolved-scope-error-handoff-oq-2)
|
||||
records the rationale and rejected alternative; the operation adds no new scope
|
||||
installation lifecycle.
|
||||
|
||||
## Selected PromptKit integration declarations
|
||||
|
||||
The `ckprompt` package uses `ckconfig` selections and scope contracts through its
|
||||
@@ -662,7 +706,9 @@ maps the owning library's public diagnostics into core-owned `Diagnostic` values
|
||||
Definition providers preserve diagnostics even when a named lookup fails.
|
||||
|
||||
Consumers may leave either definition callback nil to omit that capability.
|
||||
A valid suite with both nil is an explicit no-op after eager declaration validation.
|
||||
A suite with both callbacks nil contributes no commands and ignores unused
|
||||
selector bindings. It returns a no-op retaining any adapter-construction errors;
|
||||
those errors still fail installation.
|
||||
A nil loader supplied to `FromEngine` is invalid wiring, not missing capability;
|
||||
setting its callbacks nil does not erase the retained error. For prompt lookup,
|
||||
the adapter passes the requested version value to PromptKit, with omission using
|
||||
@@ -706,7 +752,18 @@ succeed. The no-call rows remain unconditional for CommandKit-owned paths.
|
||||
| Configuration inspection of several scopes | Once per selected scope | Once, shared by selected scopes | Requested scopes, in selected operation order |
|
||||
| Named definition inspection | Once for the selected command | Once for that invocation | Selected inspection callback |
|
||||
|
||||
The factory counts describe application inputs and suite input/state. Built-in
|
||||
help may prepare its own private input through the common compiler; it still
|
||||
leaves the target application's and suites' factories, validation/execution
|
||||
callbacks, and providers uninvoked.
|
||||
|
||||
Input conversion and scope/capability preflight use metadata without acquisition.
|
||||
All supplied occurrences on an installed command undergo conversion, including
|
||||
selectors inapplicable to the requested scope and values supplied with help.
|
||||
Scope filtering affects value application and required-value checks, not
|
||||
conversion; an earlier malformed singleton occurrence remains an error even if a
|
||||
later one is valid.
|
||||
|
||||
For configuration execution, initialize and populate each requested scope input,
|
||||
then run its `CheckInput`; initialize the shared state before acquisition after
|
||||
input checks succeed. The input/state callbacks do not run for unselected scopes
|
||||
@@ -1126,7 +1183,7 @@ of arbitrary effects inside application callbacks.
|
||||
| --- | --- |
|
||||
| `ckconfig.Command(ckconfig.Suite[struct{}, struct{}]{})` | Error: no configuration scopes |
|
||||
| One named scope with empty operations and nil acquisition | Success; `config scopes` describes it, no inspection verbs supplied by that scope |
|
||||
| Valid definition suite with no callbacks | Explicit absence, no namespace claimed |
|
||||
| Definition suite with no callbacks and unused selector bindings | Explicit absence, unused bindings ignored; retained adapter errors still fail |
|
||||
| `NoCommand()` beside ordinary children | Skipped, no placeholder help item |
|
||||
| `WithError(NoCommand(), sentinel)` | Error retaining sentinel identity |
|
||||
| Zero `Command{}` at the root or as a child | Declaration error |
|
||||
@@ -1219,10 +1276,13 @@ The documentation alignment is complete:
|
||||
| [ADR 0001 status](../adr/0001-command-dispatch-and-inputs.md#status) | Remains accepted, with refinements recorded in ADR 0011 and its decision text preserved |
|
||||
| [ADR 0010](../adr/0010-optional-integration-modules.md) | Core/integration dependency boundaries remain in effect; ADR 0011 refines registration and supersedes the migration-guide requirement for this unreleased prototype |
|
||||
| [Architecture policy](../policy/architecture.md) | Uniform installed-family ownership, optional integration facades, and declaration/input boundaries |
|
||||
| [Module roadmap](modules.md) | Final API selected; documentation alignment completed; extraction and release adoption still pending |
|
||||
| [Module roadmap](modules.md) | Final API and backend design selected; extraction and release adoption still pending |
|
||||
| [Backend design](registration-backend.md) | Shared internal pipeline, runnable children, scope-error attachment, unused-binding validation, and both composition-question resolutions |
|
||||
|
||||
A staged module implementation plan remains to be written from this finalized
|
||||
API and the module roadmap. It should specify eager capture, error retention,
|
||||
neutral bindings, scope isolation, maintained examples, and release adoption.
|
||||
API, the finalized [backend design](registration-backend.md), and the module
|
||||
roadmap. Both composition questions are resolved. The plan should specify eager
|
||||
capture, error retention, neutral bindings, scope isolation, maintained examples,
|
||||
and release adoption.
|
||||
The documentation alignment neither implements these changes nor authorizes
|
||||
implementation by itself.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Registration and execution internals
|
||||
|
||||
Status: proposed internal design for the finalized consumer API; no implementation
|
||||
has begun. Runnable-command children and scope-error attachment are selected API
|
||||
additions to incorporate into the registration API document. Both composition
|
||||
Status: finalized internal design; no implementation has begun. Runnable-command
|
||||
children, scope-error attachment, and the unused-binding validation resolution are
|
||||
incorporated into the [registration API](registration-api.md). Both composition
|
||||
questions below are resolved; the staged implementation plan remains to be written.
|
||||
|
||||
## Purpose and authority
|
||||
@@ -18,8 +18,9 @@ capture, installation, namespace, and input/state decisions.
|
||||
[ADR 0010](../adr/0010-optional-integration-modules.md) owns module boundaries, and
|
||||
the [architecture policy](../policy/architecture.md) governs implementation.
|
||||
The [module roadmap](modules.md) owns the broader extraction and release work.
|
||||
This document proposes internal mechanics and identifies gaps; it neither changes
|
||||
the finalized API silently nor establishes additional consumer guarantees.
|
||||
This document defines selected internal mechanics and records the resolved
|
||||
composition decisions. Public declarations and consumer examples belong in the
|
||||
registration API document; these changes remain unimplemented.
|
||||
|
||||
The prototype has no compatibility priority. Replace its parallel paths and
|
||||
bookkeeping where they obstruct the selected design. Preserve deliberately
|
||||
@@ -46,7 +47,7 @@ opportunities and structural risks, not measured performance regressions.
|
||||
| `bridgeTree` in [parser.go](../../parser.go) caches neutral metadata; [internal/cobra/parse.go](../../internal/cobra/parse.go) creates a session per invocation | The useful metadata/session split should survive the refactor | Share captured metadata, refresh it after registry changes, and keep mutable backend values invocation-local |
|
||||
| `commandAt` traverses names again after the adapter has already resolved a command | Duplicate route lookup can become another source of dispatch disagreement | Return a private command key from the adapter and resolve the captured runner directly |
|
||||
|
||||
## Proposed internal ownership
|
||||
## Selected internal ownership
|
||||
|
||||
Keep most cohesive core machinery private in the root package. A facade does not
|
||||
require forwarding-only files or duplicate representations for every public type.
|
||||
@@ -58,7 +59,7 @@ Use an internal package where it protects an actual dependency boundary.
|
||||
| Core bindings | Binding identity, typed conversion, presence/defaults, converted-value application, binding metadata validation | Scope names, ConfigKit/PromptKit types, application object cloning |
|
||||
| Core registry | Validate/stage/commit installation batches and invalidate derived metadata | Integration-specific installed flags, command factories, report rendering |
|
||||
| Core execution | Invoke the selected compiled runner, share the current presentation context, normalize/present outcomes | Application startup, provider schemas, process exit |
|
||||
| `internal/commandmeta` (proposed) | Narrow backend-neutral routing/help DTOs, private command keys, parse result shapes | Public contracts, typed handlers, registry policy, upstream library types |
|
||||
| `internal/commandmeta` (planned) | Narrow backend-neutral routing/help DTOs, private command keys, parse result shapes | Public contracts, typed handlers, registry policy, upstream library types |
|
||||
| `internal/cobra` | Translate neutral metadata into one invocation session; route, collect raw occurrences, render help | Typed value conversion, declaration validation, family ownership, acquisitions |
|
||||
| `ckconfig` private implementation | Capture scopes, compile applicable selectors, prepare selected inputs, acquire views, perform each configuration operation | Core registry state or private binding access |
|
||||
| `ckprompt` private implementation | Capture definition providers, adapt engine inspection, prepare definition input/state, render definition reports | A second dispatcher/parser or configuration-suite installation |
|
||||
@@ -164,9 +165,8 @@ Keep payload and children independent in the private model. Do not introduce a
|
||||
new prohibition on runnable commands with children merely because separate leaf
|
||||
and group constructors are convenient.
|
||||
|
||||
The selected public addition is `Children []Command` on `CommandSpec[I]`. The
|
||||
registration API currently has no way to combine a handler with children; the
|
||||
private model alone cannot expose the behavior described by
|
||||
The selected public addition is [children on runnable commands](registration-api.md#runnable-parents-and-captured-children)
|
||||
through `CommandSpec.Children`. It exposes the behavior described by
|
||||
[ADR 0006](../adr/0006-command-grammar.md). Capture the child-handle slice using the
|
||||
same ownership and immediate composition checks as `Group`, and enforce the same
|
||||
placement rules at installation. `Group` remains a convenience for non-runnable
|
||||
@@ -434,8 +434,8 @@ metadata-only, while the original invalid loader must remain an error. Wrapping
|
||||
the nil loader in a non-nil acquisition closure would incorrectly defer it to
|
||||
invocation. A core `WithError` only accepts a `Command`, not a scope.
|
||||
|
||||
**Selected:** add the integration-owned operation
|
||||
`ckconfig.WithScopeError[I, S](scope Scope[I, S], err error) Scope[I, S]`.
|
||||
**Selected:** use the integration-owned [retained scope-error operation](registration-api.md#retained-scope-errors),
|
||||
`ckconfig.WithScopeError`, declared in the registration API document.
|
||||
It returns a scope retaining the original issue, preserving supported error
|
||||
identity. Repeated attachments preserve earlier causes and leave the original
|
||||
scope unchanged; a nil error preserves the scope. Retained causes survive scope
|
||||
|
||||
Reference in New Issue
Block a user