Validate independent module boundaries
This commit is contained in:
@@ -39,7 +39,6 @@ integration.
|
||||
- [Architecture policy](docs/policy/architecture.md)
|
||||
- [Policy provenance](docs/policy/meta.md)
|
||||
- [Deferred capabilities and proposals](docs/roadmap/deferred.md)
|
||||
- [Registration API design record](docs/roadmap/registration-api.md)
|
||||
|
||||
CommandKit is licensed under the [LGPL v3.0 or later](COPYRIGHT).
|
||||
|
||||
|
||||
@@ -131,9 +131,9 @@ The maintained consumers compile with their owning module suites and run without
|
||||
external services:
|
||||
|
||||
```sh
|
||||
go run ./examples/core greet --count=0 --tag=first --tag second
|
||||
go run ./examples/core workspace greet --count=0 --tag=first --tag second
|
||||
(cd integrations/ckconfig/examples/simple && go run . config show)
|
||||
(cd integrations/ckprompt/examples/composed && go run . config validate --scope all --campaign spring)
|
||||
(cd integrations/ckprompt/examples/composed && go run . config validate --scope all --campaign spring --limit=0)
|
||||
(cd integrations/ckprompt/examples/composed && go run . promptkit show prompt briefing --campaign spring --format yaml)
|
||||
(cd integrations/ckprompt/examples/composed && go run . session restore session-42 --campaign spring)
|
||||
```
|
||||
|
||||
@@ -252,3 +252,16 @@ License and notices: [BSD 3-Clause](licenses/BSD-3-Clause.txt) |
|
||||
[LICENSE](https://go.googlesource.com/mod/+/d3398d06de5fa5c71083d3d1c26f2cda73508e0f/LICENSE).
|
||||
|
||||
[Source](https://go.googlesource.com/mod/+/d3398d06de5fa5c71083d3d1c26f2cda73508e0f).
|
||||
|
||||
## Go tools
|
||||
|
||||
Selected module: `golang.org/x/tools` at `v0.49.0` (ReleaseKit tool graph dependency).
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
License and notices: [BSD 3-Clause](licenses/BSD-3-Clause.txt) |
|
||||
[LICENSE](https://go.googlesource.com/tools/+/18332fec72972efbb8ab9881984fec2d8cfc2b58/LICENSE).
|
||||
|
||||
[Source](https://go.googlesource.com/tools/+/18332fec72972efbb8ab9881984fec2d8cfc2b58).
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
# Implement the optional integration modules and captured registration API
|
||||
|
||||
Status: implementation in progress. Stages 1 through 15 are complete; subsequent work follows the ordered roadmap.
|
||||
Status: implementation complete. Stages 1 through 16 are complete.
|
||||
Execute the stages in order. Each stage is sized as a separate Luna coding-agent
|
||||
assignment. This document authorizes no publication or changes to sibling
|
||||
repositories.
|
||||
|
||||
## Scope and authority
|
||||
|
||||
Deliver the target in the [module roadmap](modules.md), the exact declarations
|
||||
and behavior in the [registration API](registration-api.md), and the selected
|
||||
mechanics in the [registration backend design](registration-backend.md).
|
||||
Read [development orientation](../development.md) and its applicable policy guide
|
||||
before implementation. The [architecture policy](../policy/architecture.md) and
|
||||
accepted ADRs control if a planning instruction conflicts with them.
|
||||
This report retains the implementation sequence and completion evidence.
|
||||
Current contracts belong to the [core GoDoc](../../doc.go),
|
||||
[ckconfig GoDoc](../../integrations/ckconfig/doc.go),
|
||||
[ckprompt GoDoc](../../integrations/ckprompt/doc.go),
|
||||
[consumer guide](../consumers/guide.md), [CLI reference](../cli.md),
|
||||
[internal overview](../internal/overview.md), and
|
||||
[release procedure](../release.md). Read [development orientation](../development.md)
|
||||
and its applicable policy guide before related work. The
|
||||
[architecture policy](../policy/architecture.md) and accepted ADRs control
|
||||
architecture decisions.
|
||||
|
||||
The governing decisions include [optional modules](../adr/0010-optional-integration-modules.md),
|
||||
[captured declarations](../adr/0011-captured-declarations-and-installation.md),
|
||||
@@ -51,9 +55,8 @@ Go 1.26.8.
|
||||
|
||||
The planning review found one module, integration source and examples in the
|
||||
root, ReleaseKit v0.3.0 selected as a Go tool, and a root-only release launcher.
|
||||
The [backend findings](registration-backend.md#baseline-findings) identify the
|
||||
parallel installation paths, repeated validation, mixed input/state storage, and
|
||||
help special case that this sprint replaces.
|
||||
The selected owners and current mechanics are recorded in the
|
||||
[internal overview](../internal/overview.md) and current package GoDoc.
|
||||
|
||||
One factual correction to earlier planning is necessary: core `v0.1.0` is
|
||||
already published on `origin`. The observed annotated tag object is
|
||||
@@ -614,7 +617,7 @@ dependency ownership.
|
||||
2. Rewrite ckconfig's simple example using `AppCommand`, with no dummy input/state
|
||||
types at its consumer call site. Retain a useful typed application command.
|
||||
3. Rewrite ckprompt's composed example using the finalized
|
||||
[three consumer examples](registration-api.md#complete-consumer-registration-examples)
|
||||
[three consumer examples](../consumers/guide.md)
|
||||
as API evidence: combined app/promptkit configuration scopes, applicable typed
|
||||
selectors, scope-aware checks, pointer input isolation, shared app-owned state,
|
||||
independent named inspection, and `session restore`.
|
||||
@@ -845,11 +848,20 @@ publication wiring are verified with no compatibility scaffolding.
|
||||
pending real dependency/sum preparation. The workspace should contain no
|
||||
unrelated generated files or temporary replacement manifests.
|
||||
|
||||
**Completion evidence:** all three module suites and representative consumers
|
||||
succeed; module/package graph checks prove the requested exclusion boundaries;
|
||||
current docs and licensing reflect distribution ownership; publication tooling
|
||||
selects one module through released contracts. Actual publication and upstream
|
||||
version adoption remain separate from this sprint.
|
||||
**Completion evidence — complete:** all three module suites pass with the local
|
||||
workspace, and the five maintained consumer invocations succeed. Workspace-off
|
||||
tests and three external consumer modules also pass using temporary module files
|
||||
with local replacements only for unpublished CommandKit modules; package and
|
||||
module graph checks confirm the intended core, ckconfig, and ckprompt dependency
|
||||
boundaries. Root tidy is clean, nested manifests were reconciled from temporary
|
||||
tidy runs, and no future-version checksums or distributed filesystem
|
||||
replacements were added. Public exports and ownership, installation/input cost
|
||||
paths, maintained guides, local links, license distribution, release notes, and
|
||||
the selected-module source-only release wiring were reviewed. Obsolete module,
|
||||
registration API, and backend planning documents were retired after their current
|
||||
owners and links were updated. No real publication was attempted. Actual
|
||||
dependency downloads and checksum preparation remain part of ordered release
|
||||
preparation after the prerequisite versions are published.
|
||||
|
||||
## Release handoff
|
||||
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
# Optional integration modules
|
||||
|
||||
Status: module boundary accepted in ADR 0010; consumer API and internal backend
|
||||
design finalized, with both composition questions resolved. The
|
||||
[staged implementation plan](implementation.md) is complete; no module extraction
|
||||
has begun. ReleaseKit v0.4.0 provides module-release support; CommandKit adoption
|
||||
is pending.
|
||||
|
||||
## Purpose and authority
|
||||
|
||||
Make CommandKit useful to consumers that use both ConfigKit and PromptKit,
|
||||
ConfigKit alone, or neither library. Consumers using only CommandKit's core
|
||||
should acquire neither ConfigKit nor PromptKit through CommandKit's package or
|
||||
module dependencies. ConfigKit-only consumers should not acquire PromptKit.
|
||||
|
||||
This roadmap records the targeted end state, selected module layout, and
|
||||
delivery boundaries. The [implementation plan](implementation.md) owns the ordered
|
||||
steps and validation needed to reach this target. The finalized
|
||||
[registration API](registration-api.md) owns the
|
||||
selected declarations, installation semantics, and representative consumer
|
||||
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.
|
||||
[ADR 0011](../adr/0011-captured-declarations-and-installation.md) records the
|
||||
finalized registration and invocation-lifetime decisions. The
|
||||
[architecture policy](../policy/architecture.md) is aligned with those decisions.
|
||||
GoDoc, the [CLI reference](../cli.md), and the [consumer guide](../consumers/guide.md) describe the prototype baseline; they do
|
||||
not make its incidental API shapes compatibility requirements for this sprint.
|
||||
|
||||
## Organizing principle: design the final API
|
||||
|
||||
Give the existing prototype implementation zero deference when selecting the
|
||||
final API, as directed for this transition. Core `v0.1.0` has since been published;
|
||||
preserve that release and prepare the incompatible replacement as a fresh minor
|
||||
release under the release policy. Publication does not change the selected API
|
||||
or require compatibility wrappers for this sprint. The goal is
|
||||
the best, simplest, most coherent API for the accepted responsibilities and
|
||||
representative consumers, not the smallest diff or a mechanically relocated
|
||||
prototype. Accepted architectural decisions and explicitly selected behavior
|
||||
remain requirements; prototype declarations, helpers, bookkeeping, and tests do
|
||||
not independently establish contracts.
|
||||
|
||||
Complete the transition in one sprint. No backward-compatibility wrappers,
|
||||
deprecation period, or migration bridge is needed. Intermediate commits need not
|
||||
build or pass tests; do not add temporary machinery merely to make them do so.
|
||||
Validate the complete target state before release. Reuse existing code where it
|
||||
serves that design, and refactor, replace, or remove it where it does not.
|
||||
|
||||
## Current baseline
|
||||
|
||||
At the start of this roadmap, CommandKit has one Go module and one supported
|
||||
public root package. It requires ConfigKit v0.5.0 and PromptKit v0.12.0 and
|
||||
declares Go 1.26.0. Its internal Cobra adapter implements routing and parsing.
|
||||
|
||||
The root combines core command infrastructure with configuration and PromptKit
|
||||
inspection. Coupling extends beyond constructors:
|
||||
|
||||
- `NewConfigKitScope` accepts ConfigKit results and maps their diagnostics.
|
||||
- Core `Diagnostic.Severity` currently uses ConfigKit's public severity type;
|
||||
moving inspection handlers alone will not remove that dependency.
|
||||
- `SourceReader` returns ConfigKit source records; `ExplanationReader` accepts
|
||||
ConfigKit paths and returns ConfigKit explanations.
|
||||
- `PromptKitSuite` callbacks return PromptKit inspection types.
|
||||
- `NewPromptKitScope` adapts engine configuration into the configuration suite.
|
||||
- Standard handlers share root-private helpers and state. For example,
|
||||
configuration registration accesses the application's registry and records
|
||||
whether the suite has already been installed.
|
||||
|
||||
The [internal overview](../internal/overview.md) describes the implemented
|
||||
inventory. The maintained examples and integration tests currently belong to the
|
||||
root module. ReleaseKit v0.3.0 is also selected there as a Go tool dependency;
|
||||
the [release procedure](../release.md) assumes one module and one version tag.
|
||||
|
||||
Optional command registration currently controls behavior, not dependencies.
|
||||
Moving integration code into packages sharing the root `go.mod` would separate
|
||||
compiled imports but retain integration requirements in the module graph.
|
||||
Go's [module graph rules](https://go.dev/ref/mod#module-graph-pruning) explain
|
||||
that distinction.
|
||||
|
||||
## Targeted end state
|
||||
|
||||
Provide three consumer modules in this repository with dependencies directed
|
||||
toward the core. Keep the core at `gitea.maximumdirect.net/eric/CommandKit` and
|
||||
give each integration its own `go.mod`:
|
||||
|
||||
| Directory | Module path | Package name |
|
||||
| --- | --- | --- |
|
||||
| Repository root | `gitea.maximumdirect.net/eric/CommandKit` | `commandkit` |
|
||||
| `integrations/ckconfig` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig` | `ckconfig` |
|
||||
| `integrations/ckprompt` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | `ckprompt` |
|
||||
|
||||
The `integrations/` grouping keeps optional modules together as their number
|
||||
grows; the anticipated three to ten integrations are planning context, not a
|
||||
limit or delivery commitment. Distinct package names avoid requiring local
|
||||
aliases when these integrations are imported alongside ConfigKit and PromptKit.
|
||||
Separate module files establish dependency isolation; directory naming alone
|
||||
does not. The shared repository requires explicit multi-module testing and
|
||||
publication orchestration.
|
||||
|
||||
| Module | Responsibility | Integration dependencies |
|
||||
| --- | --- | --- |
|
||||
| Core | Application construction, command/group registration, typed bindings, dispatch, help/version, common grammar, outcomes, and diagnostics | Neither ConfigKit nor PromptKit |
|
||||
| ConfigKit integration | Standard configuration family, scope composition, reports, and ConfigKit adapters | Core and ConfigKit; no PromptKit |
|
||||
| PromptKit integration | Named prompt/profile inspection and the PromptKit configuration-scope adapter | Core, PromptKit, and the ConfigKit integration |
|
||||
|
||||
The core remains an opinionated command library with its existing internal
|
||||
Cobra boundary. The dependency goal is independence from ConfigKit and PromptKit,
|
||||
not a standard-library-only implementation.
|
||||
|
||||
Integrations remain maintained parts of CommandKit. They install commands into
|
||||
the same application through supported public core operations and follow its
|
||||
grammar, help, invocation, and outcome conventions. Applications retain domain
|
||||
commands, acquisition, runtime construction, streams, and process exit.
|
||||
|
||||
The selected configuration boundary moves the existing ConfigKit-shaped
|
||||
contracts with their handlers into the ConfigKit integration. Only ConfigKit
|
||||
support is needed for now; a generic configuration interface is outside this
|
||||
migration. The PromptKit integration may depend on the ConfigKit integration,
|
||||
consistent with PromptKit's own ConfigKit dependency. Document that relationship
|
||||
in consumer guidance: `ckprompt` depends on `ckconfig`.
|
||||
|
||||
This boundary preserves one configuration suite into which
|
||||
applications compose `app`, `promptkit`, and other supported scopes. PromptKit
|
||||
configuration inspection and named-definition inspection remain independently
|
||||
selectable. A module dependency does not automatically install a command family.
|
||||
|
||||
Core public signatures and implementation imports contain no ConfigKit or
|
||||
PromptKit types. Integration-specific types and helpers move to their owning
|
||||
modules. Do not retain root forwarding wrappers that restore those imports.
|
||||
Shared helpers stay private unless a concrete cross-module interaction needs a
|
||||
supported contract; extraction is not a reason to expose every existing helper.
|
||||
|
||||
Preserve explicitly selected operator behavior: command vocabulary, selection
|
||||
and scope semantics, native reports, diagnostics, error identity, outcomes, and
|
||||
help without provider acquisition. Identify and decide any changes to selected
|
||||
CLI behavior separately. Do not preserve accidental prototype behavior or Go API
|
||||
shapes merely because they already exist.
|
||||
|
||||
### Selected API and release principles
|
||||
|
||||
- Use the finalized [uniform registration API](registration-api.md#declaration-and-installation).
|
||||
Applications and integrations produce captured core command declarations and
|
||||
install them through core `New` or `App.Register`; construction errors are
|
||||
retained for installation-time validation. Integration factories provide
|
||||
complete families and focused conveniences. The API document owns exact
|
||||
signatures and the [input/shared-state separation](registration-api.md#why-inputs-and-shared-state-have-separate-types).
|
||||
- Follow the selected [namespace lifetime and reconciliation requirements](registration-api.md#namespace-reconciliation-and-implementation-handoff).
|
||||
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
|
||||
wider data model into the core.
|
||||
- Version the modules independently according to their own changes and the
|
||||
[release policy](../policy/release.md#versioning-and-compatibility). Do not
|
||||
require integration version numbers to match either the core or upstream
|
||||
dependency versions. Record selected dependencies in `go.mod` and explain
|
||||
relevant upstream adoption in module release notes. Coordinate publication
|
||||
when changes span modules; independent versions do not imply an exhaustive
|
||||
compatibility matrix.
|
||||
|
||||
### Selected multi-module release approach
|
||||
|
||||
Adopt ReleaseKit v0.4.0 with module-release support. This is a planned tooling
|
||||
upgrade from the current v0.3.0 baseline, not an implemented CommandKit capability.
|
||||
Use ReleaseKit's public contracts for checking and
|
||||
publishing one explicitly selected module per invocation; do not build a separate
|
||||
CommandKit publication engine or temporary compatibility path.
|
||||
|
||||
Use one shared launcher with small per-module profiles. Each profile selects its
|
||||
repository-relative module directory and product identity; each invocation
|
||||
supplies that module's independently selected semantic version. ReleaseKit owns
|
||||
module-tag derivation, selected-module validation, repository publication guards,
|
||||
and publication outcomes. Root releases use unprefixed tags. Nested releases use
|
||||
their Go module-subdirectory prefixes, and notes belong at
|
||||
`<module-directory>/docs/releases/<version>.md`. Source and licensing links use
|
||||
the complete Git tag, while note titles identify the product and semantic version.
|
||||
|
||||
Run the selected module's standard suite once with workspace mode disabled and
|
||||
prepared dependencies. Repository cleanliness, branch, candidate commit, and
|
||||
endpoint guards remain repository-wide. A root-module release does not implicitly
|
||||
validate independently released nested modules; composition checks are selected
|
||||
deliberately where needed. Keep successful source-tag publication as completion,
|
||||
without CI, hosted delivery, proxy-availability, or installation gates.
|
||||
|
||||
CommandKit's preferred shared file inputs are repository-root `COPYRIGHT`,
|
||||
`LICENSE`, and `docs/oss/attribution.md`, when present, rather than the entire
|
||||
root `docs/` tree. Use v0.4.0's `validation.shared_files` field to select those
|
||||
three files explicitly, as documented by ReleaseKit. Shared inputs affect enabled
|
||||
file checks, not Go suite scope; resolving references does not add surrounding
|
||||
directories to the inputs.
|
||||
|
||||
Keep module selection and profile lookup repository-relative, module-owned
|
||||
validation settings and product-command execution module-relative, and diagnostic
|
||||
paths repository-relative. Use the provided repository context for shared scripts.
|
||||
The released [profile](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/b96262eb0ce9c8f2eb3e948a5841db2b799bc91b/docs/config.md)
|
||||
and [CLI](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/b96262eb0ce9c8f2eb3e948a5841db2b799bc91b/docs/cli.md)
|
||||
contracts govern profile fields, command syntax, module context, and shared-file
|
||||
selection. The implementation plan specifies their adoption; no separate
|
||||
publication engine is needed.
|
||||
Nested-module artifact builds, hosted delivery, and batch publication are not
|
||||
needed for CommandKit's source-only releases.
|
||||
|
||||
## Consumer examples and validation target
|
||||
|
||||
Three maintained public consumers demonstrate the final API:
|
||||
|
||||
| Adoption path | Example home | Required evidence |
|
||||
| --- | --- | --- |
|
||||
| Core only | `examples/core` | Typed commands/groups, presence, help/version; no optional-library imports or module requirements |
|
||||
| ConfigKit only | `integrations/ckconfig/examples/simple` | Focused `AppCommand` convenience and standard config reports; no PromptKit imports or module requirements |
|
||||
| ConfigKit and PromptKit | `integrations/ckprompt/examples/composed` | Combined configuration scopes, typed applicable selectors, independent scope inputs, shared state, named definition inspection, and an application-owned command |
|
||||
|
||||
Tests, fixtures, and benchmarks belong to the module owning their contracts.
|
||||
Mixed suites are split by responsibility; root tests and examples cannot
|
||||
reintroduce optional integration dependencies. Public composition checks belong
|
||||
in the PromptKit integration. Relevant existing coverage is retained or rewritten
|
||||
for selected behavior rather than incidental prototype API shapes.
|
||||
|
||||
Validation addresses package imports and each independently selected module
|
||||
graph, including transitive and tool requirements. Core-only consumers exclude
|
||||
both owning libraries and integrations; ConfigKit-only consumers exclude
|
||||
PromptKit and its integration. Root `go test ./...` alone cannot validate nested
|
||||
modules. The three modules' suites and representative public consumers provide
|
||||
composition evidence without an exhaustive historical compatibility matrix.
|
||||
|
||||
Local workspace composition supports development; distributed manifests contain
|
||||
versioned inter-module requirements, without filesystem replacements or committed
|
||||
workspace files. Workspace-off prepublication checks against local intended
|
||||
source establish wiring and isolation, not published-version availability.
|
||||
Released consumers resolve actual independently released versions without
|
||||
adjacent checkouts or consumer replacements. The implementation plan defines the
|
||||
prepublication checks and ordered release handoff.
|
||||
|
||||
## Documentation and distribution target
|
||||
|
||||
Implemented GoDoc owns exact exports and error/lifetime semantics. The consumer
|
||||
guide and READMEs present the final imports and optional-module selection directly;
|
||||
maintained examples demonstrate it. The CLI reference retains selected operator
|
||||
behavior, with registration/ownership prose matching the implemented API. Internal
|
||||
inventory and contributor navigation describe implemented owners and validation.
|
||||
No separate downstream prototype migration guide is required.
|
||||
|
||||
Each integration distributes a module-local README, project grant, complete
|
||||
license texts, applicable attribution and required notices, and module-local
|
||||
release notes. Required licensing material remains available in that module's Go
|
||||
source distribution rather than only through an outside-module local link. The
|
||||
existing grant and separately licensed material retain their terms. Repository
|
||||
attribution can retain factual entries for integration material while module-local
|
||||
notices identify applicable components.
|
||||
|
||||
Modules use independent versions. The planned core replacement is `v0.2.0`;
|
||||
ckconfig and ckprompt initially use `v0.1.0`. Their dependency requirements express
|
||||
that relationship explicitly. The already published root `v0.1.0` and its note
|
||||
remain intact. If a planned version is occupied before preparation, select a
|
||||
fresh appropriate version under the release policy. Core publication precedes
|
||||
ckconfig, which precedes ckprompt; actual released dependencies and corresponding
|
||||
sums are prepared for each candidate. Source-only publication still completes at
|
||||
successful tag publication, without proxy-availability or installation gates.
|
||||
|
||||
The release procedure and CommandKit-specific release-policy adaptations describe
|
||||
selected-module publication, independent versions, semantic-version note paths,
|
||||
full-tag links and recovery identity, and the root shared-file selection. Release
|
||||
profiles and launcher use released ReleaseKit contracts; additional delivery
|
||||
services and permanent migration gates are outside the target.
|
||||
|
||||
## Implementation status
|
||||
|
||||
ADR/architecture alignment, public API design, and internal backend design are
|
||||
complete. Module extraction, code refactoring, maintained consumers, validation,
|
||||
current documentation, and multi-module tooling adoption are not implemented.
|
||||
The [16-stage implementation plan](implementation.md) owns the sequence and
|
||||
completion evidence. Earlier accepted ADR decision text remains intact.
|
||||
|
||||
## Scope and follow-up
|
||||
|
||||
This work changes packaging and integration boundaries. It does not select a
|
||||
new backend, concurrent-dispatch contract, dynamic plugin system, or replacement
|
||||
configuration engine. It does not lower the existing Go minimum.
|
||||
|
||||
Keep the PromptKit v0.13.0 and ConfigKit v0.6.0 adoption identifiable as a separate
|
||||
change after extraction unless an implementation dependency justifies combining
|
||||
them. Catalogs and requirement discovery are subsequent integration features.
|
||||
Semantic comparison retains the upstream-contract dependency recorded in
|
||||
[deferred work](deferred.md). None is needed to demonstrate module isolation.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,500 +0,0 @@
|
||||
# Registration and execution internals
|
||||
|
||||
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](implementation.md)
|
||||
owns the ordered work and completion evidence.
|
||||
|
||||
## Purpose and authority
|
||||
|
||||
Provide the [registration API](registration-api.md) through one coherent internal
|
||||
system. Application commands, optional integration families, and built-in core
|
||||
commands should use the same declaration, installation, routing, and execution
|
||||
machinery. Command-specific handlers remain different where their responsibilities
|
||||
are different.
|
||||
|
||||
[ADR 0011](../adr/0011-captured-declarations-and-installation.md) owns the accepted
|
||||
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 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
|
||||
selected grammar, presence, outcomes, reports, and callback lifetimes. Private
|
||||
names below describe responsibilities rather than required exported symbols or a
|
||||
mandated file layout. This is design work, not a staged implementation plan.
|
||||
|
||||
## Baseline findings
|
||||
|
||||
The following findings come from the current implementation. They identify reuse
|
||||
opportunities and structural risks, not measured performance regressions.
|
||||
|
||||
| Evidence | Pain point | Proposed solution |
|
||||
| --- | --- | --- |
|
||||
| `New` in [app.go](../../app.go) inserts help/version placeholders; `installBuiltins` in [builtins.go](../../builtins.go) replaces them directly | Built-ins bypass ordinary registry installation and have separate reserved-node bookkeeping | Construct real built-in declarations and install them with caller declarations in one batch |
|
||||
| `Register` in [registry.go](../../registry.go) already stages roots before committing | Useful atomic installation exists, but privileged writers can bypass it | Make this the sole registry mutation boundary for every command source |
|
||||
| `RegisterConfig` in [config.go](../../config.go) checks the root namespace and `App.configRegistered` before calling `Register` | The configuration installer duplicates collision policy and carries integration state in the core | Integration factories return root-only declarations; core installation decides collisions |
|
||||
| `RegisterPromptKit` in [promptkit.go](../../promptkit.go) returns early when both inspection callbacks are nil | An absence shortcut can hide construction or metadata errors | Retain errors before representing absence; installation checks errors before skipping a no-op |
|
||||
| `Group`, `validateCommandDeclaration`, and `cloneCommands` in [command.go](../../command.go) recursively validate/copy child trees; registration repeats this | Nested assembly can revisit a subtree at each ancestor and again at installation | Capture immutable child handles and local metadata once; perform contextual installation checks in one traversal |
|
||||
| `normalizeConfigSuite` and `normalizePromptKitSuite` repeat flag-name, short-name, duplicate, and wiring rules | Moving integrations into modules could create several competing implementations of core binding policy | Validate generated command bindings in the core; integrations validate only their own suite semantics |
|
||||
| `adaptContextSelector` and `contextsForScopes` in [selectors.go](../../selectors.go) apply selectors to mixed context storage, then copy/project it again | Selector storage and shared state have tangled lifetimes; pointer contexts can alias | Capture converted values once; initialize each scope input independently; create shared state after all input checks |
|
||||
| Configuration `CheckInput` calls preflight, while `runConfigShow` and `runConfigValidation` select scopes again | Metadata selection and scope setup can be repeated between validation and execution | Carry an invocation-local prepared selection from `CheckInput` into `Run` |
|
||||
| `Execute` in [execute.go](../../execute.go) identifies `help` by its path and asserts its private input type | A built-in name controls a separate execution path | Let the help declaration's typed runner receive a private execution context through the common compiler |
|
||||
| `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 |
|
||||
|
||||
## 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.
|
||||
Use an internal package where it protects an actual dependency boundary.
|
||||
|
||||
| Owner | Internal responsibility | Does not own |
|
||||
| --- | --- | --- |
|
||||
| Core declarations | Captured command records, child handles, local declaration errors, root placement, explicit absence | Registry occupancy, provider acquisition, Cobra objects |
|
||||
| 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` (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 |
|
||||
|
||||
The neutral metadata package is justified by the existing core/adapter exchange:
|
||||
today its neutral structures live inside `internal/cobra`. Move those structures
|
||||
as a unit rather than introduce an additional copy of the same DTOs. Only the core
|
||||
execution coordinator needs to call the concrete adapter. Declaration and binding
|
||||
logic can depend on the neutral shapes without depending on adapter operations.
|
||||
This is not a backend-selection interface or a new public package.
|
||||
|
||||
Integrations use supported public core contracts. Do not solve extraction by
|
||||
letting them import core private assembly helpers. Small local selection-flag or
|
||||
report-formatting helpers are acceptable; a fourth utility module or a universal
|
||||
provider framework is not justified merely by a few similar declarations.
|
||||
|
||||
## One installation path for every command
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Application command factories] --> D[Captured core declarations]
|
||||
B[Integration family factories] --> D
|
||||
C[Core help and version factories] --> D
|
||||
D --> V[Shared batch validation and staging]
|
||||
V --> R[Instance registry commit]
|
||||
R --> M[Cached neutral routing and help metadata]
|
||||
M --> S[Fresh invocation adapter session]
|
||||
S --> E[Selected typed runner and common outcome delivery]
|
||||
```
|
||||
|
||||
### Construction and later registration
|
||||
|
||||
Recommend one private `installBatch` operation used by both `New` and
|
||||
`App.Register`:
|
||||
|
||||
1. `New` validates application identity and creates an unpublished empty app.
|
||||
2. Core factories construct real help/version declarations, using the same typed
|
||||
command compiler as application declarations.
|
||||
3. `New` submits built-ins and caller declarations together to `installBatch`.
|
||||
4. `App.Register` submits its supplied declarations to that same operation.
|
||||
|
||||
There are no placeholder commands, direct built-in registry writes, privileged
|
||||
installation switches, or separate family installers. The app exists before its
|
||||
built-in callbacks are captured, but those callbacks do not execute during
|
||||
construction. A failed initial batch exposes no usable app.
|
||||
|
||||
Help/version names are occupied by real built-in nodes. Optional family names are
|
||||
occupied only by installed real roots. The ordinary collision check consequently
|
||||
implements reservation without a parallel list of known integration names.
|
||||
Root-only placement is captured metadata, not a check for a particular family
|
||||
name or the package declaring it.
|
||||
|
||||
### Batch validation and commit
|
||||
|
||||
The shared installer should:
|
||||
|
||||
- Inspect retained errors and zero/absence state. Report attached errors before
|
||||
skipping an absent declaration, including absence nested in a group.
|
||||
- Traverse real declarations with their installation path; enforce root placement
|
||||
and report contextual construction/structural errors. Read captured binding
|
||||
validation results rather than invoking parsers or factories.
|
||||
- Check real root names against the existing registry and other roots in the
|
||||
pending batch. Sibling collisions inside a declaration belong to the same core
|
||||
structural-validation rules.
|
||||
- Stage additions in a local pending map. Commit only after the entire batch is
|
||||
valid. Existing captured nodes need not be cloned to stage new roots.
|
||||
- Invalidate derived routing/help metadata once after a successful nonempty
|
||||
commit. A failed batch or an entirely absent batch leaves registry and cached
|
||||
metadata intact.
|
||||
|
||||
All mutation is confined to the commit portion. Do not implement atomicity through
|
||||
temporary insertion followed by rollback or through copying the whole existing
|
||||
registry for every call. This preserves the selected per-call registry guarantee;
|
||||
it adds no transaction for callback effects, allocation failures, or concurrency.
|
||||
|
||||
Preserve retained causes with ordinary wrapping/joining where needed. Do not
|
||||
flatten them into strings. The implementation need not promise exhaustive error
|
||||
enumeration, stable error text, or a public aggregate-error type.
|
||||
|
||||
## Capture once; keep installation state separate
|
||||
|
||||
### Immutable declaration records
|
||||
|
||||
Recommend an opaque `Command` handle referring to a private captured record.
|
||||
That record contains descriptions, child handles, an optional compiled typed
|
||||
payload, retained errors, root-only placement, and explicit absence state.
|
||||
|
||||
Copy caller-owned metadata slices at their ownership boundary, including binding
|
||||
lists, child-handle lists, scope operations, and selector applicability. Once
|
||||
captured, those records are read-only. `Group` copies its child-handle slice;
|
||||
it does not recursively clone already captured child records. `WithError` returns
|
||||
a new wrapper/record retaining the existing content and added cause without
|
||||
mutating the original handle. `RootGroup` reuses ordinary group capture and adds
|
||||
placement metadata. A zero handle remains distinguishable from explicit absence.
|
||||
|
||||
This permits declaration reuse without copying entire trees at every assembly
|
||||
level. It does not clone application values, callbacks, or their object graphs.
|
||||
Do not write registry paths, app pointers, converted values, or invocation caches
|
||||
into reusable declarations. Core built-ins capture their own app-specific context
|
||||
when each app is constructed.
|
||||
|
||||
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 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
|
||||
parents. This addition requires no separate registration mechanism.
|
||||
|
||||
### Divide validation by responsibility and lifetime
|
||||
|
||||
Use one implementation of each core metadata rule:
|
||||
|
||||
- Command/binding constructors capture local metadata and retain local errors.
|
||||
- Group capture checks its immediate composition without recursively rerunning
|
||||
every child's local binding validator.
|
||||
- Installation checks contextual placement and registry/batch collisions while
|
||||
reporting retained errors through one tree traversal.
|
||||
- Integrations check scope identifiers, applicability references, declared
|
||||
operations, adapter issues, and enabled provider wiring. They hand generated
|
||||
flags and operands to core command construction for generic binding checks.
|
||||
|
||||
This prevents ancestor-by-ancestor validation and copying from growing with both
|
||||
tree size and nesting depth. Exact allocations remain implementation choices;
|
||||
do not add a global intern table, reflection-driven compiler, or mutable
|
||||
"validated" cache shared between applications.
|
||||
|
||||
Core name/short-name/help-reservation rules also check the combined standard and
|
||||
selector flags on generated commands. Integration code should not reproduce
|
||||
those rules with handwritten reserved-name lists. Validate bindings used by
|
||||
generated commands; unused selector bindings in an absent family are ignored,
|
||||
as clarified in the OQ-1 resolution below. Retained adapter-construction errors
|
||||
still reach installation.
|
||||
|
||||
## One typed conversion and application mechanism
|
||||
|
||||
### Prepared typed values
|
||||
|
||||
Retain the useful separation in the prototype's `prepareInput`: convert raw
|
||||
occurrences before initializing input. Refactor its prepared setter closures into
|
||||
one private typed prepared-value mechanism usable by ordinary bindings and
|
||||
`CaptureFlags`/`FlagValues`.
|
||||
|
||||
A prepared entry needs original binding identity, supplied state, and a typed
|
||||
application closure. The closure captures the converted/default value and applies
|
||||
it to initialized input storage. A repeatable binding copies its core-owned slice
|
||||
when applying it to another input; it does not clone arbitrary elements.
|
||||
|
||||
Scalar, boolean, repeated-flag, and operand constructors remain distinct where
|
||||
their parsing and cardinality differ. Their execution glue should feed the same
|
||||
typed preparation/application machinery, rather than create another conversion
|
||||
system for integrations.
|
||||
|
||||
`CaptureFlags` adapts each original binding to an outer command binding that stores
|
||||
the prepared typed entry in `FlagValues`. It does not apply selectors to a shared
|
||||
template, initialize suite input, or invoke a parser a second time.
|
||||
`FlagValues.ApplyTo` selects the original identities and applies their prepared
|
||||
values to the supplied destination.
|
||||
|
||||
All supplied occurrences undergo conversion, including selectors inapplicable to
|
||||
the selected scope and values supplied alongside help. Scope filtering governs
|
||||
value application and required-value checks, not conversion. An earlier malformed
|
||||
singleton occurrence remains an error even if a later occurrence is valid.
|
||||
|
||||
Recommend a private identity token per original binding and an invocation-local
|
||||
lookup from token to prepared entry. Handle copies preserve identity; lookalike
|
||||
bindings get a different token. A private nonzero-sized token object avoids
|
||||
relying on addresses of zero-sized Go objects. No global registry or public ID is
|
||||
needed. The lookup belongs to the invocation store, not the reusable binding.
|
||||
|
||||
### Required values and errors
|
||||
|
||||
Separate required metadata used for help from the point where execution enforces
|
||||
it. Ordinary flags enforce their requirement in ordinary input preparation.
|
||||
Captured inner flags enforce it when `ApplyTo` selects applicable bindings. Do not
|
||||
erase required metadata or reimplement missing-value policy in each integration.
|
||||
|
||||
Apply the API's existing `ErrFlagInput`/`ErrFlagWiring` categories through one core
|
||||
classification helper. The command's input-validation path should recognize
|
||||
wrapped wiring failures as operational; ordinary validation and missing input use
|
||||
usage outcomes. An integration may wrap those causes with scope/family context
|
||||
without parsing error messages or inventing another outcome protocol.
|
||||
|
||||
Help still converts supplied occurrences and rejects malformed values through the
|
||||
same preparation logic, but does not materialize the target command's application
|
||||
or suite input, invoke its validation or execution callbacks, or enforce its
|
||||
execution-required fields. Suite state factories and providers also remain
|
||||
uninvoked. The built-in help command may prepare its own private typed input
|
||||
through the common compiler. Presence, singleton repetition, and repeated-value
|
||||
semantics remain those of the finalized API and selected grammar.
|
||||
|
||||
## One compiled execution path, including help
|
||||
|
||||
Recommend that the private typed command compiler produce a prepared invocation
|
||||
closure. After raw conversion, this closure materializes `I`, applies values,
|
||||
runs `CheckInput`, and invokes the typed handler. Keep `I` inside that closure
|
||||
rather than passing an `any` input through separate factory/check/run calls and
|
||||
repeated type assertions. A heterogeneous registry can store the resulting
|
||||
non-generic private runner interface/function.
|
||||
|
||||
The private runner receives the current execution context, containing streams,
|
||||
cancellation, the app, and access to the current help/presentation session. For an
|
||||
application or integration handler, the compiler passes only the public
|
||||
`Invocation` and typed input. Built-in help uses a narrow private typed runner
|
||||
adapter to render targets through that same current execution context.
|
||||
|
||||
That private adapter shares declaration capture, metadata validation, binding
|
||||
preparation, registry installation, and outcome presentation with every other
|
||||
command. It changes only the final callback's access to core services. Version
|
||||
can use ordinary typed handler wiring with captured identity. Do not add a
|
||||
second built-in compiler or a dispatcher branch keyed on `path == "help"`.
|
||||
|
||||
The adapter's local `--help` mechanism is still common syntax machinery, not a
|
||||
separately registered application command. Bare root/group help and explicit
|
||||
help commands use the same presentation service. Cobra must not add hidden
|
||||
command families independently of captured registrations.
|
||||
|
||||
### Metadata and session lifetime
|
||||
|
||||
Preserve the existing cache/session split:
|
||||
|
||||
- Registry changes invalidate one derived neutral routing/help snapshot. Sorting
|
||||
and backend metadata projection occur when that snapshot is rebuilt, not on
|
||||
every parse or help operation.
|
||||
- A fresh mutable adapter session is built for each execution and reused for
|
||||
its parsing, help, and usage presentation. Mutable Cobra values are not cached
|
||||
across invocations.
|
||||
- Give each snapshot a private key-to-runner table. The adapter returns the
|
||||
selected neutral command key along with its path/raw values. Core execution
|
||||
uses the table associated with that session rather than resolving the same
|
||||
path again through `commandAt`.
|
||||
- Command keys are meaningful only within their snapshot. Do not expose them,
|
||||
depend on persistent numbering, or use a newly rebuilt table to interpret a
|
||||
result from an older session.
|
||||
- If a callback registers additional commands and subsequent presentation needs
|
||||
current metadata, refresh the presentation session on demand. Do not reparse
|
||||
argv or rerun factories, validators, or handlers merely to refresh help.
|
||||
|
||||
This removes duplicated route resolution and preserves useful existing behavior
|
||||
without promising concurrent dispatch, registration during another goroutine's
|
||||
execution, or a general snapshot-isolation contract.
|
||||
|
||||
## Integration preparation without parallel execution frameworks
|
||||
|
||||
### Configuration suite
|
||||
|
||||
At family construction, capture a private prepared suite containing ordered scope
|
||||
records, lookup by scope name, supported operations, discovery metadata, and the
|
||||
applicable original selector bindings for each scope. Those lists are a natural
|
||||
output of composing scopes and selectors; no separate mutable membership cache
|
||||
or public capability framework is needed.
|
||||
|
||||
Each inspection command uses an invocation-local outer input containing standard
|
||||
selectors, `FlagValues[I]`, and its prepared operation selection. Recommend a
|
||||
pointer-shaped private outer input initialized by the command's own `NewInput`.
|
||||
Its `CheckInput` can populate the prepared selection and `Run` receives that same
|
||||
object. This matters because the public `CheckInput` receives its generic input
|
||||
by value: assigning a plan to a field in a copied value struct would lose it.
|
||||
This outer allocation is distinct from the suite's input and shared-state
|
||||
factories and is not performed on help paths.
|
||||
|
||||
The shared configuration preparation routine should:
|
||||
|
||||
1. Resolve scopes, operation availability, formats, and applicable operand rules
|
||||
from metadata before suite factories or acquisition.
|
||||
2. For each selected scope, obtain a fresh `I` through `NewInput` or its zero
|
||||
value, apply only applicable captured bindings, and call the scope-aware
|
||||
`CheckInput` with scope identity and selection.
|
||||
3. Retain the successfully prepared scope/input records in selected order on the
|
||||
outer invocation input. On failure, return the supported error and stop;
|
||||
later inputs need not be initialized.
|
||||
4. In `Run`, after input validation succeeds and execution reaches acquisition,
|
||||
obtain shared `S` once through `NewState` or its zero value. Pass that state
|
||||
and each prepared input explicitly to the selected provider.
|
||||
|
||||
Do not recompute selection in every operation's `Run`, put the plan in a shared
|
||||
declaration closure, project a shallow copy of one input pointer, or clear
|
||||
non-applicable fields after initialization. Non-applicable bindings should leave
|
||||
the scope input's own initialized fields untouched.
|
||||
|
||||
Share this preparation across validate/show/sources/explain. Keep acquisition and
|
||||
report loops operation-owned: `show` acquires all selected views before report
|
||||
output, while other operations retain their selected timing. A universal
|
||||
"acquire everything then render" wrapper would alter behavior unnecessarily.
|
||||
Discovery reads captured metadata without initializing suite input or state.
|
||||
|
||||
`AppCommand` should build the ordinary scope and suite internally and call the
|
||||
same family factory. It is convenience assembly, not a second config installer,
|
||||
handler set, or execution cache.
|
||||
|
||||
### PromptKit suite and scope adapter
|
||||
|
||||
Definition commands use the same core captured bindings, typed runner, and outcome
|
||||
delivery. A small private definition-input helper applies the entire selected
|
||||
flag set, validates the typed input, and retains it for the runner. It needs no
|
||||
configuration-scope projection or inherited mixed-context selector model.
|
||||
|
||||
Within `ckprompt`, share engine loading/inspection and diagnostic adaptation
|
||||
between scope and named-definition adapters where their upstream contract is the
|
||||
same. Inspect the original loader before wrapping it. Provider lookup failures
|
||||
still retain diagnostics and error identity. Keep report models and native
|
||||
configuration views with their proper owners.
|
||||
|
||||
`ConfigScope` constructs a public `ckconfig.Scope` and delegates configuration
|
||||
command generation to `ckconfig`. It must not construct another config family or
|
||||
reach into `ckconfig`'s private prepared suite. Its construction-error handoff is
|
||||
the selected `ckconfig.WithScopeError` operation described below.
|
||||
|
||||
### Share mechanics where ownership supports them
|
||||
|
||||
Core owns outcome classification and diagnostic delivery once; integration
|
||||
handlers return public outcomes and diagnostic envelopes. Within an integration,
|
||||
share mundane writing/encoding and provider-error helpers where appropriate,
|
||||
while preserving each report's actual timing and incomplete-delivery semantics.
|
||||
|
||||
Some small helpers may remain similar between independent modules. Do not expose
|
||||
generic encoders, upstream severity converters, standard-flag getters, or a
|
||||
generic pipeline merely to eliminate a few lines. Important duplication to remove
|
||||
is competing registration, validation, conversion, acquisition-lifetime, and
|
||||
presentation policy—not every structurally similar field assignment.
|
||||
|
||||
## Efficiency and implementation review evidence
|
||||
|
||||
The intended cost profile is straightforward:
|
||||
|
||||
- Capture local metadata once and share read-only subtrees; avoid recursively
|
||||
copying/revalidating a child at every ancestor.
|
||||
- Stage only added roots, with one contextual tree walk and ordinary name
|
||||
lookups; avoid cloning the existing registry or installing commands one by one
|
||||
inside a supposedly atomic batch.
|
||||
- Derive routing/help metadata once per changed registry state, and use the
|
||||
adapter's selected command key rather than repeating route traversal.
|
||||
- Convert each supplied occurrence once per invocation. Apply prepared values
|
||||
only to selected inputs, copying only core-owned repeated collections.
|
||||
- Prepare scope selection once per invocation and shared state once when
|
||||
acquisition is reached. No process-global provider cache is introduced.
|
||||
|
||||
These are algorithmic recommendations, not latency/allocation guarantees. Existing
|
||||
benchmarks can inform the implementation sprint; this audit has not run them or
|
||||
measured performance. Profile before adding pools, segmented trees, bitsets,
|
||||
concurrent registries, or mutable backend reuse.
|
||||
|
||||
Focused implementation evidence should demonstrate the common path with all
|
||||
three command sources: built-ins, application declarations, and integrations.
|
||||
Include invalid bindings, conflicting roots in either order, an invalid final
|
||||
member of a batch, nested root-only declarations, absence with retained errors,
|
||||
source metadata edits after capture, and declaration reuse across apps.
|
||||
Include runnable parents with children through `CommandSpec.Children`, applying
|
||||
the same capture, collision, and placement checks as ordinary groups.
|
||||
|
||||
For execution, check wrapped wiring versus input failures, fresh repeatable
|
||||
collections, pointer-shaped scope inputs with shared state, scope-aware validation,
|
||||
help without target application/suite factories or providers, and metadata refresh
|
||||
without callback replay. Check that supplied but inapplicable selectors still
|
||||
undergo conversion, including on help paths, while the built-in help command can
|
||||
prepare its own private input through the common compiler.
|
||||
Evidence for the internal path itself can inspect the shared installer/compiler;
|
||||
do not turn a private function name or exact allocation count into a public
|
||||
contract. These are review targets for the future implementation, not a request
|
||||
to add or run tests during this planning pass.
|
||||
|
||||
## Resolved scope-error handoff (OQ-2)
|
||||
|
||||
The selected `Scope[I, S]` includes private adapter-construction issues owned by
|
||||
`ckconfig`. Before the selected addition below, `ckprompt.ConfigScope` could not
|
||||
attach its original nil-loader error through supported public contracts. An
|
||||
`Acquire == nil` check alone is insufficient: narrowing `Operations` to empty makes a scope
|
||||
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:** 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
|
||||
copies and narrowing of `Operations`. The family factory collects those issues
|
||||
into its command declaration before capability selection or absence can discard
|
||||
them. `ConfigScope` uses this for its original loader validation and
|
||||
otherwise fills the ordinary public scope fields.
|
||||
|
||||
This mirrors the accepted core retained-error model at the boundary that needs
|
||||
it. It does not add scope installation, expose private representations, or move
|
||||
PromptKit types into the core. Scope capture still occurs at the existing family
|
||||
factory; this operation is evidence attachment rather than a new lifecycle.
|
||||
|
||||
**Alternative considered:** give the public scope declaration an explicit
|
||||
construction-error field, consumed by the family factory alongside provider metadata. This is simple
|
||||
and permits application-created adapters to supply errors directly. It expands
|
||||
mutable public representation and requires defining preservation/combination of
|
||||
multiple errors; the opaque attachment operation keeps those details private.
|
||||
|
||||
## Resolved unused-binding validation (OQ-1)
|
||||
|
||||
**Selected:** empty definition suites contribute no commands, and unused selector
|
||||
bindings are ignored. Generate commands for the supplied capabilities and validate
|
||||
the bindings needed by those commands. When neither definition-inspection
|
||||
capability is enabled, the family contributes no namespace, help entry, or handler.
|
||||
There is no need to construct validation-only commands or a temporary application
|
||||
for selector bindings that will not be installed.
|
||||
|
||||
This follows the capability-driven assembly model: selecting no capabilities
|
||||
naturally produces no commands. Rejecting unused bindings would report defects
|
||||
that cannot affect routing, parsing, or execution. This clarifies the validation
|
||||
boundary while preserving ADR 0011's selected empty-suite behavior; it does not
|
||||
promise exhaustive validation of unused metadata.
|
||||
|
||||
An explicitly invalid adapter construction remains distinct from an omitted
|
||||
capability. Retain errors such as a nil loader supplied to an adapter even when
|
||||
its capabilities are subsequently cleared. Return ordinary `NoCommand()` for an
|
||||
empty definition suite, attaching any retained construction errors through the
|
||||
existing `WithError`. Installation checks those errors before skipping absence.
|
||||
No validation-bearing `NoCommand` overload or public declaration-validation helper
|
||||
is needed.
|
||||
|
||||
The binding rule also applies to configuration selectors unused by any generated
|
||||
inspection command. Existing configuration-suite semantics remain unchanged:
|
||||
zero named scopes is an error, while named metadata-only scopes supply the real
|
||||
`config scopes` discovery command and remain valid. Integration scope identifiers,
|
||||
applicability references, and enabled-provider wiring retain their own validation;
|
||||
ignoring unused bindings does not erase retained adapter errors or bypass checks
|
||||
on commands that are generated.
|
||||
|
||||
This construction-time rule does not skip invocation-time conversion of a supplied
|
||||
flag on an installed command merely because it is inapplicable to the selected
|
||||
scope. Conversion and scope-specific application remain separate as described
|
||||
above.
|
||||
|
||||
**Alternatives considered:** rejecting empty definition suites could catch an
|
||||
accidental omission, but would make an empty capability selection an error without
|
||||
a demonstrated need. Validating all unused bindings, through either an extended
|
||||
absence factory or an explicit validation helper, would catch latent defects but
|
||||
add public API and validation machinery for commands that do not exist. Neither
|
||||
alternative is selected.
|
||||
@@ -7,3 +7,9 @@ require (
|
||||
gitea.maximumdirect.net/eric/ConfigKit v0.5.0
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/cobra v1.10.1 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ definition inspection, and one application-owned command:
|
||||
|
||||
```sh
|
||||
go run . config scopes
|
||||
go run . config validate --scope all --campaign spring
|
||||
go run . config validate --scope all --campaign spring --limit=0
|
||||
go run . promptkit show prompt briefing --campaign spring --format yaml
|
||||
go run . promptkit show profile spring --campaign spring
|
||||
go run . session restore session-42 --campaign spring
|
||||
|
||||
@@ -5,6 +5,17 @@ go 1.26.0
|
||||
require (
|
||||
gitea.maximumdirect.net/eric/CommandKit v0.2.0
|
||||
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig v0.1.0
|
||||
gitea.maximumdirect.net/eric/ConfigKit v0.5.0
|
||||
gitea.maximumdirect.net/eric/promptkit v0.12.0
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.6
|
||||
)
|
||||
|
||||
require (
|
||||
gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v3 v3.20260930.0 // indirect
|
||||
gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v3 v3.20260930.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
||||
github.com/spf13/cobra v1.10.1 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user