15 Commits

71 changed files with 555 additions and 2284 deletions

View File

@@ -20,11 +20,12 @@ defines the shared visibility policy.
| --- | --- | --- | | --- | --- | --- |
| `go.maximumdirect.net/commandkit` | `commandkit` | Typed commands, bindings, execution reporting and outcomes, help, and version. | | `go.maximumdirect.net/commandkit` | `commandkit` | Typed commands, bindings, execution reporting and outcomes, help, and version. |
| `go.maximumdirect.net/ckconfig` | `ckconfig` | ConfigKit-backed `config` scopes, including configuration source evidence. | | `go.maximumdirect.net/ckconfig` | `ckconfig` | ConfigKit-backed `config` scopes, including configuration source evidence. |
| `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | `ckprompt` | PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, concrete request validation, and native smoke tests. | | `go.maximumdirect.net/ckprompt` | `ckprompt` | PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, concrete request validation, and native smoke tests. |
Importing an integration does not install commands. The ckconfig v0.2.0 Importing an integration does not install commands. The published ckconfig and
candidate uses core v0.3.0; ckprompt still uses the old core identity and cannot ckprompt v0.2.0 modules use core v0.3.0. The local
be composed with the new core path until its planned v0.2.0 release. See the ckconfig v0.3.0 candidate uses ConfigKit v1.1.0 and does not compose with
ckprompt v0.2.0; the published v0.2.0 pair remains matched. See the
[consumer guide](docs/consumers/guide.md#module-selection) for migration details. [consumer guide](docs/consumers/guide.md#module-selection) for migration details.
## Examples ## Examples
@@ -42,7 +43,7 @@ be composed with the new core path until its planned v0.2.0 release. See the
- [Maintainer release procedure](docs/release.md) - [Maintainer release procedure](docs/release.md)
- [Architecture policy](docs/policy/architecture.md) - [Architecture policy](docs/policy/architecture.md)
- [Policy provenance](docs/policy/meta.md) - [Policy provenance](docs/policy/meta.md)
- [Deferred capabilities and proposals](docs/roadmap/deferred.md) - [Future work and proposals](docs/roadmap/future.md)
CommandKit is licensed under the [LGPL v3.0 or later](COPYRIGHT). CommandKit is licensed under the [LGPL v3.0 or later](COPYRIGHT).

View File

@@ -363,14 +363,14 @@ sources:
- id: source-1 - id: source-1
label: "application config" label: "application config"
path: /etc/example/config.yml path: /etc/example/config.yml
layer: base layer: main
kind: file kind: file
underlay_index: 0 underlay_index: 0
imported_from: null imported_from: null
destination: /server destination: /server
placement: mapping placement: mapping
destination_unresolved: false destination_is_fallback: false
version_check: version_evidence:
path: /version path: /version
version: version:
present: true present: true
@@ -381,22 +381,28 @@ sources:
line: 2 line: 2
column: 1 column: 1
redacted: false redacted: false
empty_import_selections: []
``` ```
Each source includes `id`, `label`, `path`, `layer`, `kind`, `underlay_index`, Each source includes `id`, `label`, `path`, `layer`, `kind`, `underlay_index`,
and `imported_from`, plus the native destination pointer, placement, unresolved and `imported_from`, plus the native destination pointer, placement,
destination flag, and nullable `version_check`. Placement is `mapping` or `destination_is_fallback`, nullable `version_evidence`, and
`sequence_item`. The import location is null when absent; otherwise it has `empty_import_selections`. Placement is `mapping` or `sequence_item`. The
import location is null when absent; otherwise it has
`source_id`, `line`, and `column`. Version evidence preserves `path`, `present`, `source_id`, `line`, and `column`. Version evidence preserves `path`, `present`,
`null`, `text`, optional source `location`, and `redacted` as returned by `null`, `text`, optional source `location`, and `redacted` as returned by
ConfigKit. Owning values and source order are preserved, including empty fields, ConfigKit. Owning values and source order are preserved, including empty fields,
zero coordinates, false and null observations, and synthetic sources without zero coordinates, false and null observations, and synthetic sources without
paths. An absent version check is null. An empty inventory is `sources: []`. paths. Absent version evidence is null. Each empty-import record has a source-local
`path`, a `location` mapping (`source_id`, `line`, `column`), and a `selector`;
records preserve their returned order. No records are `empty_import_selections: []`.
An empty inventory is `sources: []`.
Text output begins with the scope heading and prints the same source fields, Text output begins with the scope heading and prints the same source fields,
quoting labels and paths. These fields project the selected ConfigKit source quoting labels and paths. These fields project the selected ConfigKit source
records; CommandKit does not reload files or rerun version checks. See the records; CommandKit does not reload files or rerun version checks. See the
[ConfigKit v0.8.0 inspection API](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go) [ConfigKit v1.1.0 source records](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/records.go)
for native evidence definitions. for native evidence definitions. Ckprompt v0.2.0 uses
[ConfigKit v0.8.0](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go).
### Explain a configuration path ### Explain a configuration path
@@ -427,7 +433,7 @@ effective:
redacted: false redacted: false
yaml: "localhost:8080\n" yaml: "localhost:8080\n"
origin: origin:
layer: base layer: main
locations: locations:
- source_id: source-1 - source_id: source-1
line: 4 line: 4

View File

@@ -13,14 +13,16 @@ installed at the application root, not as group children.
| --- | --- | | --- | --- |
| `go.maximumdirect.net/commandkit` | The application needs typed command declarations and common CLI behavior. | | `go.maximumdirect.net/commandkit` | The application needs typed command declarations and common CLI behavior. |
| `go.maximumdirect.net/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. | | `go.maximumdirect.net/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. |
| `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. | | `go.maximumdirect.net/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. |
The ckconfig v0.2.0 candidate uses core v0.3.0. The ckprompt source still uses The published matched releases are core v0.3.0, ckconfig v0.2.0, and ckprompt v0.2.0.
the old core and ckconfig identities; its planned matched v0.2.0 release will The local ckconfig v0.3.0 candidate uses ConfigKit v1.1.0 and does not compose
use the new paths. Update application imports and dependency versions together. with ckprompt v0.2.0, which retains ckconfig v0.2.0 and ConfigKit v0.8.0.
Old and new core paths have distinct Go type identities. Install core with Update application imports and dependency versions together; old and new core
`go get go.maximumdirect.net/commandkit@v0.3.0` and the matching integration paths have distinct Go type identities. Install core with
with `go get go.maximumdirect.net/ckconfig@v0.2.0` once it is published. `go get go.maximumdirect.net/commandkit@v0.3.0` and either integration with
`go get go.maximumdirect.net/ckconfig@v0.2.0` or
`go get go.maximumdirect.net/ckprompt@v0.2.0`.
The two integrations are independent optional imports. `ckprompt` uses the The two integrations are independent optional imports. `ckprompt` uses the
public scope and error contracts from `ckconfig`; importing it does not add the public scope and error contracts from `ckconfig`; importing it does not add the
@@ -30,12 +32,13 @@ core-only, ConfigKit-only, and composed applications.
## Go compatibility ## Go compatibility
All three modules declare a consumer minimum of Go 1.26.0. The root module also Core and ckprompt declare a consumer minimum of Go 1.26.0; the ckconfig
v0.3.0 candidate requires Go 1.27.0. The root module also
selects ReleaseKit v0.9.0 (`go.maximumdirect.net/releasekit`) as a Go tool, which selects ReleaseKit v0.9.0 (`go.maximumdirect.net/releasekit`) as a Go tool, which
makes that tool's module graph part of the root consumer module requirements makes that tool's module graph part of the root consumer module requirements
even though production packages do not import ReleaseKit. The even though production packages do not import ReleaseKit. The
[release policy](../policy/release.md#consumer-minimum-and-release-toolchain) [release policy](../policy/release.md#consumer-minimum-and-release-toolchain)
defines the support assumption. Maintainers use Go 1.26.8 for validation and defines the support assumption. Maintainers use Go 1.27.0 for validation and
publication; see the [release procedure](../release.md#release-toolchain). publication; see the [release procedure](../release.md#release-toolchain).
## Core commands ## Core commands
@@ -347,8 +350,24 @@ signal handling, and exit mapping; `Execute` never exits the process.
Go declarations and GoDoc own exact exported contracts. ConfigKit owns Go declarations and GoDoc own exact exported contracts. ConfigKit owns
configuration decoding, validation, and provenance. PromptKit owns prompt configuration decoding, validation, and provenance. PromptKit owns prompt
formats, profile resolution, and inspection details. See the formats, profile resolution, and inspection details. See the
[ConfigKit v0.8.0 inspection API](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go), [ConfigKit v0.8.0 inspection API for ckprompt v0.2.0](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go),
[PromptKit engine methods](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/engine.go), [PromptKit engine methods](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/engine.go),
[configuration inspection](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/configuration_inspection.go), [configuration inspection](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/configuration_inspection.go),
[smoke diagnostics](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/smoke_diagnostics.go), [smoke diagnostics](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/smoke_diagnostics.go),
and [PromptKit v0.16.0 consumer guidance](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/docs/consumers/pkg-promptkit.md). and [PromptKit v0.16.0 consumer guidance](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/docs/consumers/pkg-promptkit.md).
## ConfigKit v1.1 migration
The ckconfig v0.3.0 candidate uses `go.maximumdirect.net/configkit v1.1.0`
and Go 1.27.0. Consumers must migrate ConfigKit imports and values passed to
ckconfig: the old and new package paths have distinct type identities. Source
reports rename `destination_unresolved` to `destination_is_fallback` and
`version_check` to `version_evidence`, and add `empty_import_selections`.
The upstream [v0.9 migration notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v0.9.0.md),
[v0.10 notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v0.10.0.md),
[v1.0 migration notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v1.0.0.md),
and [v1.1 notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v1.1.0.md)
cover source-root `configkit` controls becoming `config`, import requiredness
and defaults, collection registration and operations, removed APIs, and CLI
assignment order.

View File

@@ -15,8 +15,8 @@ canonical documentation owners.
For application-owned aliases, use the For application-owned aliases, use the
[CLI reference](cli.md#application-owned-aliases), [CLI reference](cli.md#application-owned-aliases),
[Go declarations and GoDoc](../command.go), and [Go declarations and GoDoc](../command.go), and
[ADR 0013](adr/0013-application-alias-routing.md). Keep deferred capabilities in [ADR 0013](adr/0013-application-alias-routing.md). Keep unfinished work and
[deferred work](roadmap/deferred.md). capability proposals in [future work](roadmap/future.md).
## Initial orientation ## Initial orientation
@@ -54,17 +54,17 @@ For application-owned aliases, use the
| Task | Read | | Task | Read |
| --- | --- | | --- | --- |
| Implemented CLI behavior | [CLI reference](cli.md) | | Implemented CLI behavior | [CLI reference](cli.md) |
| Invocation reporting | [CLI reporting contract](cli.md#reporting), [consumer guide](consumers/guide.md#invocation-reporting), core GoDoc, [reporting roadmap](roadmap/reporting.md), and [ADR 0014](adr/0014-invocation-reporting.md) | | Invocation reporting | [CLI reporting contract](cli.md#reporting), [consumer guide](consumers/guide.md#invocation-reporting), core GoDoc, and [ADR 0014](adr/0014-invocation-reporting.md) |
| Application-owned aliases | [CLI reference](cli.md#application-owned-aliases), [Go declarations and GoDoc](../command.go), [consumer guide](consumers/guide.md#application-owned-aliases), and [ADR 0013](adr/0013-application-alias-routing.md) | | Application-owned aliases | [CLI reference](cli.md#application-owned-aliases), [Go declarations and GoDoc](../command.go), [consumer guide](consumers/guide.md#application-owned-aliases), and [ADR 0013](adr/0013-application-alias-routing.md) |
| Public API usage and standard-suite wiring | [Consumer guide](consumers/guide.md), [ckconfig package](../integrations/ckconfig/doc.go), [ckprompt package](../integrations/ckprompt/doc.go), and applicable ADRs | | Public API usage and standard-suite wiring | [Consumer guide](consumers/guide.md), [ckconfig package](../integrations/ckconfig/doc.go), [ckprompt package](../integrations/ckprompt/doc.go), and applicable ADRs |
| Dispatcher, registration, or typed inputs | [Command declarations](../command.go), [bindings](../binding.go), [invocation](../execute.go), and [ADR 0001](adr/0001-command-dispatch-and-inputs.md), refined by [ADR 0011](adr/0011-captured-declarations-and-installation.md) | | Dispatcher, registration, or typed inputs | [Command declarations](../command.go), [bindings](../binding.go), [invocation](../execute.go), and [ADR 0001](adr/0001-command-dispatch-and-inputs.md), refined by [ADR 0011](adr/0011-captured-declarations-and-installation.md) |
| Backend integration | [Internal overview](internal/overview.md), [adapter implementation](../internal/cobra/parse.go), and [ADR 0002](adr/0002-cobra-backend.md) | | Backend integration | [Internal overview](internal/overview.md), [adapter implementation](../internal/cobra/parse.go), and [ADR 0002](adr/0002-cobra-backend.md) |
| Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0003](adr/0003-public-facade.md) as scoped by [ADR 0010](adr/0010-optional-integration-modules.md), and the architecture policy | | Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0003](adr/0003-public-facade.md) as scoped by [ADR 0010](adr/0010-optional-integration-modules.md), and the architecture policy |
| Module ownership and public contracts | [Consumer guide](consumers/guide.md), [internal overview](internal/overview.md), [core GoDoc](../doc.go), [ckconfig GoDoc](../integrations/ckconfig/doc.go), [ckprompt GoDoc](../integrations/ckprompt/doc.go), and applicable ADRs | | Module ownership and public contracts | [Consumer guide](consumers/guide.md), [internal overview](internal/overview.md), [core GoDoc](../doc.go), [ckconfig GoDoc](../integrations/ckconfig/doc.go), [ckprompt GoDoc](../integrations/ckprompt/doc.go), and applicable ADRs |
| Deferred capabilities and proposals | [Deferred work](roadmap/deferred.md) | | Unfinished work and capability proposals | [Future work](roadmap/future.md) |
| Completed planning and implementation history | [Completed dependency upgrades, PromptKit validation, discovery, smoke testing, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/a6278a6d9f940948ec7745955d745523aaff0734/docs/roadmap), [earlier ConfigKit and PromptKit adoption and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap), [earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap), and [completed module implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/bb2528532b78d30e52f5082e491a5e1fd9b0fb99/docs/roadmap) in Git history | | Completed planning and implementation history | [Completed dependency upgrades, PromptKit validation, discovery, smoke testing, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/a6278a6d9f940948ec7745955d745523aaff0734/docs/roadmap), [earlier ConfigKit and PromptKit adoption and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap), [earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap), and [completed module implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/bb2528532b78d30e52f5082e491a5e1fd9b0fb99/docs/roadmap) in Git history |
| Release tooling | [Maintainer release procedure](release.md) | | Release tooling | [Maintainer release procedure](release.md) |
| Performance maintenance | [Internal overview](internal/overview.md), existing benchmarks, and [deferred efficiency work](roadmap/deferred.md#possible-further-efficiency-work) | | Performance maintenance | [Internal overview](internal/overview.md), existing benchmarks, and [possible further efficiency work](roadmap/future.md#possible-further-efficiency-work) |
| Licensing or incorporated material | [Project grant](../COPYRIGHT), [license texts](../LICENSE), and [attribution](oss/attribution.md) | | Licensing or incorporated material | [Project grant](../COPYRIGHT), [license texts](../LICENSE), and [attribution](oss/attribution.md) |
| Policy provenance | [Policy provenance](policy/meta.md) | | Policy provenance | [Policy provenance](policy/meta.md) |
@@ -72,11 +72,12 @@ Read all applicable rows for cross-cutting work. Go declarations and GoDoc own
current exported contracts; the CLI reference owns operator behavior. The current exported contracts; the CLI reference owns operator behavior. The
[maintainer release procedure](release.md) owns current release operations. [maintainer release procedure](release.md) owns current release operations.
Completed roadmaps and implementation evidence remain available in Git history, Completed roadmaps and implementation evidence remain available in Git history,
including [application-owned alias planning, implementation, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/f42aefe02d84e154855ac922173e6f367180929f/docs/roadmap) including [ConfigKit adoption, reporting, release-tooling, and remediation records](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/260256d722f52bc947103d078cb67a129f4cc9f1/docs/roadmap),
[application-owned alias planning, implementation, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/f42aefe02d84e154855ac922173e6f367180929f/docs/roadmap)
and [PromptKit requirements implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/40499a43608bf60d1104cd8ee24caf18ac0e9e66/docs/roadmap). and [PromptKit requirements implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/40499a43608bf60d1104cd8ee24caf18ac0e9e66/docs/roadmap).
These records are not assignments to restart completed work. The These records are not assignments to restart completed work. The
[deferred-work record](roadmap/deferred.md) preserves future capability targets [future work record](roadmap/future.md) preserves unfinished work and unselected
and unselected proposals separately from current contracts. proposals separately from current contracts.
## Documentation validation ## Documentation validation
@@ -99,28 +100,14 @@ Sibling-checkout references in retired planning records are historical review
evidence, not build dependencies. Implemented contracts belong in CommandKit evidence, not build dependencies. Implemented contracts belong in CommandKit
under their canonical owners. under their canonical owners.
The root module does not traverse nested modules. During the vanity-path The root module does not traverse nested modules. Preserve the ignored `go.work`
migration, ckprompt still imports the old core and ckconfig identities and and `go.work.sum`; use `GOWORK=off GOTOOLCHAIN=local` for dependency preparation,
cannot compose with the migrated modules until its own migration is complete. After module suites, and examples during the ckconfig migration. Local ckprompt uses
the matched migrations, during development use a the old ConfigKit identity and cannot compose with migrated local ckconfig. Its
local workspace for all three modules; it is ignored and must not be committed. independent suite and composed example use published ckconfig v0.2.0; restore
If a local `go.work` already exists, preserve it and add these module directories: full local workspace guidance after the coordinated ckprompt migration.
Run `go test ./...` separately from each module directory.
```sh
if [ -f go.work ]; then
go work use . ./integrations/ckconfig ./integrations/ckprompt
else
go work init . ./integrations/ckconfig ./integrations/ckprompt
fi
go test ./...
(cd integrations/ckconfig && go test ./...)
(cd integrations/ckprompt && go test ./...)
```
The workspace checks package behavior. Workspace-off checks with each module's
own dependency graph are separate evidence. For unpublished CommandKit dependency
versions, the [completed integration validation record](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap/implementation.md#stage-12-validate-the-complete-end-state-and-finish)
describes the disposable module-file procedure used during implementation.
Format changed Go files with `gofmt`. The Format changed Go files with `gofmt`. The
[maintainer release procedure](release.md) owns candidate preparation and [maintainer release procedure](release.md) owns candidate preparation and
publication commands. publication commands.
@@ -144,25 +131,25 @@ external services. The PromptKit smoke examples use local fixtures and the
example's configured client: example's configured client:
```sh ```sh
go run ./examples/core workspace greet --count=0 --tag=first --tag second GOWORK=off GOTOOLCHAIN=local go run ./examples/core workspace greet --count=0 --tag=first --tag second
(cd integrations/ckconfig/examples/simple && go run . config show) (cd integrations/ckconfig/examples/simple && GOWORK=off GOTOOLCHAIN=local go run . config show)
(cd integrations/ckconfig/examples/simple && go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml) (cd integrations/ckconfig/examples/simple && GOWORK=off GOTOOLCHAIN=local go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml)
(cd integrations/ckprompt/examples/composed && go run . config validate --scope all --campaign spring --limit=0) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . config validate --scope all --campaign spring --limit=0)
(cd integrations/ckprompt/examples/composed && go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml)
(cd integrations/ckprompt/examples/composed && go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring)
(cd integrations/ckprompt/examples/composed && go run . promptkit list prompts --config fixtures/before.yml --campaign spring) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list prompts --config fixtures/before.yml --campaign spring)
(cd integrations/ckprompt/examples/composed && go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml)
(cd integrations/ckprompt/examples/composed && go run . promptkit list backends --namespace team) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list backends --namespace team)
(cd integrations/ckprompt/examples/composed && go run . promptkit list namespaces --kind prompt --kind profile) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list namespaces --kind prompt --kind profile)
(cd integrations/ckprompt/examples/composed && go run . promptkit list collections) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list collections)
(cd integrations/ckprompt/examples/composed && go run . promptkit show prompt briefing --campaign spring --format yaml) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit show prompt briefing --campaign spring --format yaml)
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements show briefing --campaign spring) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements show briefing --campaign spring)
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml)
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt)
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt --var mode=full --input notes=fixtures/notes.txt --format yaml) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt --var mode=full --input notes=fixtures/notes.txt --format yaml)
(cd integrations/ckprompt/examples/composed && go run . promptkit test reachability --campaign spring --prompt briefing --profile spring) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit test reachability --campaign spring --prompt briefing --profile spring)
(cd integrations/ckprompt/examples/composed && go run . promptkit test all --campaign spring --prompt briefing --profile spring) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit test all --campaign spring --prompt briefing --profile spring)
(cd integrations/ckprompt/examples/composed && go run . session restore session-42 --campaign spring) (cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . session restore session-42 --campaign spring)
``` ```
The [consumer guide](consumers/guide.md) explains how their public API usage The [consumer guide](consumers/guide.md) explains how their public API usage

View File

@@ -6,10 +6,9 @@ own the optional ConfigKit and PromptKit integrations. The
[architecture policy](../policy/architecture.md) owns normative boundaries; [architecture policy](../policy/architecture.md) owns normative boundaries;
this page inventories the implemented owners. this page inventories the implemented owners.
The core and ckconfig modules declare `go.maximumdirect.net/commandkit` and The core, ckconfig, and ckprompt modules declare
`go.maximumdirect.net/ckconfig`. Ckprompt retains the old module and import `go.maximumdirect.net/commandkit`, `go.maximumdirect.net/ckconfig`, and
identities until its planned matched release; Go treats those identities as `go.maximumdirect.net/ckprompt`, respectively.
distinct.
## Root `commandkit` ## Root `commandkit`

View File

@@ -56,7 +56,7 @@ invariant, not from the convenience of the selected implementation. Explain the
specific failure it prevents and why a less restrictive implementation cannot specific failure it prevents and why a less restrictive implementation cannot
satisfy the contract. satisfy the contract.
The [deferred-work record](../roadmap/deferred.md) distinguishes future proposals The [future work record](../roadmap/future.md) distinguishes future proposals
from accepted contracts. Do not approve proposed commands, grammar, statuses, or from accepted contracts. Do not approve proposed commands, grammar, statuses, or
illustrative API declarations illustrative API declarations
merely by repeating them in implementation or tests. Cobra/pflag defaults do not merely by repeating them in implementation or tests. Cobra/pflag defaults do not

View File

@@ -294,7 +294,7 @@ recommended for application-owned commands; their names and domain behavior
remain application choices. remain application choices.
Accepted ADRs and current CLI/API owners define selected contracts; the Accepted ADRs and current CLI/API owners define selected contracts; the
[deferred-work record](../roadmap/deferred.md) preserves remaining proposals. [future work record](../roadmap/future.md) preserves remaining proposals.
Backend defaults and incidental consumer behavior do not establish new contracts. Backend defaults and incidental consumer behavior do not establish new contracts.
A replacement backend must preserve published CLI behavior or follow deliberate compatibility A replacement backend must preserve published CLI behavior or follow deliberate compatibility
changes under the release policy. changes under the release policy.

View File

@@ -35,20 +35,21 @@ module metadata.
## Release toolchain ## Release toolchain
The selected release toolchain is **Go 1.26.8**. Each module declares a consumer The selected release toolchain is **Go 1.27.0**. Core and ckprompt declare a
minimum of **Go 1.26.0**. Maintainers use Go 1.26.8 for dependency preparation, consumer minimum of **Go 1.26.0**; ckconfig requires **Go 1.27.0**. Maintainers
candidate validation, and ReleaseKit execution. The use Go 1.27.0 for dependency preparation, candidate validation, and ReleaseKit
execution. The
[consumer guide](consumers/guide.md#go-compatibility) and [consumer guide](consumers/guide.md#go-compatibility) and
[release policy](policy/release.md#consumer-minimum-and-release-toolchain) [release policy](policy/release.md#consumer-minimum-and-release-toolchain)
describe these selections. describe these selections.
Select Go 1.26.8 on `PATH`; the launcher uses `GOTOOLCHAIN=local`. If needed, Select Go 1.27.0 on `PATH`; the launcher uses `GOTOOLCHAIN=local`. If needed,
install it with the standard Go tools: install it with the standard Go tools:
```sh ```sh
GOWORK=off GOTOOLCHAIN=local go install golang.org/dl/go1.26.8@latest GOWORK=off GOTOOLCHAIN=local go install golang.org/dl/go1.27.0@latest
go1.26.8 download go1.27.0 download
export PATH="$(go1.26.8 env GOROOT)/bin:$PATH" export PATH="$(go1.27.0 env GOROOT)/bin:$PATH"
hash -r hash -r
GOWORK=off GOTOOLCHAIN=local go version GOWORK=off GOTOOLCHAIN=local go version
``` ```

View File

@@ -1,82 +0,0 @@
# Deferred work
Status: retained future work and unselected proposals; no implementation schedule.
## Purpose and authority
Completed initial delivery, performance, ReleaseKit upgrade, and remediation
records have been retired. This document preserves remaining deferred
capabilities and unselected ideas under the
[release policy](../policy/release.md#release-documentation-and-preparation).
The original records remain available in
[Git history](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap).
Accepted [ADRs](../adr/) and the [architecture policy](../policy/architecture.md)
govern any future implementation. The [CLI reference](../cli.md), public GoDoc,
and [consumer guide](../consumers/guide.md) own implemented behavior. Retaining
an idea here does not select its syntax, API, priority, or delivery date.
## Deferred capability targets
### Comparison extensions
Independent per-side domain selectors and an optional assertion mode remain
unselected extensions to the delivered ConfigKit comparison. Consider them only
for a concrete consumer need and a deliberate API/behavior decision under the
relevant ADRs.
### Alias completion and discovery
The delivered [shell completion feature](../cli.md#shell-completion) provides
canonical suggestions and alias-aware interpretation. Potential future work
includes suggesting command and flag alias spellings and valid continuations of
alias-only prefixes. For example, completion could suggest `inspect` after
`app legacy ` when `legacy inspect` is an installed alias.
Alias discovery is outside the initial scope. This deferral does not establish a
permanent canonical-only completion contract or prohibit future alias discovery.
A later design should determine how alias suggestions are presented alongside
canonical suggestions while ensuring inserted continuations form valid next
steps. No delivery date or final API is selected here.
## Other deferred proposals
These capabilities remain outside the delivered scope and require a concrete
operator or consumer need and an appropriate ownership/behavior decision:
- JSON reports and output-file management or reloadable export.
- Shell completion extensions, including alias discovery described above and
dynamic discovery of configured or remote values.
- Configuration mutation, generic value assignment, and exhaustive field-origin
inventories.
- Credential diagnostics beyond PromptKit's native smoke checks and additional
live provider probes.
- Additional component identity registration and domain artifact catalogs.
- Additional library families, including possible FeedKit integration; families
can define suitable verbs without requiring comparison or configuration scopes.
- Backend selection or replacement, a plugin framework, general dependency
injection, and concurrent-dispatch guarantees.
Execution, rendering, serving, and session operations remain application-owned.
Shared vocabulary is guidance under [ADR 0006](../adr/0006-command-grammar.md).
Backend replacement remains possible behind the accepted facade, subject to the
published API/CLI contracts and deliberate compatibility decisions.
## Possible further efficiency work
Selected-scope memoization and selector-membership indexes were deferred pending
measurements that justify their bookkeeping. Mutable backend reuse across
invocations, segmented aggregate YAML delivery, provider caching, consumer-loader
redesign, and a replacement backend were outside the completed performance
target. Reconsider them only with concrete motivation and review of ownership,
invocation state, native reports, and the affected contracts. Retained measurement
records are historical evidence, not performance guarantees or release gates.
## Consumer adoption
Consumer migrations remain separate from library delivery. Applications can
replace duplicated standard handlers and routing, then update their CLI docs
and subprocess consumers for intentional changes while retaining domain commands.
No migration order or claim about individual applications' adoption is recorded
here; the [consumer guide](../consumers/guide.md) and maintained examples provide
integration guidance.

183
docs/roadmap/future.md Normal file
View File

@@ -0,0 +1,183 @@
# Future work
Status: pending release and integration work, plus future capability proposals.
No delivery dates are selected here.
## Purpose and authority
Completed roadmaps, implementation plans, and review findings have been retired.
This document preserves unfinished work and unselected ideas under the
[release policy](../policy/release.md#release-documentation-and-preparation).
The completed ConfigKit adoption, reporting, dependency alignment, release-tooling,
and remediation records remain available at the
[retirement snapshot](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/260256d722f52bc947103d078cb67a129f4cc9f1/docs/roadmap).
[Earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap)
also remain in Git history. Completed records are not assignments to restart work.
Accepted [ADRs](../adr/) and the [architecture policy](../policy/architecture.md)
govern any future implementation. The [CLI reference](../cli.md), public GoDoc,
and [consumer guide](../consumers/guide.md) own implemented behavior. Retaining
an idea here does not select its syntax, API, priority, or delivery date.
## Pending release and integration work
### ckconfig release and hosted delivery
The ckconfig v0.3.0 candidate adopts ConfigKit v1.1.0 and Go 1.27.0; its
implementation and audits are complete. Its
[candidate release note](../../integrations/ckconfig/docs/releases/v0.3.0.md)
is prepared, but source publication and hosted delivery remain pending. Complete
those operations when requested through the [release procedure](../release.md),
using the existing fresh-version guards and reporting source publication and
hosted Gitea delivery separately. Publishing this roadmap cleanup does not
publish a module version tag or deliver a release page.
### ckprompt dependency migration and workspace alignment
Review the upstream PromptKit vanity release and select compatible ConfigKit
and PromptKit dependencies before migrating ckprompt's adapters and maintained
composed consumer. The new ckconfig uses vanity ConfigKit types; ckprompt v0.2.0
still uses published ckconfig v0.2.0 and old-path ConfigKit v0.8.0. Their local
sources do not currently compose in the three-module workspace. See the
[consumer guide](../consumers/guide.md#module-selection) for the current module
relationship.
The follow-up includes migrating affected imports and public type boundaries,
selecting real released dependency versions and the required Go minimum,
updating notices and migration guidance, and validating both ckprompt's
independent graph and the aligned composed consumer. Restore three-module
workspace guidance when those dependencies align, updating the ignored workspace
Go version as needed. Until then, preserve local workspace files and validate
with workspace discovery off as described in the [development guide](../development.md).
No unreviewed PromptKit version or new compatibility bridge is selected here.
## Future capability targets
### Comparison extensions
Independent per-side domain selectors and an optional assertion mode remain
unselected extensions to the delivered ConfigKit comparison. Consider them only
for a concrete consumer need and a deliberate API/behavior decision under the
relevant ADRs.
### Configuration inspection extensions
The [completed ConfigKit v1.1.0 adoption review](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/260256d722f52bc947103d078cb67a129f4cc9f1/docs/roadmap/configkit-v1.1.0.md#selected-scope-decisions)
retained the following work after dependency and source-report adoption.
Metadata inspection is the recommended next functional sprint; the other
features have no selected sequence or delivery date. These proposals do not
establish command grammar, report schemas, or new provider requirements.
ConfigKit's public APIs own the evidence and its semantics.
- **Optional field metadata, path discovery, and history (OD-3).** Expose native
`Metadata.Lookup`, `IsExplicit`, `HistoricalPaths`, and `History` through an
optional provider capability. Design field and history reports together,
keeping existing providers usable. Distinguish effective paths from removed
historical paths: a failed `Lookup` must not suppress available `History`.
Validate that distinction and faithful projection of returned field/change
records without recreating upstream provenance logic. Historical enumeration
is not an exhaustive inventory of possible schema fields. This gives the
earlier field-origin inventory proposal a concrete, upstream-backed scope;
command names, selectors, and report shapes remain to be designed.
- **Failed-load source inventory (OD-4).** Present acquired source evidence from
`LoadError.Sources()` while retaining the failed outcome and diagnostics.
Design how an adapter returns its source facet on error and how result output
precedes terminal failure presentation. Cover acquisition and report-delivery
failures together; current diagnostic context remains available meanwhile.
- **Detailed comparison (OD-5).** Consider an additional form projecting native
`Difference` paths, both snapshots, presence/redaction fields, and
`HiddenChanged`. The current comparison retains the reduced
additions/changes/deletions report. Decide later whether a detailed form
complements it or replaces it through a deliberate compatibility change.
- **Structured diagnostics (OD-6).** Consider machine-readable native codes,
paths, severities, and locations alongside CommandKit's shared reporting
design. Define result/diagnostic channels, warning and terminal-failure
interaction, and delivery outcomes. A ckconfig-specific report remains an
alternative, with its cross-family alignment considered explicitly.
- **Source-ID filtering.** Consider selecting a record already available in the
source inventory. Native `Source(id)` lookup is a convenience; this proposal
need not introduce another command or require a lookup method from every
custom source provider.
Discovery, import defaults, collection identities, and field-level resolution
recording remain available through application loaders. Standard inspection of
resource contexts or secrets-directory bootstrap has no immediate proposal;
those capabilities primarily serve application loading and startup.
### Alias completion and discovery
The delivered [shell completion feature](../cli.md#shell-completion) provides
canonical suggestions and alias-aware interpretation. Potential future work
includes suggesting command and flag alias spellings and valid continuations of
alias-only prefixes. For example, completion could suggest `inspect` after
`app legacy ` when `legacy inspect` is an installed alias.
Alias discovery is outside the initial scope. This deferral does not establish a
permanent canonical-only completion contract or prohibit future alias discovery.
A later design should determine how alias suggestions are presented alongside
canonical suggestions while ensuring inserted continuations form valid next
steps. No delivery date or final API is selected here.
### Reporting extensions
Error-conversion helpers such as `WarnError` remain deferred pending demonstrated
value; applications can already use `report.Warn(err.Error())`. Terminal redraw
and progress-bar presentation were outside the completed reporting scope and
remain unselected. Whole-run buffering to make failed runs show only errors
was also outside that scope. Any later extension needs a deliberate API and
presentation decision rather than assuming those behaviors are already provided.
### Release workflow extensions
Historical hosted-page backfilling and automated CI delivery remain separate
future choices. The current local page-only delivery workflow is implemented;
these extensions are not prerequisites for using it. The release procedure owns
delivery, immutable content, and recovery behavior.
Additional validation options, including race testing, full vet, compilation
matrices, size limits, and more forbidden-file paths, can be considered for
demonstrated needs. None is selected by retaining it here, and the existing
candidate checks do not become general prohibitions on development workspaces.
## Other future proposals
These capabilities remain outside the delivered scope and require a concrete
operator or consumer need and an appropriate ownership/behavior decision:
- JSON reports and output-file management or reloadable export.
- Shell completion extensions, including alias discovery described above and
dynamic discovery of configured or remote values.
- Configuration mutation and generic value assignment. Field metadata and
provenance inspection are scoped under
[configuration inspection extensions](#configuration-inspection-extensions).
- Credential diagnostics beyond PromptKit's native smoke checks and additional
live provider probes.
- Additional component identity registration and domain artifact catalogs.
- Additional library families, including possible FeedKit integration; families
can define suitable verbs without requiring comparison or configuration scopes.
- Backend selection or replacement, a plugin framework, general dependency
injection, and concurrent-dispatch guarantees.
Execution, rendering, serving, and session operations remain application-owned.
Shared vocabulary is guidance under [ADR 0006](../adr/0006-command-grammar.md).
Backend replacement remains possible behind the accepted facade, subject to the
published API/CLI contracts and deliberate compatibility decisions.
## Possible further efficiency work
Selected-scope memoization and selector-membership indexes were deferred pending
measurements that justify their bookkeeping. Mutable backend reuse across
invocations, segmented aggregate YAML delivery, provider caching, consumer-loader
redesign, and a replacement backend were outside the completed performance
target. Reconsider them only with concrete motivation and review of ownership,
invocation state, native reports, and the affected contracts. Retained measurement
records are historical evidence, not performance guarantees or release gates.
## Consumer adoption
Consumer migrations remain separate from library delivery. Applications can
replace duplicated standard handlers and routing, then update their CLI docs
and subprocess consumers for intentional changes while retaining domain commands.
No migration order or claim about individual applications' adoption is recorded
here; the [consumer guide](../consumers/guide.md) and maintained examples provide
integration guidance.

View File

@@ -1,351 +0,0 @@
# CommandKit vanity migration and dependency alignment plan
Status: Stages 1–3 complete; Stages 4–7 are not started.
This plan is for the Luna coding agent implementing the
[feature roadmap](integration-dependency-alignment.md). Follow the stages in
integer order during one end-to-end sprint. Unpublished editing states may be
temporarily inconsistent. Each published module must be a coherent, committed
candidate validated by its ordinary release workflow.
This planning pass changes documentation only. The target includes three real
source releases because later modules need downloadable predecessors. The
publication stages below describe that future work; this planning request does
not perform or authorize Git pushes. Honor the user's implementation/publication
scope when executing the plan, and report any unperformed release as pending.
Read [development guidance](../development.md), the
[agent policy](../policy/agents.md), [architecture policy](../policy/architecture.md),
[testing policy](../policy/testing.md),
[documentation policy](../policy/documentation.md),
[release policy](../policy/release.md), and [OSS policy](../policy/oss.md) for
the work they govern. Follow `AGENTS.md` codebase-memory discovery instructions.
The [release procedure](../release.md) remains the owner of operational commands.
The previous plan's [completed ReleaseKit v0.9.0 stages and evidence](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/c8d659dfe5ae3e834b3aeabdfd0fe29b736dc05a/docs/roadmap/implementation.md)
remain in Git history. R1/R2 in [remediation.md](remediation.md) and the ReleaseKit
adoption are complete; do not restart them or rewrite their historical evidence.
## Baseline and fixed decisions
Planning baseline: `c8d659dfe5ae3e834b3aeabdfd0fe29b736dc05a`.
| Module directory | Current module path | Target module path | Target version and full tag |
| --- | --- | --- | --- |
| `.` | `gitea.maximumdirect.net/eric/CommandKit` | `go.maximumdirect.net/commandkit` | v0.3.0; `v0.3.0` |
| `integrations/ckconfig` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig` | `go.maximumdirect.net/ckconfig` | v0.2.0; `integrations/ckconfig/v0.2.0` |
| `integrations/ckprompt` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | `go.maximumdirect.net/ckprompt` | v0.2.0; `integrations/ckprompt/v0.2.0` |
- Both integrations currently require core v0.2.0; ckprompt also requires
ckconfig v0.1.0. Their source uses newer core APIs. Independent baseline suites
fail; temporary local-source selections pass only when ckprompt also uses
current ckconfig. The feature roadmap records those diagnostics.
- Target ckconfig requires `go.maximumdirect.net/commandkit v0.3.0`. Target
ckprompt requires that core and `go.maximumdirect.net/ckconfig v0.2.0`.
- Vanity discovery is verified. The integration metadata's fourth field maps
the short paths to the existing physical directories. Existing tags still
declare old identities. Discovery alone does not complete module migration.
- Preserve package names, exported declaration shapes, runtime behavior, Go
1.26.0 consumer minimums, and the Go 1.26.8 maintainer toolchain. Preserve root
ReleaseKit v0.9.0 selection, scripts, profiles, endpoints, and validators.
- Retain ConfigKit v0.8.0 and PromptKit v0.16.0; no upstream library upgrade is
selected. Inspect tidy's actual graph changes and update affected attribution.
- The three proposed tags were unused at planning time. Existing publication
guards recheck freshness; never move/reuse a published tag. A conflict needs
a deliberate new version selection and matching dependent metadata/notes.
- Retain ignored `go.work` and `go.work.sum`, and the supplied ignored
`.releasekit/gitea-token` without reading its contents. No credential or live
provider is needed for local validation. Source publication uses the existing
Git endpoint; hosted delivery remains a separate operation/outcome.
Do not rename physical module directories or flatten integration tag prefixes.
Do not add an old-path forwarding module, type-interoperability layer, API
rollback, permanent validation shim, or new recurring release gate. These are
outside the selected migration, not new restrictions on application behavior.
## Execution and validation conventions
Use Go 1.26.8 on `PATH` following the existing
[toolchain setup](../release.md#release-toolchain). The ignored workspace declares
Go 1.26.10 at baseline; preserve it. Use `GOWORK=off GOTOOLCHAIN=local` for module
preparation and independent validation. Use normal dependency retrieval during
preparation; ReleaseKit runs the final selected-module suite offline/read-only.
Migrate module-owned source, tests, and examples together. Apply integration
path mappings before the broader core prefix when a replacement tool is used;
`go.maximumdirect.net/commandkit/integrations/ckconfig` is not the selected
ckconfig identity. Preserve import aliases such as `commandkit`. Core `internal`
imports must use the new core prefix. Review identity-sensitive strings as well
as Go import declarations.
Update current prose and GoDoc for the module being migrated. Treat repository,
license, and immutable historical source links separately from Go import paths.
Keep published notes, accepted ADR history, and completed review evidence intact.
Do not globally replace every old URL or migrate unrelated upstream identities.
Publication steps use the existing protocol: prepare dependencies, review and
commit the final selected candidate on `main`, publish that candidate commit to
the authoritative branch, and invoke the module's release wrapper. The wrapper
runs the owning complete suite once, selected file checks, and publication
guards, then creates/pushes the intended tag. It does not push `main` for you.
Run validation-only `check` for diagnosis when useful; do not make it a required
duplicate suite before `publish`. Do not add CI/proxy polling or post-push
read-back as a successful-publication gate. Reuse evidence for unchanged content.
Each release has its own candidate commit, suite result, and publication outcome.
The next module's dependency download is preparation for that next release;
failure to download does not undo completion of the predecessor's source push.
Use a command-scoped direct download to diagnose proxy lag if necessary rather
than permanently changing proxy settings. Retain authentic downloaded sums.
## Stage 1: Migrate core identity and prepare its release candidate
**Completed.** The root module, owned imports, component build identity,
consumer guidance, and v0.3.0 release note use the new core identity. The
focused build-identity test passed offline with Go 1.26.8; affected links and
whitespace were checked. The complete candidate suite belongs to publication.
1. Change only the root module declaration to `go.maximumdirect.net/commandkit`.
Migrate root-owned imports in production files, root/external tests, internal
packages, and `examples/core`. Leave nested module migration to Stages 3/5.
Preserve the root tool declaration and other dependency versions; prepare
caches and tidy the root with workspace discovery off.
2. Update `commandKitModulePath` in `builtins.go` to the new core identity.
`version --scope commandkit` uses it to find build information. Retain its
existing application/component scopes, tag/replacement handling, and `dev`
fallback; do not add a legacy-identity fallback.
3. Adapt existing identity/import-path test expectations. In
`TestCommandKitBuildIdentityProjectsEffectiveModuleVersion`, make at least
one existing successful tagged case supply the literal new module path
independently of `commandKitModulePath`. Otherwise a stale constant and its
self-referencing fixtures could agree while real version lookup fails.
Preserve all existing replacement/development cases and boundary assertions.
4. Update the root row in README's module table, current core imports and
installation guidance in `docs/consumers/guide.md`, affected developer and
internal guidance, example documentation, and GoDoc. Describe integrations
according to their implemented identity until their migration stages land;
keep the matched future set in migration guidance explicit.
5. Refresh `docs/releases/v0.3.0.md` against the full v0.2.0-to-candidate change:
aliases, reporting migration, completion, ReleaseKit maintenance, and the new
core import path. Explain consumer updates and the forthcoming matched
integration versions. Use current procedure URLs with immutable `v0.3.0`
source/licensing links. Keep the declared toolchains unchanged.
6. Format changed Go files. Review root-owned imports/identity literals and
module metadata; check affected prose links and whitespace. Run the existing
focused identity test with prepared caches:
```sh
GOWORK=off GOTOOLCHAIN=local GOPROXY=off GONOPROXY=none GOSUMDB=off \
go test -mod=readonly -count=1 -run '^TestCommandKitBuildIdentityProjectsEffectiveModuleVersion$' .
```
**Stage result:** a reviewed core v0.3.0 candidate with the new identity, correct
component version lookup, migrated root consumers, and current release notes.
The full root suite belongs to Stage 2's normal publication workflow.
## Stage 2: Validate and publish core v0.3.0
**Completed.** Core `go.maximumdirect.net/commandkit v0.3.0` was published as
tag `v0.3.0` at candidate `e256eb1cc02a0c72c4e23c4967ed1caeaef17008`.
The ordinary Go 1.26.8 release workflow passed the complete root suite and
selected file checks before the successful source-tag push.
1. Review and commit the complete core candidate under the local commit policy.
Confirm that unrelated/private files and ignored workspaces are excluded.
The independently released integration sources may still declare old paths;
that does not make their suites a prerequisite for this root release.
2. From the repository root, execute the existing publication sequence within
the authorized release scope:
```sh
git push origin HEAD:refs/heads/main
./scripts/release core v0.3.0
```
3. Require the real selected-module suite and file checks to pass. Fix actual
failures in scope and commit the corrected candidate before retrying. On a
failed/ambiguous push, use the existing publication evidence and recovery
procedure. Do not force refs, bypass guards, or treat a local tag as publication.
4. Record the candidate commit, module path, full tag, validation outcome, and
confirmed source outcome here. A successful tag push completes this source
release; move to dependent preparation without waiting for hosted pages.
**Stage result:** core v0.3.0 is source-published with
`module go.maximumdirect.net/commandkit`. Actual download of this version and its
sums is part of Stage 3, not a new completion gate for core publication.
## Stage 3: Migrate ckconfig and prepare its independent candidate
**Completed.** Ckconfig declares `go.maximumdirect.net/ckconfig`, imports the
new core identity, and downloaded `go.maximumdirect.net/commandkit v0.3.0`
with authentic sums. The resolved graph retains ConfigKit v0.8.0 and selects
both the older ReleaseKit v0.4.1 and vanity ReleaseKit v0.9.0 tool modules;
module-local attribution and current guidance reflect those selections. The
v0.2.0 release note is prepared; independent suite validation follows.
1. In `integrations/ckconfig`, migrate the module declaration to
`go.maximumdirect.net/ckconfig`. Update all owned imports, tests, and the
maintained simple example to that self-path and the new core path. Keep
package names and existing adapter behavior.
2. Replace its old core dependency key with the published new-path version.
From the ckconfig module directory, use:
```sh
GOWORK=off GOTOOLCHAIN=local go mod edit -module=go.maximumdirect.net/ckconfig -droprequire=gitea.maximumdirect.net/eric/CommandKit -require=go.maximumdirect.net/commandkit@v0.3.0
GOWORK=off GOTOOLCHAIN=local go mod download go.maximumdirect.net/commandkit@v0.3.0
GOWORK=off GOTOOLCHAIN=local go mod tidy
```
Perform source import migration before tidy to avoid resolving old imports.
Keep real downloaded sums. If retrieval is unavailable, resolve dependency
preparation before proceeding; do not fabricate metadata or substitute a
local replacement as final release evidence.
3. Inspect the actual direct and indirect graph, including tool requirements.
Preserve ConfigKit v0.8.0 and unrelated versions. Update affected notices in
`integrations/ckconfig/docs/oss/attribution.md` under the OSS policy using the
actual selected source revisions; add/retain applicable license texts. Do
not assume similarly named old/new upstream modules are interchangeable.
4. Prepare `integrations/ckconfig/docs/releases/v0.2.0.md` with product
`CommandKit ckconfig`, the new module/core paths, compatible dependency set,
and relevant reporting/completion migration. Immutable footer/source URLs
use the full tag `integrations/ckconfig/v0.2.0` and correct physical files.
5. Update README's ckconfig row, consumer module/import examples, the simple
example guidance, affected GoDoc, and relevant current release/development
references. Explain that applications moving to the new core identity also
use the matched new integration identity.
6. Format changed Go files. Review for stale owned imports/direct requirement
keys, accidental replacements/workspace files, and unexplained graph churn.
Check current links and whitespace. The owning complete suite runs in
Stage 4; a local workspace pass is not a substitute.
**Stage result:** a ckconfig v0.2.0 candidate whose actual dependency is
downloaded `go.maximumdirect.net/commandkit v0.3.0`, with authentic metadata and
aligned current documentation/attribution.
## Stage 4: Validate and publish ckconfig v0.2.0
**Status:** not started.
Review and commit the complete ckconfig candidate. From the repository root,
use the same authoritative-branch protocol as Stage 2:
```sh
git push origin HEAD:refs/heads/main
./scripts/release ckconfig v0.2.0
```
The normal release command must pass the independent ckconfig suite, including
its maintained example, with workspace discovery off and without dependency
redirection. It must also pass selected committed-file checks and publication
guards. Do not insert the earlier temporary Go shim or weaken a selected check.
Apply the existing failed/ambiguous-publication procedure if needed.
Record the candidate, path, version, full tag, validation, and source outcome.
The intended tag is `integrations/ckconfig/v0.2.0`; the physical directory remains
`integrations/ckconfig` despite the short vanity module path.
**Stage result:** compatible ckconfig v0.2.0 is source-published under its vanity
identity. Downloading it for ckprompt is the next module's preparation.
## Stage 5: Migrate ckprompt and prepare its independent candidate
**Status:** not started.
1. Migrate `integrations/ckprompt` to `go.maximumdirect.net/ckprompt`. Update its
owned source/tests and composed example to import the new core, ckconfig,
and ckprompt paths. Preserve PromptKit adaptation and reporting behavior.
2. From that module directory, replace both old CommandKit dependency keys:
```sh
GOWORK=off GOTOOLCHAIN=local go mod edit -module=go.maximumdirect.net/ckprompt -droprequire=gitea.maximumdirect.net/eric/CommandKit -droprequire=gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig -require=go.maximumdirect.net/commandkit@v0.3.0 -require=go.maximumdirect.net/ckconfig@v0.2.0
GOWORK=off GOTOOLCHAIN=local go mod download go.maximumdirect.net/commandkit@v0.3.0 go.maximumdirect.net/ckconfig@v0.2.0
GOWORK=off GOTOOLCHAIN=local go mod tidy
```
Migrate imports before tidy. Retain actual downloaded sums; resolve fetch
failures as preparation rather than masking them with local source. A new
core with old ckconfig v0.1.0 is the known incompatible combination.
3. Review graph changes while retaining ConfigKit v0.8.0 and PromptKit v0.16.0.
Update affected module-local attribution and immutable notice links based on
the resolved graph, including transitive tools. Keep actual upstream module
identities distinct from the three CommandKit identities being migrated.
4. Prepare `integrations/ckprompt/docs/releases/v0.2.0.md` with product
`CommandKit ckprompt`, new imports/dependencies, and consumer migration.
Footer/source links use full tag `integrations/ckprompt/v0.2.0` and physical
module-local files. Preserve the published v0.1.0 record.
5. Update README's ckprompt row, consumer composition/import examples, composed
example guidance, affected GoDoc, and remaining current module descriptions.
Keep URLs to hosted repository files separate from Go package links.
6. Format changed Go files and review remaining owned old-path imports or direct
requirement keys, metadata, links, and whitespace. Keep the ordinary source
checks intact; the independent suite runs in Stage 6.
**Stage result:** ckprompt v0.2.0 composes the real new-path core and ckconfig
versions in its declared graph, with current guidance and authentic metadata.
## Stage 6: Validate and publish ckprompt v0.2.0
**Status:** not started.
Review and commit the complete ckprompt candidate. From the repository root:
```sh
git push origin HEAD:refs/heads/main
./scripts/release ckprompt v0.2.0
```
The normal publication workflow must pass the independent ckprompt suite and
composed consumer with actual downloaded predecessors, plus selected file and
publication checks. Preserve the offline/read-only suite environment and
ordinary recovery handling. No workspace or replacement shim supplies final
release evidence.
Record its candidate, module identity, full tag
`integrations/ckprompt/v0.2.0`, suite outcome, and source-publication outcome.
Report any separate hosted delivery under its own outcome; page publication
is not required to establish dependency alignment.
**Stage result:** all three matched source releases are published with vanity
module declarations and verified independent dependency graphs.
## Stage 7: Audit the completed migration and record evidence
**Status:** not started.
1. Review the cumulative diff against the feature roadmap. Confirm all three
module declarations, owned imports, examples, direct dependency keys, and
component build identity use the new paths. Preserve physical directories,
tag prefixes, root ReleaseKit selection, scripts/profiles, exported shapes,
Go minimums, and upstream versions apart from explained graph consequences.
2. Check that tests and current guidance use the new identities while historical
notes, accepted ADRs, and immutable source URLs retain their historical
meaning. Resolve current dependency-readiness claims that are now stale.
Do not mechanically rewrite every old-path reference in completed records.
3. Record each final candidate's exact commit, full tag, suite result, and
publication outcome. Identify diagnostic-only earlier evidence separately.
Reuse each successful publication suite for its unchanged candidate; do not
require another complete run just to finish this stage. Any later code or
metadata correction belongs in a new candidate/version under release policy.
4. Mark stages complete only with their stated evidence and update the feature
roadmap's status/link here. Preserve this record and prior immutable plans;
apply normal roadmap retirement only during later preparation. If publication
was outside the authorized implementation scope or could not finish, record
the actual prepared state and pending release stages rather than claiming
alignment is complete.
5. Review new evidence prose, links/fragments, intended staged files, and
`git diff --check` / `git diff --cached --check`. Commit any remaining
nonempty documentation unit with a short plain-English message, following
the local commit policy. Finish with a clean tracked worktree when only
planned work is present; preserve unrelated and ignored local files.
**Stage result:** the implemented and published matched version set has accurate
source/validation evidence, current migration guidance, and committed tracking.
Source release and hosted-delivery outcomes remain separate.
## Open Questions
None required to choose the implementation. Vanity paths, target versions,
physical layout, dependency order, validation ownership, and compatibility scope
are selected in the roadmap. Publication authorization is an execution-scope
constraint, not a reason to invent different versions, fabricated sums, or a
local-only substitute for the target end state.

View File

@@ -1,208 +0,0 @@
# Integration dependency alignment and vanity-path migration
Status: proposed release-preparation roadmap. This pass adds documentation only;
dependency changes and publication remain future work. The
[implementation plan](implementation.md) owns execution stages, concrete tasks,
and validation tracking; this roadmap owns the target and selected scope.
## Purpose and authority
Align the independently released integrations with the core APIs their current
source already uses, and migrate all three CommandKit modules to the supplied
vanity paths. Publish compatible module versions in dependency order so each
integration builds and validates against its declared, downloaded dependencies
with workspace discovery off.
The [release procedure](../release.md) owns publication commands and release
order. The [release policy](../policy/release.md),
[agent policy](../policy/agents.md), [testing policy](../policy/testing.md),
[documentation policy](../policy/documentation.md), and
[OSS policy](../policy/oss.md) govern the work. This roadmap selects the target
and release-preparation scope; it does not change those policies.
## Baseline and investigation evidence
Reviewed baseline: `289a171e97699ad9aa57ee2cc40bdad1c0b680a9`.
Vanity-path review baseline: `d7cbaed3ed18bc2909c8144f308e2dfd58ade7ec`.
Module declarations and library source were unchanged between these revisions.
- Both integration module declarations require core v0.2.0. The
[ckprompt declaration](../../integrations/ckprompt/go.mod) also requires
ckconfig v0.1.0; the [ckconfig declaration](../../integrations/ckconfig/go.mod)
has no dependency on ckprompt.
- Current integration source uses newer core APIs including `CompletionHint`,
`Explanation`, and `Reporter`. Both independent Go 1.26.8 suites fail to
compile with `GOWORK=off` and their existing read-only module graphs.
- Updating core alone is insufficient for ckprompt: published ckconfig v0.1.0
still uses removed core APIs, including `Invocation.Streams`,
`Outcome.Diagnostics`, and `SeverityError`, plus the old `Failure(error)`
call shape.
- The authoritative `origin` tag listing contains core v0.1.0 and v0.2.0, and
the two integration v0.1.0 tags. The proposed next versions below were unused
at review. Remote `main` was `230187296fae5253cb1773f16c2f1d1a39499ed0`;
the reviewed local changes still need normal publication to the authoritative
branch as part of candidate preparation.
- A checked-in [core v0.3.0 draft](../releases/v0.3.0.md) already describes the
reporting and alias migration. It is an unpublished draft, not proof that
the module version can be downloaded.
The investigation used disposable alternate module files, Go 1.26.8,
`GOWORK=off`, and read-only offline tests. Only temporary dependency selections
changed; the real module declarations, sums, and source remained unchanged.
| Current source under test | Temporary dependency selection | Result |
| --- | --- | --- |
| ckconfig | Current core source | Module suite and maintained example passed. |
| ckprompt | Current core source, published ckconfig v0.1.0 | Compilation failed in the old ckconfig implementation. |
| ckprompt | Current core and current ckconfig source | Module suite and maintained example passed. |
The successful cases retained ConfigKit v0.8.0 and PromptKit v0.16.0. These
results isolate the CommandKit dependency alignment needed here; they do not
prove that future published versions or their downloaded sums already exist.
### Verified vanity discovery
The core endpoint at `https://go.maximumdirect.net/commandkit?go-get=1` serves
the mapping to `https://forge.maximumdirect.net/base-layer/commandkit`. Go direct
discovery finds the existing core v0.1.0 and v0.2.0 tags. Fetching v0.2.0 through
the vanity path reaches its source but reports a module-path mismatch because
that release declares `gitea.maximumdirect.net/eric/CommandKit`.
Both integration endpoints now return HTTP 200 with these `go-import` contents:
| Vanity path | VCS | Repository URL | Subdirectory field |
| --- | --- | --- | --- |
| `go.maximumdirect.net/ckconfig` | `git` | `https://forge.maximumdirect.net/base-layer/commandkit` | `integrations/ckconfig` |
| `go.maximumdirect.net/ckprompt` | `git` | `https://forge.maximumdirect.net/base-layer/commandkit` | `integrations/ckprompt` |
Go 1.26.8 direct discovery finds each integration's v0.1.0 tag. Disposable
consumer fetches reach the correct nested `go.mod` and report its old declared
module path, confirming subdirectory routing. Discovery is working; the
existing tags have not migrated. The optional fourth metadata field is
supported from Go 1.25, within the existing Go 1.26.0 consumer minimum; see the
[Go discovery reference](https://go.dev/ref/mod#vcs-find).
## Targeted end state
### Compatible independently released modules
Use the following proposed next versions, subject to the existing fresh-version
publication guards:
| Module path | Physical module directory | Next release | Required CommandKit dependencies | Full tag |
| --- | --- | --- | --- | --- |
| `go.maximumdirect.net/commandkit` | `.` | v0.3.0 | None | `v0.3.0` |
| `go.maximumdirect.net/ckconfig` | `integrations/ckconfig` | v0.2.0 | `go.maximumdirect.net/commandkit v0.3.0` | `integrations/ckconfig/v0.2.0` |
| `go.maximumdirect.net/ckprompt` | `integrations/ckprompt` | v0.2.0 | `go.maximumdirect.net/commandkit v0.3.0` and `go.maximumdirect.net/ckconfig v0.2.0` | `integrations/ckprompt/v0.2.0` |
Minor integration releases fit the existing pre-1.0 compatibility policy: the
reporting migration changes consumer-facing behavior and adopts a core version
with incompatible API changes. The vanity migration also deliberately changes
Go module and import identities. Migration notes explain the new imports and
dependency set, provider results, invocation reporting, and application changes.
The three modules retain independent versions and source tags. Their candidates
may identify successive commits: core publication need not wait for integration
metadata that depends on that newly published core. Each selected module's
final release suite runs against its actual declared dependencies.
### Module and import identity
Change each module declaration and all CommandKit-owned imports to the matching
new path. Core self-imports, including its `internal` packages, use
`go.maximumdirect.net/commandkit/...`; integration self-imports use
`go.maximumdirect.net/ckconfig/...` or `go.maximumdirect.net/ckprompt/...`.
Cross-module imports and requirements use the complete new paths in the table,
including ckprompt's ckconfig dependency. Core component-version discovery uses
`go.maximumdirect.net/commandkit` as its build-info identity, retaining the
existing `version --scope commandkit` behavior with the new module path.
Update production files, tests, maintained examples, and any import-path-based
test expectations together. A declared vanity module that still imports the
old core path would select a different Go package identity and can violate
`internal` import rules. The matched new releases compose through one core
identity rather than mixing old-path and new-path CommandKit types.
Keep physical directories, repository URLs, and Git tag prefixes as shown. The
Go subdirectory metadata makes the short integration vanity paths resolve to
the existing layout. The existing release profiles select physical directories;
the migration does not rename those directories or flatten integration tags.
Published old-path versions remain immutable. This scope selects the new paths
for new releases and updates consumer guidance; it makes no new promise of
type interoperability between the two identities and adds no old-path forwarding
module or compatibility layer.
### Retained architecture and scope
Preserve exported declaration shapes and runtime behavior while deliberately
changing module/import identities. Retain the integration adapters, Go 1.26.0
consumer minimum, Go 1.26.8 maintainer toolchain, and root-selected ReleaseKit
v0.9.0. The earlier successful diagnostic suites establish the dependency fix
before renaming; the migrated source still needs its own validation. This work
selects no API rollback or shim for old reporting APIs.
Retain ConfigKit v0.8.0, PromptKit v0.16.0, and other dependency selections
unless ordinary tidy changes the resolved graph as a consequence of the
CommandKit updates. Inspect and explain the resulting graph rather than
bundling unrelated upgrades. In particular, transitive tools with different
module paths may coexist; attribution must reflect the actual selection.
Preserve the existing launchers, three release profiles, generic validators,
credential handling, and separate source-publication and hosted-delivery
outcomes. Development workspaces remain useful and ignored. Diagnostic local
replacements and the earlier temporary Go shim remain development evidence;
release validation uses normal downloaded dependencies without that redirection.
## Release-preparation deliverables
The core v0.3.0 draft describes the complete candidate, including completion,
reporting, aliases, tool maintenance, and the vanity-path migration. New
integration notes at `integrations/ckconfig/docs/releases/v0.2.0.md` and
`integrations/ckprompt/docs/releases/v0.2.0.md` explain the matched dependency set
and consumer migration. Their source and licensing links follow the current
release procedure; published notes and tags remain immutable.
Current installation examples, README module selections, consumer/developer
guidance, affected GoDoc, and maintained examples use the implemented new
identities. Import-path-aware tests retain their existing boundary assertions.
Source-hosting and license URLs remain repository links, distinct from Go
import paths. Module-local attribution describes each actual resolved graph.
The final record identifies module paths, versions, candidate revisions,
validation evidence, and independent source-publication outcomes. Current
readiness guidance reflects the aligned state; historical failures remain in
completed investigation records. The implementation plan owns the ordered
migration, dependency preparation, release, and evidence-recording steps.
## Validation and completion boundaries
Review current CommandKit-owned source and dependency selections for stale
self-imports or old direct dependency keys. Historical notes, source URLs, and
unrelated upstream module identities are outside that mechanical rename.
Confirm release identity still pairs each new module path with its existing
physical directory and tag prefix. The verified redirects are preparation
evidence; publishing the renamed modules is needed for real consumers to use
them through those paths.
Use the selected module's ordinary deterministic offline suite with
`GOWORK=off` and read-only metadata after dependency preparation. Its maintained
consumer compiles and runs with that suite. ReleaseKit's publication command
owns the final candidate suite and selected file checks; validation-only checks
remain optional diagnostics. Reuse successful evidence for unchanged candidates
instead of adding a required check-then-publish repetition.
Retrieving a newly published dependency is preparation for the next module's
release. It does not turn proxy availability or consumer installation into a
completion gate for the preceding source release. Continue to resolve failed
or ambiguous publication using the existing policy and upstream recovery flow.
Hosted Gitea delivery keeps its separate outcome; this roadmap adds no CI
polling, live provider calls, or additional publication gate.
Alignment is complete when the matched source versions are published under all
three vanity module paths, owned imports and examples use the new identities,
each integration declares the compatible vanity-path versions with authentic
downloaded sums, each final selected-module suite passes without workspace or
replacement redirection, and current documentation and attribution agree with
that graph. Temporary local-source success alone does not establish that end
state.

View File

@@ -1,198 +0,0 @@
# Release tooling simplification
Status: the selected release-tooling design has been implemented. All four
generic file checks, registered-tool execution, page-only hosted delivery, and
protection of the supplied token path are selected.
The [completed implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/87eb84ccb462bf54e6250c8b287ac217efe90883/docs/roadmap/implementation.md)
contains stage order, tasks, validation, and completion evidence. Current release
behavior stays with its canonical owners.
## Purpose and authority
Reduce CommandKit's release infrastructure to declarative module profiles,
a small launcher, and focused tests of CommandKit-owned wiring. Delegate
reusable candidate validation and publication mechanics to ReleaseKit while
retaining CommandKit's domain-specific checks in their existing owners. Add
hosted Gitea release pages as a separate local delivery operation after source
publication.
The [agent policy](../policy/agents.md),
[release policy](../policy/release.md#candidate-validation), and
[testing policy](../policy/testing.md#upstream-integration-testing-ownership)
govern implementation. The [release procedure](../release.md) continues to own
the current workflow.
## Targeted end state
### Ownership
CommandKit retains module selectors, product identities, profile locations,
the authoritative endpoint selection, release order, release-note meaning,
compatibility decisions, and attribution accuracy. Its existing public API,
CLI, integration-adaptation, and consumer-example tests remain local and run
through the owning module's suite. No parallel release-only domain suite is
needed unless a concrete CommandKit requirement is otherwise unprotected.
ReleaseKit supplies the standard offline candidate suite, selected generic file
checks, candidate/note and publication guards, tag creation and publication,
hosted delivery, outcome reporting, and recovery. CommandKit's launcher delegates
those operations. Existing source-release completion and immutability rules
continue to apply. Hosted pages are the added delivery channel; binary
deliverables and platform support commitments remain unchanged.
### Profiles
Select these existing ReleaseKit options in each profile:
| Selection | Intended protection |
| --- | --- |
| `validation.go_format: true` | Detect unformatted committed Go source. |
| `validation.markdown: {}` | Detect broken local Markdown destinations and supported heading fragments. |
| `validation.module_distribution.workspace_files: true` | Detect committed development workspace files in selected inputs. |
| `validation.module_distribution.local_replacements: true` | Detect filesystem replacements in selected committed module declarations. |
Also select
`validation.forbidden_files: [".releasekit/gitea-token"]` in all three profiles.
This delegates protection of the supplied credential path to ReleaseKit's
existing check. The path is repository-relative and the check applies across
the captured repository even for an integration release. It does not read token
contents, scan other paths, or inspect Git history.
Retain the explicit shared-file lists and use ReleaseKit's existing input scope.
The root profile does not run every nested module's suite. File checks inspect
committed inputs and do not replace formatting worktree changes or reviewing
documentation meaning, attribution, and external links. Markdown keeps its
default treatment of outside-checkout destinations; no stricter boundary mode
is proposed.
The pinned [ReleaseKit configuration reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/23203f235cc414c4ffe0fd3941030eb0c9f9943f/docs/config.md)
owns exact scope and behavior, including nested-module boundaries and vendored
inputs. Do not expand an option's scope into a general repository prohibition.
Race testing, full vet, compilation matrices, size limits, and additional
forbidden-file paths are not selected by this roadmap. They can be considered
separately for demonstrated needs.
### Launcher and recovery
Use the root module's registered `go tool releasekit` through `exec`, keeping
the current selector interface and publication argument mapping.
Retain host normalization, workspace-off execution, the local toolchain, and
read-only module metadata. Preserve other effective Go settings while arranging
read-only selection.
The implementation plan specifies the wrapper interface and invocation details.
Go's cache supplies executable storage; the launcher creates no persistent
binary directory. `/.releasekit/` remains ignored for the credential file, with
an explanatory comment. Recovery instructions use the registered tool or the
entry point printed for the saved attempt, preserving ReleaseKit's distinction
between publication outcome and record-storage errors.
Share module selection and host-safe tool invocation between publication,
delivery, and recovery where applicable. Delivery selects the same module
profile as publication; recovery uses its recorded attempt rather than inferring
identity from a current profile. Keep the existing publication interface and
provide an explicit delivery invocation without automatically chaining the two
operations. Keep one selector mapping and shared invocation plumbing.
ReleaseKit v0.9.0 shipped host-safe consumer launcher examples and regression
coverage. The earlier simplification used v0.8.0, which already supported
registered tools. Keep host normalization locally because the reviewed
`go tool` invocation inherited foreign `GOOS`/`GOARCH` values and failed to run.
Do not switch tool-version selection from the root module to each integration
merely to match the upstream multi-module example.
### Hosted Gitea release pages
Configure this delivery selection in each module profile:
| Field | Selected value |
| --- | --- |
| `delivery.forge` | `gitea` |
| `delivery.base_url` | `https://forge.maximumdirect.net` |
| `delivery.owner` | `base-layer` |
| `delivery.repository` | `commandkit` |
| `delivery.token_file` | `.releasekit/gitea-token` |
Preserve the profiles' distinct product identities and physical module
directories. All pages belong to the same Gitea repository and are keyed by
the complete tag: `vX.Y.Z` for core, `integrations/ckconfig/vX.Y.Z` for ckconfig,
and `integrations/ckprompt/vX.Y.Z` for ckprompt. Pass the selected profile and
semantic version to `deliver`; ReleaseKit derives the complete module tag.
With no build targets, delivery is page-only. ReleaseKit uses the complete
checked-in module release note, including its licensing footer, as the hosted
body. No binary assets, receipts, or checksum manifests are added. Use current
forge URLs and the full module tag for future notes' immutable source and
licensing links. Existing published tags and notes remain unchanged.
After source publication succeeds, explicitly invoke delivery from a clean
checkout whose `HEAD` identifies that published tag's commit. For later retries,
use the original tagged source and its recorded module files. Report the source
publication outcome and hosted-delivery outcome separately, including the hosted
URL on success. A delivery failure leaves the source release complete; repair
delivery without republishing or moving its tag.
Delivery performs its own read-only credential preflight, without rerunning
candidate validation or publishing a tag. Hosted-service availability and the
Gitea token do not become source-publication gates. A nonblank
`RELEASEKIT_GITEA_TOKEN` environment value takes precedence over the configured
file. The file path resolves from the repository root for all three modules.
ReleaseKit accepts matching hosted content and reports conflicting content
without overwriting it. Resolve uncertain hosted writes before retrying the
same immutable version. The pinned
[delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/23203f235cc414c4ffe0fd3941030eb0c9f9943f/docs/consumers/delivery.md)
owns exact delivery behavior and recovery. Start with tags containing the new
delivery configuration; historical page backfilling remains a separate decision.
This local workflow needs no CI delivery job or additional secret distribution.
### Focused local tests
Replace the release-test scaffolding with a small controlled Go-command boundary
that invokes the actual launcher. Cover:
- Selector-to-profile/module routing for core, ckconfig, and ckprompt, including
consistency with the checked-in profiles' intended module and product.
- Invalid argument handling before tool invocation.
- Invocation from another directory and paths containing spaces.
- Host normalization and workspace/toolchain/read-only settings.
- Publication and delivery argument, output-stream, and child exit-status
forwarding, with the selected module profile reaching the delivery operation.
- Profile wiring for the shared Gitea destination, token path, and its selected
committed-path protection; assertions do not read the credential file.
Exercise module routing separately from exit statuses rather than multiplying
every combination. Assert behavior and meaningful selections, not helper
implementation details or exact usage prose.
The resulting local suite omits the disposable publication exercise, generic
tag inspection, assertion-helper self-tests, and custom build-call log/parser.
Upstream publication and delivery coverage owns those generic behaviors. No
replacement publication engine or exported test-helper API is needed. There is
no line-count target for the replacement tests.
## Selected choices and rationale
All four generic file checks are selected as release-time checks, in addition
to the agreed forbidden token path. Formatting and local-link validation automate
existing contributor review work. Workspace-file and filesystem-replacement
checks address accidental inclusion of development metadata that a successful
local test run can overlook. This adds specific release checks; it does not
make every optional ReleaseKit validator mandatory or prohibit development
workspaces and replacements outside the selected committed candidate inputs.
Selecting only formatting and Markdown would change less release behavior, but
would leave these distribution mistakes to manual review. The selected upstream
checks avoid a second local implementation.
Host-normalized registered-tool execution is selected because the root module
already registers ReleaseKit and Go caches the executable. Retaining a persistent
native executable would provide a recovery entry point independent of a later
Go-driver invocation, but would retain executable-storage and bootstrap test
maintenance. Recovery instead uses the registered tool or ReleaseKit's reported
entry point. The credential directory remains ignored under either approach.
The implementation plan records the existing integration dependency-version
mismatch separately from validation of the current source. This infrastructure
sprint does not publish releases or select new library dependency versions.
Historical hosted-page backfilling and CI delivery remain separate future
choices, not prerequisites for the selected local page-only workflow.

View File

@@ -1,184 +0,0 @@
# ReleaseKit v0.9.0 adoption
Status: R1 and R2 remediation, ReleaseKit v0.9.0 adoption, and the completion
assertion repair are complete. The [completed implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/c8d659dfe5ae3e834b3aeabdfd0fe29b736dc05a/docs/roadmap/implementation.md)
records stage order, tasks, and validation evidence. This document owns the
target and selected choices; it does not authorize source or hosted publication.
## Purpose and authority
Adopt ReleaseKit v0.9.0's improved recovery behavior while preserving
CommandKit's existing release-tooling architecture. Update current dependency
and maintainer documentation together, and make the validation evidence clear
about existing local defects.
The [agent policy](../policy/agents.md),
[release policy](../policy/release.md#candidate-validation),
[testing policy](../policy/testing.md#upstream-integration-testing-ownership),
and [documentation policy](../policy/documentation.md) govern the work. Current
behavior remains owned by the [release procedure](../release.md), Go declarations,
and owning package tests until implementation updates them.
## Current baseline and review evidence
Reviewed CommandKit code baseline: `4d92ee4ee6a8403b22a4172e0f04face802b9499`.
The original upgrade review used `98e7e9933353cf43f2be4a96cb0436a0bce068d2`;
its findings and validation history are retained below.
- The root [module](../../go.mod) selects
`go.maximumdirect.net/releasekit v0.8.0` as a Go tool. Its selected version
serves core, ckconfig, and ckprompt operations.
- The [shared helper](../../scripts/releasekit) already normalizes the Go host,
disables workspace discovery, selects the local toolchain, retains read-only
metadata, and invokes the full executable package path. The
[legacy entry point](../../scripts/release) delegates publication to it.
- All three profiles already select the agreed generic file checks, forbidden
token path, and page-only Gitea destination. Source publication and hosted
delivery are separate operations. The local token directory remains ignored.
- [R1 and R2](remediation.md) are complete. Commit `7eac3fe` rejects invalid
legacy selectors before invoking Go; commit `4d92ee4` restores explicit,
optional POSIX-shell invocation in launcher tests. The remediation record owns
their acceptance evidence, including passing focused tests, shell syntax
checks, and profile assertions running when no shell is available.
- Both integrations still require older published CommandKit dependencies than
their current source needs. The completed [release-tooling implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/87eb84ccb462bf54e6250c8b287ac217efe90883/docs/roadmap/implementation.md#stage-5-verify-the-final-source-and-record-validation-boundaries)
distinguishes workspace-backed tests from independent release readiness.
The upstream v0.9.0 tag identifies commit
`2180aa868ec2caa95fc8279fd59d5f0ebac41bd4`. The tag and direct Go-module
resolution were verified. The default proxy initially returned v0.8.0 for
`@latest`; select v0.9.0 explicitly rather than changing repository-wide proxy
settings to work around that observation.
Upstream [release notes](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/docs/releases/v0.9.0.md)
describe host-safe launchers and generated recovery commands, full package-path
tool selection, preservation of wildcard and version-specific replacements in
API-only recovery, and safer manual hosted-page retries. Public Go APIs,
profiles, record formats, and the Go 1.26.0 consumer minimum remain unchanged.
The v0.8.0-to-v0.9.0 comparison also left upstream module requirements, checksums,
copyright, and license texts unchanged.
A disposable CommandKit upgrade changed only the selected ReleaseKit version in
`go.mod`. With Go 1.26.8, the root suite passed on a subsequent run, both
workspace-backed integration suites passed, and the real helper reported v0.9.0
under foreign target settings. No production publication or delivery was run.
A later disposable review at `7eac3fe` confirmed that downloading and tidying
v0.9.0 changed only the ReleaseKit requirement and its checksum entries. The
offline root suite and both workspace-backed integration suites passed with
Go 1.26.8, and the helper reported v0.9.0 under Windows/ARM64 target settings.
That snapshot excluded the then-uncommitted R2 change; it does not replace
validation of the eventual adoption commit.
The initial upgrade run failed in
[`TestCompletionCommandContext`](../../completion_context_test.go). The same
alias-order failure reproduced four times in 30 focused repetitions on the
unchanged v0.8.0 baseline. A single passing rerun therefore does not establish
stable validation. The test compares an internal alias slice in a fixed order;
commit `0acbbf4` deliberately changed completion to use unsorted lookup records
before this upgrade review.
## Targeted end state
### Tool adoption and retained architecture
The root module selects ReleaseKit v0.9.0 with authentic downloaded checksums.
Its existing tool declaration and root-owned selection remain. No integration
dependency version, library import path, Go minimum, or selected Go 1.26.8
maintainer toolchain changes as part of adoption.
Keep host normalization and full-package invocation in the existing helper:
upgrading a dependency does not update or replace local shell scripts. Keep one
module/profile mapping and the established wrapper forms. Retain the selected
profiles, token-file handling, credential-directory ignore rule, and separation
of source and hosted outcomes. No new validator, binary target, CI workflow,
publication channel, credential preflight gate, or runtime API is needed.
The new generated Go recovery commands complement the helper's existing host
handling. Recovery continues to use saved publication evidence and the upstream
record formats; CommandKit does not acquire a parallel recovery implementation.
### Release-code simplification review
The v0.9.0 review identified no additional local release implementation to remove.
The earlier simplification already delegated generic validation, publication,
delivery, and recovery to ReleaseKit. This release improves launcher examples
and generated recovery commands without adding validation options that replace
the remaining CommandKit code.
Retain the shared helper's module/profile selection and execution environment.
Host normalization must happen before Go compiles and runs ReleaseKit. Retain
the legacy publication wrapper to preserve the established maintainer interface.
The upstream multi-module launcher example adds a module map and temporary
metadata preparation for a different tool-selection model; replacing our
root-owned registered-tool helper with it would add machinery.
Retain the focused [wiring tests](../../scripts/release_test.go) for profile
selections, argument forwarding, environment, streams, status, and optional-shell
handling. ReleaseKit owns validation and recovery semantics; CommandKit's tests
continue to cover its own adapter. The adoption work therefore preserves the
release-code structure while updating the dependency and documentation, alongside
the separately planned completion assertion repair.
### Current documentation and history
Current release procedure, project-specific release policy, consumer Go-tool
selection summary, and root attribution describe v0.9.0. Upstream contract and
notice links use the corresponding immutable source revision. Record that the
host-safe launcher request has shipped upstream instead of describing it as
pending in the earlier feature roadmap.
Continue linking to upstream recovery and delivery contracts from the maintainer
procedure. Use ReleaseKit's generated recovery commands and keep local guidance
focused on CommandKit's entry points and selections.
Preserve the baseline and validation history in completed implementation and
review records. Do not mechanically replace every historical v0.8.0 reference.
Integration attribution describes its own selected published dependency graph;
update it only if that actual selection changes. No license-text replacement
is needed for the unchanged upstream texts.
### Completed remediation and remaining correctness work
R1 and R2 were delivered before the dependency upgrade, with their completion
markers and acceptance evidence in [remediation.md](remediation.md). Preserve
their selector rejection, legitimate raw helper forms, and optional-shell test
boundary during adoption; no further implementation of those findings remains.
The completion assertion compares the expected alias source/target records
without depending on their iteration order, while detecting missing, unexpected,
or duplicate records. Its routing and visible-completion assertions remain.
Production alias ordering and public contracts are unchanged. This correction
was completed as part of the maintenance scope, separate from R1/R2 remediation;
the implementation plan records the test changes and focused verification.
Ordinary releases retain their single selected-module publication suite and
separate hosted-delivery outcome. One-time upgrade diagnostics are maintenance
evidence, with no new recurring release gate. Credentials and live publication
are unnecessary for this adoption.
## Completion evidence
Adoption is demonstrated by authentic module metadata, the real helper reporting
v0.9.0 for the host, aligned current documentation and attribution, and recorded
validation of the final source. The reviewed upgrade introduced no other module
version change; verify rather than assume that result during implementation.
R1/R2 acceptance evidence is complete in the remediation record. Completion of
the remaining maintenance work also includes a stable, order-independent
completion assertion and validation that the adopted helper retains the
corrected launcher behavior. Independent integration dependency alignment
remains separate release-preparation work; this roadmap selects no future
versions or sums.
## Resolved choices
R1 and R2 were corrected in separate commits before adoption, resolving the
former OD-1 scheduling question. Their acceptance evidence remains in
[remediation.md](remediation.md).
The selected maintenance scope is the completion assertion repair, root tool
upgrade, aligned current documentation and attribution, and validation of the
resulting source. The older integration dependency-version mismatch remains
separate release-preparation work. The implementation plan defines execution
and commit sequencing.

View File

@@ -1,116 +0,0 @@
# Release tooling review findings
Status: R1 and R2 complete; no open findings. Review baseline:
`124a9fa57fb3f815bedbafe2d4819f6aa265ee7d`, covering the implementation commits
after `cb40f1d`. The findings below preserve the review evidence; completion
markers record the subsequent corrections. No implementation was changed during
the original review.
The selected architecture is substantially present: three declarative profiles,
one host-normalized registered-tool helper, separate publication and page-only
delivery, retained credential-directory ignoring, and focused wiring tests.
Both issues identified by the review have been addressed.
## R1 — P2: Reject raw helper command names as legacy module selectors
**Completed.** The legacy entry point now checks its three module selectors
before delegating to the helper, retaining the single profile/module mapping
there. Regression cases cover all three raw-command collisions and require
usage status 2 with no Go invocation. The new regression failed before the fix;
the complete focused scripts suite and shell syntax checks passed afterward
with Go 1.26.8, including valid legacy and direct raw-command forwarding.
**Location:** [scripts/release](../../scripts/release), lines 9–10, delegating to
the first-argument dispatch in [scripts/releasekit](../../scripts/releasekit),
lines 10–15. The invalid-form cases in
[scripts/release_test.go](../../scripts/release_test.go), lines 186–200, miss
these collisions.
The legacy interface is `scripts/release MODULE VERSION`, with three module
selectors. It now delegates its first argument directly into a helper that also
accepts `version`, `publication-attempts`, and `reconcile` as raw commands. These
invalid module names consequently bypass selector rejection and invoke Go.
For example, `./scripts/release version v1.2.3` reaches the tool as
`version publish v1.2.3`. With the real pinned tool it returns upstream's
"version takes no arguments" diagnostic after tool resolution. In a disposable
copy with a controlled Go boundary returning status 73, each of the three raw
command names returned 73 and invoked Go; an ordinary unknown selector returned
2 without invoking Go. Thus invalid legacy input depends on tool availability
and behavior instead of being rejected at the wrapper boundary.
**Required correction:** Make legacy module selection unambiguous before raw
command dispatch. Keep one profile/module mapping and the supported raw helper
forms; a small selector check is preferable to another routing framework.
Preserve upstream ownership of version and flag validation.
**Verification:** Add all three raw command names as invalid legacy selectors.
Each must return usage status 2 before any Go command runs. Valid legacy
publication and the helper's direct raw forms must retain their forwarding and
exit-status behavior. This restores the requested malformed-wrapper handling;
it adds no new accepted-version restriction.
## R2 — P2: Restore the tests' optional POSIX-shell execution boundary
**Completed.** Launcher execution tests now discover `sh`, invoke it explicitly
with the script path, and skip when it is unavailable. Profile assertions remain
independent of shell availability. A regression case removes the fixture
script's executable permission to verify interpreter invocation; it failed
before the correction and passes afterward. The focused scripts suite and shell
syntax checks passed with Go 1.26.8 on the available POSIX host. Running the
compiled test binary with an empty `PATH` confirmed that every launcher
execution case skips while all three profile assertions pass. Native Windows
execution was not tested and no new platform guarantee is introduced.
**Location:** [scripts/release_test.go](../../scripts/release_test.go), especially
`fixture.run` at line 63 and the launcher test setup.
The rewritten tests execute extensionless POSIX shell scripts directly through
`exec.Command`. They neither discover a shell nor skip launcher execution when
it is unavailable. The previous suite resolved `sh`, skipped shell-dependent
tests when it was missing, and passed the script as an argument to that shell.
Direct execution works on this review's Linux host, but relies on Unix script
execution semantics. Native Windows process creation does not supply a POSIX
interpreter for these files. Go's
[os/exec documentation](https://pkg.go.dev/os/exec#hdr-Overview) explicitly notes
that it does not invoke a system shell. Consequently the default repository
suite now fails on hosts without compatible script execution rather than
preserving the previous optional-shell behavior. This portability finding is
based on the changed execution path and platform implementation; a native
Windows test run was not available during review.
**Required correction:** Discover a POSIX shell for launcher execution tests,
invoke it explicitly with the script path, and skip those tests when the shell
is unavailable. Keep profile-only JSON assertions runnable without requiring a
shell. Preserve the reduced test architecture and existing argv/status checks.
No native Windows release launcher or additional supported-platform guarantee
is requested.
**Verification:** Confirm that launcher tests use the discovered interpreter
and handle its absence explicitly, while profile assertions still run. Rerun
the focused suite on the available POSIX host. Broader platform matrices are
not a new release gate; this correction removes an incidental environment
restriction introduced by the test rewrite.
## Review evidence and limits
- Go 1.26.8 offline root tests and the temporary-workspace suites for both
integrations passed. Both production scripts passed shell syntax checks.
- The real helper reported ReleaseKit v0.8.0 under foreign target settings.
- ReleaseKit checks passed for a disposable committed source snapshot using
the actual profiles: ordinary root validation, then both integration checks
with the implementation plan's temporary workspace-backed test process.
Selected file checks continued to inspect the committed declarations.
- Local documentation destinations and applicable Markdown fragments passed
inspection. The credential file remained ignored and its contents were not
read. No real publication or hosted-delivery operation was invoked.
- Library code and dependency declarations were unchanged by the sprint. The
documented integration dependency-version mismatch remains a pre-existing
independent-release-readiness limitation; the workspace-backed results do
not establish that published dependencies are aligned.
No additional architecture gaps or unrequested runtime/public-API guarantees
were identified. The selected file checks and forbidden token path match the
finalized scope. R2 concerns the default tests' execution environment rather
than a new production validator or library contract.

View File

@@ -1,890 +0,0 @@
# Output policy and invocation reporting
Status: behavioral decisions selected through OD-4. Message categories, all four
output modes, uniform treatment of help and version, message prefixes, and
OD-1's flag grammar and scope (including independent Progress control) are selected.
OD-2's unified reporting direction, the terminal failure model, and application
ownership of domain-specific error decisions are selected.
OD-3's failure presentation and retention boundaries are selected.
OD-4's delivery lifecycle, write-failure handling, and quiet-mode rendering are
selected. The consumer API signatures, presentation-result model, provider
diagnostic boundary, fallback explanations, and rendering callback boundary
below are also selected. Architectural preparation is complete:
[ADR 0014](../adr/0014-invocation-reporting.md) is accepted, and the
[architecture policy](../policy/architecture.md) is aligned. Implementation and
final validation are complete; Stages 1–20 are complete. The [implementation
plan](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/230187296fae5253cb1773f16c2f1d1a39499ed0/docs/roadmap/implementation.md) records the stage order and validation evidence.
## Purpose
Provide consistent handling of `--quiet`, `--verbose`, `--debug`, and
`--progress` across application commands and optional integrations. Reduce
repeated output classification, diagnostic presentation, and delivery bookkeeping
where CommandKit can provide a meaningful benefit.
Ordinary Go writers and formatting functions already make application output
straightforward. Design reporting conveniences around the shared output policy
and invocation lifecycle. Applications continue to own their report content,
domain behavior, and operation outcomes.
## CLI presentation and error-handling ownership
Applications decide how to respond to domain-specific errors: recover, retry,
continue silently, report a Warning, or end the invocation with a failure.
CommandKit may provide shared helpers for carrying, inspecting, and presenting
errors while leaving those decisions with the application. A Go `error` alone
does not determine a CLI message category. Warnings may describe issues with or
without an underlying Go error, and handling an error does not require emitting
a message.
CommandKit handles the presentation the application requests: message category,
visibility, formatting, timing, and delivery. For terminal application failures,
the application supplies a non-zero outcome and an operator-facing explanation.
It may also supply an optional Go error cause for the execution caller to inspect.
CommandKit preserves that cause and its existing `errors.Is`/`errors.As` behavior.
Supplying a cause alone does not select an outcome, generate an operator-facing
message, or change visibility.
Applications can explicitly present `err.Error()` as a Warning through the
ordinary message API, illustrated by `report.Warn(err.Error())`. Defer a separate
`WarnError` convenience helper pending demonstrated value; this conversion
already requires little code.
CommandKit retains responsibility for handling its own errors, including
routing, parsing, and reporting failures. Integration-owned commands similarly
adapt their upstream APIs into deliberate command outcomes and presentations.
Ordinary Go error returns from CommandKit APIs and writers remain available where
appropriate.
## Current baseline
[`Streams` and `Invocation`](../../identity.go) expose caller-selected output
and diagnostic writers. [`Outcome` and `Diagnostic`](../../outcome.go) carry
operation causes, diagnostic writers, and delivery state. Handlers can return
`Failure(err)` or attach diagnostics to an outcome for presentation after the
handler returns. `MessageDiagnostic` currently writes the supplied message with
a newline; severity does not add a label automatically.
CommandKit coordinates final diagnostic delivery and retains delivery failures
separately from the operation cause. Custom handlers can also write directly to
the supplied streams and retain responsibility for their output. The existing
outcome and channel ownership decisions are recorded in
[ADR 0005](../adr/0005-invocation-outcomes.md).
Integration adapters already translate upstream diagnostic records into
CommandKit diagnostics while preserving native rendering and source context.
Some adapters wrap multiple records in one diagnostic writer and classify the
batch by its highest severity. This matters when designing selective visibility.
There is currently no shared verbosity policy or invocation reporter API.
## Selected output policy
Distinguish substantive application output from diagnostic message categories:
- **Substantive output (Normal):** The requested report or command result.
- **Error:** Terminal presentation of an unrecoverable invocation failure,
resulting in a non-zero status code.
- **Warning:** Something went wrong or deserves attention, but the invocation
can still succeed. The application chooses whether to report such an issue.
- **Info:** Informational context and useful explanation, such as which profile
was selected or a final operation summary.
- **Progress:** Streaming updates about work underway, such as items processed.
- **Debug:** Troubleshooting detail, including intermediate decisions and
execution-path information.
Debug mode adds troubleshooting detail to verbose output:
| Output category | `--quiet` | No flag | `--verbose` | `--debug` |
| --- | --- | --- | --- | --- |
| Substantive application output | Suppressed | Shown | Shown | Shown |
| Error | Shown | Shown | Shown | Shown |
| Warning | Suppressed | Suppressed | Shown | Shown |
| Info | Suppressed | Suppressed | Shown | Shown |
| Debug | Suppressed | Suppressed | Suppressed | Shown |
| Progress, without an explicit setting | Suppressed | Suppressed | Suppressed | Shown |
Info belongs in verbose mode; debug includes verbose messages. Normal output
remains a substantive result category, separate from diagnostic severity.
The category of a message determines its visibility; stream destination alone
cannot distinguish a warning from an error.
Progress is distinct from Info and is controlled separately as specified below.
Applications and integrations are not required to generate messages in any
category. Enabling a category adds no output when there are no messages in it;
other output remains subject to its own visibility rules.
Error presentation follows the terminal failure model below. An application
may report a recovered problem as a Warning or continue without a message.
Apply the same policy to help and version. There are no command-specific
exceptions for successful output:
```text
app help --quiet # succeeds silently
app version --quiet # succeeds silently
```
Usage and operational failures still report their errors in quiet mode.
The feature must distinguish successful output suppression from failure
diagnostic delivery.
### Message prefixes and channels
Substantive output uses the result destination, conventionally stdout. Warning,
Info, Progress, Debug, and terminal explanations use the diagnostic destination,
conventionally stderr. Callers supply both destinations.
Use `WARN:`, `DEBUG:`, and `ERROR:` prefixes for simple warning, debug, and error
messages respectively. Substantive output and Info messages have no prefix.
For multiline diagnostics, prefix the opening line and preserve the structured
detail. Integration adapters coordinate native diagnostic rendering to avoid
duplicate severity labels or loss of upstream formatting.
Usage guidance belongs to the terminal usage explanation and remains visible in
quiet mode. Successful help output follows the substantive-output policy.
Initially, Progress messages are unprefixed streamed lines. The diagnostic
destination keeps them separate from substantive output such as JSON or YAML.
Terminal redraw and progress-bar behavior are outside this implementation.
### Terminal failure model
During execution, applications can produce substantive output, Progress, Info,
Debug, and Warnings. An unrecoverable failure ends the handler by returning a
failed outcome. There is no standalone `report.Error(...)` method. Detailed
error explanations accompany the returned failure and are presented as part of
that terminal step.
CommandKit finalizes reporting, presents the terminal failure explanation, and
returns the non-zero outcome to the application entry point. It accepts no
further normal output for that invocation after terminal error presentation.
The same boundary applies to core routing and parsing failures that prevent
handler execution. The application entry point retains ownership of process
exit; CommandKit ends the invocation and returns its outcome.
For example, if an export operation fails and the application decides it cannot
continue, the handler returns a non-zero outcome with an explicit explanation
such as "Unable to export the requested report." The application can choose to
include detail from a Go error in that explanation. CommandKit presents the
supplied explanation without automatically deriving text from an application
error. The selected API below provides failure constructors for this purpose.
When a failed outcome supplies no explanation, CommandKit supplies the generic
fallback defined under terminal outcomes below.
Output streamed before the failure remains visible according to its selected
mode; terminal failure does not withdraw earlier bytes. Deferred messages,
cleanup writes, and delivery failures must respect the end of normal reporting.
Their finalization and late-write behavior follow OD-4 below. A terminal
failure may have multiple explanatory records, all belonging to that failure.
### Failure explanations and presentation ownership (OD-3)
Make a non-zero outcome with an explicit message the convenient failure path.
Support structured explanations, including multiple records, through the same
presentation facility for richer application and integration reports. Neither
form requires an underlying Go error.
The application or integration explicitly identifies the context belonging to
a terminal explanation. Present that context with the failure in every mode,
including quiet. Independent warnings and other messages retain their own
visibility rules. For mixed upstream batches, adapters preserve useful native
rendering while distinguishing terminal explanatory context from independent
messages. Core does not infer those relationships from error chains or text.
Assign each submitted message one presentation path. Returning a terminal
explanation schedules its presentation once; core does not append another
message derived from an application error cause. Native renderers can supply
already-labelled content without receiving duplicate prefixes. Avoid text-based
deduplication: separate events may legitimately produce identical messages.
Constructing a failure result attaches explanatory content without emitting or
independently scheduling an Error. Returning that result hands the explanation
to CommandKit for terminal delivery through the invocation's reporting facility.
The selected API expresses this distinction for both simple and structured
explanations. For example:
| Handler action | Presentation |
| --- | --- |
| Construct a non-zero result with "Unable to export the requested report," then return it. | Construction emits nothing. CommandKit presents the message once during terminal delivery. |
| Return a failure with native diagnostic records and their source context, submitting independent warnings separately. | CommandKit presents the structured terminal explanation in every mode. Independent warnings follow their own visibility policy. |
### Retention boundary (OD-3)
CommandKit provides invocation-scoped CLI presentation. Logging and message
history collection remain application concerns. Keep terminal explanations and
any supplied cause with the returned outcome, and keep the temporary state needed
for deferred delivery, parser events awaiting mode selection, and delivery
bookkeeping. The reporting facility does not collect a transcript or retain other
emitted or suppressed messages for later inspection. No optional message-history
facility is planned for this implementation.
## Selected flag grammar and scope
### Mode selection and resets
Model quiet, ordinary, verbose, and debug as mutually exclusive presentation
modes. Each invocation starts in ordinary mode. Process flag occurrences in
invocation order; the last enabled mode wins. Repetition does not increment
verbosity, and debug is selected explicitly.
Accept presence and the existing explicit boolean syntax, including
`--quiet=true` and `--quiet=false`. A false occurrence clears its mode only if
that mode is currently selected, returning to ordinary mode. It does not restore
an earlier selection or disable a different mode. Every occurrence is converted;
invalid boolean values remain usage errors even when a later flag would replace
the selection.
| Flag sequence | Final mode |
| --- | --- |
| `--quiet --verbose` | Verbose |
| `--debug --quiet` | Quiet |
| `--verbose --verbose` | Verbose |
| `--verbose --verbose=false` | Ordinary |
| `--quiet --verbose=false` | Quiet |
| `--verbose --quiet --quiet=false` | Ordinary |
| `--quiet=false --debug` | Debug |
Keep verbosity a presentation choice: quiet preserves the requested operation's
semantics and rendering failures. Delivery failures depend on the output actually
requested; suppressing a destination write can avoid a delivery failure. Apply
the policy through CommandKit-managed reporting and streams. Output written
directly to process streams or external destinations remains application-owned.
### Progress selection
`--progress` enables Progress without enabling Info, Warning, or Debug messages.
`--progress=false` explicitly disables it. Accept the existing boolean syntax;
repeated canonical or aliased progress settings use the last value. Retain
whether a setting was explicitly supplied, separately from its boolean value.
Determine effective Progress visibility from the final presentation mode and
explicit progress setting:
1. Quiet mode always suppresses Progress.
2. Otherwise, an explicit progress setting controls visibility.
3. Without an explicit setting, debug enables Progress; ordinary and verbose
modes leave it disabled.
An explicit progress setting overrides the mode's default regardless of its
position relative to mode flags. It does not select or reset the presentation
mode. Debug includes verbose detail and defaults Progress on; verbose alone
does not enable Progress.
| Flags | Result |
| --- | --- |
| `--verbose` | Warning and Info, without Progress. |
| `--verbose --progress` | Warning, Info, and Progress. |
| `--debug` | Warning, Info, Debug, and Progress. |
| `--debug --progress=false` or `--progress=false --debug` | Debug detail without Progress. |
| `--quiet --progress` or `--progress --quiet` | Only failure diagnostics. |
| `--debug --verbose` | Verbose detail without Progress, absent an explicit progress setting. |
Passing `--progress` to an application that emits no Progress messages adds no
visible output. It does not suppress that application's substantive results or
require a progress implementation.
### Placement, availability, and aliases
Core supplies `--quiet`, `--verbose`, `--debug`, and `--progress` for application
commands, integrations, the root, canonical groups, and alias-only discovery help.
Consumers do not register them individually. Preserve the existing placement
grammar: flags follow the complete command path and may be interspersed with
operands after that path. For example:
```text
app config show --quiet
app export destination --verbose
app help config show --quiet
app version --quiet
```
Options before or between command-path components are outside this grammar.
Tokens consumed as values and tokens following `--` retain their ordinary
meaning.
Reserve the four long spellings. Applications may add `-q`, `-v`, or `-d`
through the alias API; no built-in short spellings are selected. An application
flag declaration that defines a reserved long name fails installation with a
collision error. Aliases may target these flags but may not overload canonical
spellings. Apply the existing collision and atomic installation rules, including
later registration.
Aliased and canonical occurrences participate in the same ordering. With
`-q → --quiet`, `app export --verbose -q` selects quiet mode. Document the newly
reserved canonical names as a compatibility change.
### Routing and parsing failures
Determine the mode through the normal parser before execution or successful
help/report presentation. Do not add a separate verbosity scanner. This keeps
token interpretation consistent and avoids reinterpreting values or operands.
Routing and parsing failures report their errors regardless of verbosity. For
example, `app export --quiet --unknown` still reports the unknown flag. Error
visibility follows the selected output policy independently of how the mode is
determined; avoiding a separate scanner is an implementation simplification.
## CommandKit's own diagnostics
Use the shared reporting system for CommandKit's invocation diagnostics so
parser, integration, and application messages follow the same visibility and
delivery policy. Installation errors occur before an invocation exists and
continue to be returned to the application without automatic printing.
Supported repetition and last-occurrence overrides are routine decisions.
Repeated singleton flags, including `--verbose --verbose`, may produce debug
detail; repetition alone does not warrant a warning. Repeatable flags retain
their intended accumulation behavior. Add warnings for concrete concerns an
operator can act on, such as a deprecated spelling if deprecation is introduced.
Unknown flags, invalid values, and invalid command paths remain invocation
failures with error diagnostics.
Start debug instrumentation with routing, alias resolution, verbosity selection,
and handler completion. Other useful candidates can be added where they
explain a consequential decision:
| Event | Useful detail |
| --- | --- |
| Command-alias resolution | Entered path, intermediate redirects, and final canonical path. |
| Flag-alias resolution | Entered spelling and canonical flag name. |
| Scoped alias selection | A command-scoped mapping took precedence over an application-wide mapping. |
| Verbosity selection | A later occurrence selected a different mode; for `--verbose --debug`, debug wins because it appears last. |
| Help-route selection | A canonical command or alias-only discovery context was selected. |
| Repeated singleton flag | A later occurrence replaced an earlier occurrence, without printing their values. |
| Input preparation | Canonical input validation completed and the handler is starting. |
| Handler completion | Canonical command and the handler's returned classification and status, before final delivery. |
The handler-completion event describes the handler's result. The final returned
invocation outcome also includes delivery failures and remains authoritative.
Present this event before terminal failure presentation; do not emit a completion
message afterward.
Use the final selected mode to present earlier parser decisions. Collect the
relevant events during parsing and apply visibility after mode selection:
`--verbose --debug` shows the selection explanation, while `--debug --quiet`
suppresses it. This collection of parser events does not require whole-run
output buffering.
Debug messages should explain operator-relevant decisions independently of
incidental implementation steps. Use command paths, flag names, and decision
descriptions rather than raw argument or configuration-value dumps. Upstream
libraries retain ownership of their diagnostic detail and disclosure rules.
## Selected delivery lifecycle and quiet execution (OD-4)
### Ordering and finalization
Use synchronous delivery. Present immediate messages and substantive writes in
submission order. After the handler returns:
1. Deliver eligible deferred messages in queue order, without sorting by severity.
2. Finish ordinary reporting, including any handler-completion debug message and
flushing any CommandKit-owned buffers for ordinary output. Account for failures
discovered during this delivery before preparing the terminal explanation.
3. Present any terminal failure explanation and complete its delivery, including
any CommandKit-owned buffering of that explanation.
4. Close the invocation's reporting facility and return the final outcome.
Deferred messages remain eligible when the operation fails, subject to verbosity.
Deferral controls timing; applications queue success summaries only after the
relevant operation succeeds. Ordering governs CommandKit's writes; separate
stdout and stderr destinations may be buffered or displayed differently by the
caller.
CommandKit finalizes automatically. Consumers do not need a separate flush or
finish call. Handler cleanup, including Go `defer` functions, runs before the
handler returns and participates in normal reporting. Applications complete any
reporting goroutines before returning. After finalization, writes and message
submissions return a closed-reporter error and emit nothing.
Reporter operations within an invocation are safe to call concurrently.
Serialize access to reporting state and delivery so individual messages do not
interleave. Concurrent submissions have no predetermined order; deferred messages
follow the order in which they enter the queue. Multiple writes composing one
application report still require application coordination if they must remain
together. This contract covers operations through one invocation's reporter;
coordination with writes outside that reporter remains caller-owned.
Finalize any buffers owned by CommandKit. Caller-supplied writers remain
caller-owned; CommandKit does not automatically close them or invoke arbitrary
flushing interfaces.
Visibility applies when output is emitted. A verbose or debug run may show
informational detail before subsequently failing. Progress and substantive
output may likewise be partially delivered before a failure. Previously written
bytes cannot be withdrawn. Whole-run buffering solely to make failed runs
contain only error output is outside this implementation.
Keep errors understandable in every mode, including source locations and
related explanatory context. Unrelated warnings and informational messages
remain subject to the selected mode. Apply the selected retention boundary
without accumulating a message history.
### Rendering failures, write failures, and execution flow
Distinguish who invokes a renderer and whether its destination failed:
| Failure source | Responsibility and handling |
| --- | --- |
| An encoder or renderer called directly by the application | The application handles its returned error and chooses the outcome and explanation. |
| A rendering callback invoked by CommandKit | CommandKit handles its returned error as a presentation failure and reflects it in the invocation outcome. |
| A destination rejects a write | CommandKit records the delivery failure and stops further writes to that destination. |
A rendering failure may occur before any write or while the destination remains
healthy. It does not by itself establish a failed destination. CommandKit can
explain its rendering failure through a working diagnostic destination. These
responsibilities also apply when rendering into a discard destination under
quiet mode.
Failure to deliver requested output makes an otherwise successful invocation
unsuccessful. Apply this rule to substantive output, Warning, Info, Progress,
Debug, and terminal explanations. Intentional suppression requests no delivery
and is not a delivery failure.
Standard writer operations return write errors normally. Immediate reporting
methods also expose delivery errors. CommandKit records bounded delivery-failure
information so an ignored write error cannot yield a successful invocation.
Deferred delivery failures appear in the final outcome.
Apply ADR 0005's outcome rules when presentation fails. For standard outcomes,
return operational failure with status `1`, including when the original outcome
was a usage failure. Preserve the original explanation and any supplied cause;
record the presentation failure separately in `Presentation`.
Application-defined domain outcomes retain their domain classification. Preserve
an already non-zero domain status. If the domain status was `0`, change the
suggested status to `1` so presentation failure cannot yield a successful
invocation. The application entry point retains control of process exit.
| Outcome before presentation fails | Final outcome |
| --- | --- |
| Success, status `0` | Operational failure, status `1`. |
| Usage failure, status `2` | Operational failure, status `1`. |
| Operational failure, status `1` | Operational failure, status `1`. |
| Domain outcome, non-zero status | Same domain classification and status. |
| Domain outcome, status `0` | Same domain classification, status `1`. |
These rules apply to both destination-write failures and rendering failures from
callbacks invoked by CommandKit. Reporting failures remain CommandKit's own
error-handling responsibility.
Stop writing to a destination after it fails. A substantive-output failure can
receive a terminal explanation through the diagnostic destination if it still
works. If diagnostic delivery fails, return that information to the caller.
Do not redirect diagnostics into substantive output or recursively attempt to
report the reporting failure.
A failed write does not stop application code. The handler can inspect the error
and return immediately; otherwise, CommandKit records the failure and finalizes
when the handler returns. CommandKit does not use process exit or panic to
interrupt execution. Terminal failure presentation ends normal output.
### Quiet-mode rendering and suppression
Initially, run substantive report generation normally with its managed writer
discarding output in quiet mode. This preserves report generation, validation,
and serialization failures while changing presentation. For example, a report
encoder failure still fails the invocation under `--quiet`; the handler remains
responsible for handling errors returned by an encoder it calls.
Simple suppressed messages need no formatting or destination writes. For richer
report renderers, initially render into a discard destination. Rendering may be
skipped later where doing so preserves the command's operation and failure
semantics.
Treat suppression as intentional suppression, never as failed or incomplete
delivery. Do not retain suppressed content. Delivery needs only the deferred
queue, reporting lifecycle state, and bounded delivery-failure information,
alongside the temporary parser state and returned explanations described above.
## Selected consumer reporting API
Provide one reporting facility per invocation for substantive output, immediate
messages, and end-of-run diagnostics. The consumer API is chosen for its intended
long-term design; with no current consumers, preserving existing API shapes
carries no weight in this decision.
The following declarations specify the target API and are not yet implemented.
The reporter owns presentation: output visibility, progress settings, prefixes,
ordering, and delivery bookkeeping. Its views share invocation state, allowing
already-emitted messages, deferred messages, suppression, and write failures to
be coordinated in one place. Helpers may receive the reporter or a narrow
application-defined interface. Domain libraries can continue returning
diagnostic data for the handler to submit, independently of CommandKit.
Use the reporter as the common diagnostic submission path, replacing the earlier
proposal to split submission between a reporter and `Outcome.Diagnostics`.
Terminal explanations accompany returned outcomes and are delivered through the
same facility. Caller-selected destinations remain at `App.Execute`; handlers
use `Invocation.Reporter()` in place of raw invocation streams.
### Invocation reporter and structured detail
```go
func (inv Invocation) Reporter() *Reporter
type Reporter struct {
// Private invocation state.
}
func (r *Reporter) Output() io.Writer
func (r *Reporter) RenderOutput(write func(io.Writer) error) error
func (r *Reporter) Info(message string, details ...Detail) error
func (r *Reporter) Warn(message string, details ...Detail) error
func (r *Reporter) Debug(message string, details ...Detail) error
func (r *Reporter) Progress(message string, details ...Detail) error
func (r *Reporter) AtEnd() DeferredReporter
type Detail func(io.Writer) error
```
`Output()` supports ordinary writers and encoders. `RenderOutput()` coordinates
an entire rendering operation, captures its rendering error, and prevents other
reporter operations from interleaving with it. Rendering callbacks write through
their supplied writer. Each complete categorized message, including its details,
is likewise coordinated as one reporter operation.
Rendering callbacks use their supplied writer only during the callback. They may
call rendering helpers that write through it. While a callback is running, it
must not recursively submit messages, queue deferred messages, start another
rendering operation, or write through a separate `Output()` handle belonging to
the same invocation's reporter. Make additional reporter submissions before or
after the callback. A callback must also avoid waiting for another goroutine to
submit through that reporter, since the submission may be waiting for the
callback to finish.
This boundary applies to `RenderOutput`, immediate and deferred message details,
and terminal explanation details. Ordinary concurrent reporter calls remain
supported and serialized. Keeping each rendering operation together motivates
the boundary; it does not prescribe a lock implementation or promise runtime
detection of recursive calls.
Message strings are literal; consumers use `fmt.Sprintf` when formatting is
needed. Initially omit parallel `Infof`, `Warnf`, and similar methods. CommandKit
formats the opening message with its category's prefix and a terminating newline.
Optional details follow in order with their formatting preserved. An empty
opening message produces no heading, prefix, or blank opening line, supporting
native renderers that supply a complete, labelled diagnostic:
```go
_ = report.Warn("Using the default profile")
_ = report.Warn("Some configuration settings need attention.", writeNativeWarnings)
_ = report.Warn("", writeNativeWarnings)
```
These are alternative calls; `writeNativeWarnings` represents an
application- or integration-supplied function with signature
`func(io.Writer) error`. No generic logging method or severity enumeration is
needed to submit messages. Applications need not check verbosity before reporting
or implement categories they do not use.
Immediate methods return rendering or delivery errors, and CommandKit records
the corresponding presentation failure even if the caller ignores the error.
A caller can inspect the returned error and end its handler immediately.
### Deferred messages
```go
type DeferredReporter struct {
// Private reference to the same invocation state.
}
func (r DeferredReporter) Info(message string, details ...Detail) error
func (r DeferredReporter) Warn(message string, details ...Detail) error
func (r DeferredReporter) Debug(message string, details ...Detail) error
```
For example:
```go
_ = report.AtEnd().Warn("Three optional files were unavailable.")
```
Copies of the deferred view share invocation state. Its methods return submission
errors, such as attempting to use a closed reporter. Errors encountered during
deferred rendering appear in the final invocation outcome. Progress remains an
immediate streaming operation; substantive output uses the main reporter.
Copy callback lists when accepting a submission. Callers retain ownership of
data captured by rendering callbacks and keep that data valid until presentation.
### Terminal outcomes
Outcome construction requires no invocation state and emits nothing:
```go
type Explanation struct {
Message string
Details []Detail
}
type Outcome struct {
Kind OutcomeKind
Status int
Domain string
Cause error
Explanation Explanation
Presentation PresentationResult
}
func Success() Outcome
func Failure(message string, details ...Detail) Outcome
func Usage(message string, details ...Detail) Outcome
func Domain(name string, status int) Outcome
func (o Outcome) WithExplanation(message string, details ...Detail) Outcome
func (o Outcome) WithCause(cause error) Outcome
```
`Success` returns a successful outcome with status `0`. `Failure` produces an
operational failure with status `1`; `Usage` produces a usage failure with status
`2`. `Domain` constructs an outcome with the supplied application-defined
classification and status. Subsequent presentation failures follow OD-4's rules:
domain classification is preserved, and a zero status becomes `1` if presentation
fails.
`OutcomeKind` retains the success, usage, operational, and domain classifications.
`WithExplanation` returns a modified outcome value and replaces its terminal
explanation. Explanations belong to failed outcomes; successful summaries use
Info or substantive output. Ordinary application failure, native failure
rendering, and a custom domain failure respectively can be expressed as:
```go
return commandkit.Failure("Unable to export the requested report.")
```
```go
return commandkit.Failure("", writeNativeFailure)
```
```go
return commandkit.Domain("validation", 3).
WithExplanation("The document failed validation.", writeFindings)
```
The named renderers above have signature `func(io.Writer) error` and preserve the
owning library's safe diagnostic formatting. They run during terminal delivery,
not when constructing the outcome.
Before terminal delivery, supply the explanation `Command failed.` when a
non-zero outcome has an empty `Explanation.Message` and no non-nil callback in
`Explanation.Details`. This produces `ERROR: Command failed.` in every mode,
including quiet, and becomes the explanation retained in the returned outcome.
Adding the fallback leaves classification, status, and cause unchanged;
presentation failures still follow OD-4's rules. The fallback is based on the
failed outcome and absent explanation, without deriving text from `Cause.Error()`.
An empty heading with a non-nil detail renderer is an explicitly supplied
explanation. Trust that renderer to provide its content. Do not buffer or replay
it to decide whether the explanation is sufficiently informative, and do not
add the fallback merely because it writes no bytes.
| Returned outcome | Terminal presentation |
| --- | --- |
| `Failure("")` | Generic fallback, operational classification and status `1`. |
| `Domain("validation", 3)` | Generic fallback, domain classification and status `3`. |
| `Failure("").WithCause(err)` | Generic fallback; the supplied cause remains available without automatic rendering. |
| `Failure("", writeNativeFailure)` | Native explanation without an added generic heading. |
`Cause` is optional. `WithCause` returns a modified outcome value, replacing the
cause without changing the classification, status, or explanation. For example:
```go
return commandkit.Failure("Unable to open the configuration file.").
WithCause(err)
```
CommandKit presents the supplied explanation and carries the original error
through to the execution caller, which can inspect it with expressions such as
`errors.Is(outcome.Cause, fs.ErrNotExist)`. It does not automatically present
`Cause.Error()` or use the cause to decide success, failure, or message category.
Providing a cause is independent of choosing the terminal explanation; neither
is inferred from the other. Warnings do not require supplying or retaining causes.
Outcome processing preserves supplied causes, including their existing Go error
identity, when a subsequent rendering or delivery failure occurs. Presentation
failures are recorded separately in `Presentation`. The returned outcome retains
its terminal explanation and optional cause, with other retention limited to the
presentation needs described above.
### Provider-returned diagnostic data
Providers return values and diagnostic data without needing a reporter parameter.
Retain `Acquired[T]` with separate fields for independent messages and failure
explanations:
```go
type Acquired[T any] struct {
Value T
Diagnostics []Diagnostic
Explanation Explanation
}
```
`Diagnostics` carries independent, nonterminal messages. `Diagnostic` and
`Severity` remain passive data types for those messages, with each diagnostic
carrying its `Severity` and a `Write func(io.Writer) error` renderer. Adapt their
contracts to the nonterminal reporting categories. Integrations submit the
records through the corresponding reporter methods, including the deferred view
where appropriate. Removing `Outcome.Diagnostics` removes a submission path;
provider-returned records remain available for the integration to submit.
`Explanation` carries context to attach when the integration returns a failed
outcome. Terminal Error content uses this field rather than an independently
submitted diagnostic. An upstream warning that helps explain the failure may
belong in the explanation; unrelated warnings remain in `Diagnostics` and follow
their ordinary visibility rules. Adapters preserve this distinction and useful
native formatting when translating mixed upstream batches, instead of assigning
the whole batch its highest severity.
Providers may return acquired data alongside a Go error. The owning integration
chooses the command outcome, attaches any terminal explanation, and decides which
cause to preserve. Returning diagnostic data does not itself emit messages or
select the invocation outcome. Diagnostic renderers follow the same callback
boundary as other details when invoked through the reporter.
### Presentation observations and closed reporters
```go
type PresentationResult struct {
Output DeliveryResult
Diagnostics DeliveryResult
}
type DeliveryResult struct {
State DeliveryState
RenderError error
WriteError error
}
type DeliveryState uint8
const (
DeliveryNone DeliveryState = iota
DeliverySuppressed
DeliveryComplete
DeliveryIncomplete
)
var ErrReporterClosed = errors.New("reporter is closed")
```
| State | Meaning |
| --- | --- |
| `DeliveryNone` | No content was submitted for this destination. |
| `DeliverySuppressed` | All submitted content was intentionally suppressed, and rendering succeeded. |
| `DeliveryComplete` | All requested delivery completed; other content may have been suppressed. |
| `DeliveryIncomplete` | Rendering or destination writing failed. |
Retain the first rendering failure and first destination-write failure for each
destination. This provides bounded evidence without collecting an event history.
`Outcome.Presentation` is populated by CommandKit during execution and
finalization; it is observation data, not another submission API.
The invocation supplies the reporter. Consumers neither construct nor finalize
it. After closure, message submissions and writer operations return
`ErrReporterClosed`, including in quiet mode. The initial API needs no explicit
flush method, transcript accessor, or verbosity checks. Error-conversion helpers
are deferred pending demonstrated value.
### Application example
This target-API handler uses an application-owned `exportData` operation that
returns a JSON-encodable result with a `UsedDefaults` field:
```go
func runExport(inv commandkit.Invocation) commandkit.Outcome {
report := inv.Reporter()
result, err := exportData(inv.Context)
if err != nil {
return commandkit.Failure("Unable to export the requested data.")
}
if result.UsedDefaults {
_ = report.Warn("Some optional settings used defaults.")
}
if err := report.RenderOutput(func(w io.Writer) error {
return json.NewEncoder(w).Encode(result)
}); err != nil {
return commandkit.Failure("Unable to present the export result.")
}
_ = report.AtEnd().Info("Export completed.")
return commandkit.Success()
}
```
Ignored immediate reporting errors are still recorded and can make the final
invocation unsuccessful. The renderer runs in quiet mode against the discard
destination, preserving serialization failures. The deferred summary follows
the selected verbosity policy and describes the completed export operation;
the final invocation outcome also accounts for presentation failures.
## Upstream diagnostic ownership
ConfigKit and PromptKit remain authoritative for their diagnostic semantics,
severity, source context, and disclosure rules. Integration adapters expose
those capabilities through the shared CommandKit presentation policy.
Support consistent reporting of ConfigKit errors and warnings as its adopted
public API evolves. This roadmap does not assume that a future warning API
already exists or prescribe its upstream shape. Integration-owned commands
select the outcome and submit useful native diagnostic detail for presentation.
Core presents those records under the shared policy. Applications using upstream
libraries directly choose how to respond to domain-specific errors and which
outcomes and messages to supply, as for their other operations.
An integration may receive both a useful substantive report and an operation
failure, as PromptKit smoke testing supports. Preserve the report under the
ordinary substantive-output policy, then present the terminal explanation.
Quiet mode suppresses the report while retaining the explanation. Having a
report does not imply a successful outcome, and returning a failure does not
discard substantive output already prepared for delivery before the terminal step.
Debug output follows the same upstream disclosure and safe-rendering contracts.
Enabling debug does not authorize secret disclosure or bypass owning-library
rules.
## Delivery scope
The completed feature includes the selected reporter and outcome API, ordered
mode/progress selection through normal parsing, shared core presentation, and
both optional integration migrations. Passive provider diagnostics distinguish
independent messages from terminal explanations while preserving native evidence
and rendering. Existing command behavior remains unchanged outside the selected
reporting policy.
Maintained consumers demonstrate ordinary output, immediate/deferred messages,
silent recovery, explicit warnings, failure after partial output, optional cause
transport, and structured terminal explanations. Integration consumers include
native diagnostic context and useful reports returned alongside failures.
Behavioral coverage establishes CommandKit-owned parsing, visibility, ordering,
concurrent reporter coordination, closure, presentation observations, and failure
handling. It preserves existing alias, input/state, discovery, native-report,
and upstream-adapter protections without testing upstream domain correctness.
GoDoc, CLI documentation, consumer guidance, internal documentation, and release
notes describe the implemented boundary under their canonical ownership.
The [implementation plan](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/230187296fae5253cb1773f16c2f1d1a39499ed0/docs/roadmap/implementation.md) defines the concrete migration
steps, focused validation, and completion criteria. This roadmap defines the
target behavior and selected policy choices.
## Architectural preparation completed
- [x] Review and accept [ADR 0014](../adr/0014-invocation-reporting.md) as an
extension for shared reporting, retaining ADR 0005's outcome and supplied-error
preservation decisions.
- [x] Align the [architecture policy](../policy/architecture.md) with the reporting
ownership model, including application ownership of domain-specific error
decisions and scope for useful shared error helpers.
OD-1 through OD-4 and the consumer API signatures are selected. The target end
state includes maintained, executable consumers using those APIs; the
[implementation plan](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/230187296fae5253cb1773f16c2f1d1a39499ed0/docs/roadmap/implementation.md) owns their delivery sequence.

View File

@@ -26,8 +26,7 @@ and try completing `core-example report d` or `core-example ws gr`.
Compatible integration factories also return `commandkit.Command` and can be Compatible integration factories also return `commandkit.Command` and can be
passed directly to `New` beside `commandkit.Alias` or flag-alias declarations. passed directly to `New` beside `commandkit.Alias` or flag-alias declarations.
The ckconfig candidate uses the new core identity; ckprompt will use it in its The matched ckconfig and ckprompt releases use the new core identity. For a
planned matched release. For a
command-only `[]commandkit.Command`, convert its elements into a command-only `[]commandkit.Command`, convert its elements into a
`[]commandkit.Declaration` before appending routing rules; Go cannot expand the `[]commandkit.Declaration` before appending routing rules; Go cannot expand the
command slice as `...commandkit.Declaration`. The command slice as `...commandkit.Declaration`. The

View File

@@ -7,9 +7,9 @@ itself.
## Module ## Module
The module path is `go.maximumdirect.net/ckconfig`. Version v0.2.0 uses The module path is `go.maximumdirect.net/ckconfig`. The prepared v0.3.0
`go.maximumdirect.net/commandkit v0.3.0` and candidate requires Go 1.27.0 and uses `go.maximumdirect.net/commandkit v0.3.0` and
ConfigKit; it does not import PromptKit. See the `go.maximumdirect.net/configkit v1.1.0`; it does not import PromptKit. See the
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes) [consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
for exact callback and lifetime contracts. for exact callback and lifetime contracts.
@@ -26,9 +26,9 @@ scopes, selectors, input checks, and state shared by the selected acquisitions
or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed
ConfigKit loader. The `config` command family exposes scope discovery and the ConfigKit loader. The `config` command family exposes scope discovery and the
validate, show, sources, explain, and diff operations supported by the declared validate, show, sources, explain, and diff operations supported by the declared
scopes. Source reports include native destination, placement, unresolved scopes. Source reports include native destination, placement, destination
destination, and source version-check evidence. Comparison returns ConfigKit's fallback, version evidence, and empty-import selections. Comparison returns
native records to the YAML report path; the ConfigKit's native records to the YAML report path; the
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections) [CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections)
owns its operator details. owns its operator details.

View File

@@ -10,8 +10,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
type adapterSettings struct { type adapterSettings struct {
@@ -27,7 +27,7 @@ func adapterDefinition() configkit.Definition[adapterSettings] {
validation.Warning(configkit.Keys("greeting"), "using the default greeting") validation.Warning(configkit.Keys("greeting"), "using the default greeting")
} }
}, },
Secret: func(path configkit.Path) bool { return path.String() == "/secret" }, Sensitive: func(path configkit.Path) bool { return path.String() == "/secret" },
} }
} }
@@ -97,7 +97,7 @@ func TestFromConfigKitCompareIgnoresDefaultAndResolutionHistoryForEqualValues(t
Resolve: func(value *resolvedSettings, resolution *configkit.Resolution) error { Resolve: func(value *resolvedSettings, resolution *configkit.Resolution) error {
if value.Greeting != "resolved" { if value.Greeting != "resolved" {
value.Greeting = "resolved" value.Greeting = "resolved"
resolution.Record(configkit.Keys("greeting"), configkit.ChangeNormalization, "canonical greeting") resolution.RecordNormalization(configkit.Keys("greeting"), "canonical greeting")
} }
return nil return nil
}, },

View File

@@ -7,8 +7,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
func TestComparisonCapabilitiesAreIndependentAndCaptured(t *testing.T) { func TestComparisonCapabilitiesAreIndependentAndCaptured(t *testing.T) {

View File

@@ -6,8 +6,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
func TestComparisonSelectionInheritsFieldsIndependently(t *testing.T) { func TestComparisonSelectionInheritsFieldsIndependently(t *testing.T) {

View File

@@ -8,8 +8,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
func TestComparisonPreparesEqualSelectionsWithSeparateTypedInputs(t *testing.T) { func TestComparisonPreparesEqualSelectionsWithSeparateTypedInputs(t *testing.T) {

View File

@@ -7,8 +7,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
func TestCompletionUsesInstalledScopeCapabilitiesWithoutAcquisition(t *testing.T) { func TestCompletionUsesInstalledScopeCapabilitiesWithoutAcquisition(t *testing.T) {

View File

@@ -7,8 +7,8 @@ import (
"io" "io"
"strconv" "strconv"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
// FromConfigKit adapts a typed ConfigKit loader to all five native // FromConfigKit adapts a typed ConfigKit loader to all five native

View File

@@ -4,8 +4,8 @@ import (
"context" "context"
"io" "io"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
// Selection carries the configuration and overlay choices supplied for a // Selection carries the configuration and overlay choices supplied for a

View File

@@ -9,8 +9,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
func TestWithScopeErrorCopiesAndRetainsCauses(t *testing.T) { func TestWithScopeErrorCopiesAndRetainsCauses(t *testing.T) {

View File

@@ -9,8 +9,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )
@@ -273,7 +273,7 @@ func TestConfigDiffExecutesConcealedChangesAndEmptyResults(t *testing.T) {
if selection.Config.Set && selection.Config.Value == "after" { if selection.Config.Set && selection.Config.Value == "after" {
value = "changed-secret" value = "changed-secret"
} }
return configkit.Load(configkit.Mapping("selected", map[string]any{"secret": value}), configkit.Options[settings]{Definition: configkit.Definition[settings]{Secret: func(path configkit.Path) bool { return path.String() == "/secret" }}}) return configkit.Load(configkit.Mapping("selected", map[string]any{"secret": value}), configkit.Options[settings]{Definition: configkit.Definition[settings]{Sensitive: func(path configkit.Path) bool { return path.String() == "/secret" }}})
})) }))
var output bytes.Buffer var output bytes.Buffer
outcome := app.Execute(context.Background(), []string{"config", "diff", "--config", "before", "--against-config", "after"}, commandkit.Streams{Out: &output, Err: io.Discard}) outcome := app.Execute(context.Background(), []string{"config", "diff", "--config", "before", "--against-config", "after"}, commandkit.Streams{Out: &output, Err: io.Discard})

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "go.maximumdirect.net/configkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -6,7 +6,7 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "go.maximumdirect.net/configkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )
@@ -119,7 +119,7 @@ func TestRenderDiffReportPreservesNativeMasksAndMarkerLookingStrings(t *testing.
Public string `yaml:"public"` Public string `yaml:"public"`
Secret string `yaml:"secret"` Secret string `yaml:"secret"`
} }
definition := configkit.Definition[settings]{Secret: func(path configkit.Path) bool { return path.String() == "/secret" }} definition := configkit.Definition[settings]{Sensitive: func(path configkit.Path) bool { return path.String() == "/secret" }}
load := func(public, secret string) *configkit.Result[settings] { load := func(public, secret string) *configkit.Result[settings] {
result, err := configkit.Load(configkit.Mapping("configuration", map[string]any{"public": public, "secret": secret}), configkit.Options[settings]{Definition: definition}) result, err := configkit.Load(configkit.Mapping("configuration", map[string]any{"public": public, "secret": secret}), configkit.Options[settings]{Definition: definition})
if err != nil { if err != nil {

View File

@@ -1,10 +1,10 @@
// Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides // Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides
// CommandKit's optional ConfigKit integration. Its // CommandKit's optional ConfigKit v1.1.0 integration, requiring Go 1.27.0. Its
// canonical Command declaration installs the standard config command family // canonical Command declaration installs the standard config command family
// through the core commandkit package. Applications can install CommandKit // through the core commandkit package. Applications can install CommandKit
// RoutingRule declarations alongside it through commandkit.New or // RoutingRule declarations alongside it through commandkit.New or
// App.Register. Source reports preserve ConfigKit's destination, placement, // App.Register. Source reports preserve ConfigKit's destination, placement,
// and version-check evidence. Invocation reporting applies CommandKit's shared // version, and empty-import evidence. Invocation reporting applies CommandKit's shared
// visibility and delivery policy; provider warnings remain independent of // visibility and delivery policy; provider warnings remain independent of
// failure explanations. Importing ckconfig alone installs no commands. // failure explanations. Importing ckconfig alone installs no commands.
package ckconfig package ckconfig

View File

@@ -2,16 +2,16 @@
## ConfigKit ## ConfigKit
Selected module: `gitea.maximumdirect.net/eric/ConfigKit` at `v0.8.0`. Selected module: `go.maximumdirect.net/configkit` at `v1.1.0`.
Copyright (C) 2026 Eric Rakestraw Copyright (C) 2026 Eric Rakestraw
SPDX-License-Identifier: LGPL-3.0-or-later SPDX-License-Identifier: LGPL-3.0-or-later
License and notices: [LGPL v3.0](../../LICENSE) | License and notices: [LGPL v3.0](../../LICENSE) |
[LICENSE](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/LICENSE). [LICENSE](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/LICENSE).
[Source](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5). [Source](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9).
## go-yaml v4 ## go-yaml v4
@@ -153,19 +153,6 @@ License and notices: [MIT](licenses/MIT.txt) |
## ReleaseKit ## ReleaseKit
Selected module: `gitea.maximumdirect.net/eric/ReleaseKit` at `v0.4.1` (transitive Go tool requirement; not a runtime import).
Copyright (C) 2026 Eric Rakestraw
SPDX-License-Identifier: LGPL-3.0-or-later
License and notices: [LGPL v3.0](../../LICENSE) |
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469/LICENSE).
[Source](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469).
## ReleaseKit (vanity module)
Selected module: `go.maximumdirect.net/releasekit` at `v0.9.0` (transitive Go tool requirement; not a runtime import). Selected module: `go.maximumdirect.net/releasekit` at `v0.9.0` (transitive Go tool requirement; not a runtime import).
Copyright (C) 2026 Eric Rakestraw Copyright (C) 2026 Eric Rakestraw

View File

@@ -0,0 +1,25 @@
# CommandKit ckconfig v0.3.0
## Summary
This candidate adopts `go.maximumdirect.net/configkit v1.1.0` and requires Go
1.27.0, while retaining `go.maximumdirect.net/commandkit v0.3.0`. It updates
configuration source reports to expose ConfigKit's current evidence.
## Migration
Change ConfigKit imports from `gitea.maximumdirect.net/eric/ConfigKit` to
`go.maximumdirect.net/configkit`. Values from the two paths have distinct Go
type identities. Update application loaders and provider values together with
ckconfig. Published ckprompt v0.2.0 continues to use ckconfig v0.2.0 and the old
ConfigKit identity; it does not compose with this candidate.
Source reports rename `destination_unresolved` to `destination_is_fallback` and
`version_check` to `version_evidence`, use the native `main` layer name, and add
`empty_import_selections` records (or `[]` when empty). Update report consumers.
See the [consumer migration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/docs/consumers/guide.md#configkit-v11-migration)
for links to upstream configuration and API changes.
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/integrations/ckconfig/COPYRIGHT) |
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/integrations/ckconfig/LICENSE) |
[ATTRIBUTION](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/integrations/ckconfig/docs/oss/attribution.md)

View File

@@ -1,7 +1,9 @@
# Simple consumer # Simple consumer
This example imports `go.maximumdirect.net/ckconfig` and This example imports `go.maximumdirect.net/ckconfig` and
`go.maximumdirect.net/commandkit`; use ckconfig v0.2.0 with core v0.3.0. `go.maximumdirect.net/commandkit`; use the ckconfig v0.3.0 candidate with core
v0.3.0, ConfigKit v1.1.0, and Go 1.27.0. Set `GOWORK=off GOTOOLCHAIN=local`
for the commands below.
Run the maintained example with: Run the maintained example with:

View File

@@ -7,9 +7,9 @@ import (
"os" "os"
"strconv" "strconv"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
"go.maximumdirect.net/ckconfig" "go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
type appConfiguration struct { type appConfiguration struct {

View File

@@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"io" "io"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
type explanationReport struct { type explanationReport struct {

View File

@@ -9,8 +9,8 @@ import (
"sort" "sort"
"strings" "strings"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
type scopeMetadata struct { type scopeMetadata struct {

View File

@@ -9,8 +9,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
func TestScopeDiscoveryIsOrderedAndDoesNotUseSuiteFactories(t *testing.T) { func TestScopeDiscoveryIsOrderedAndDoesNotUseSuiteFactories(t *testing.T) {
@@ -441,6 +441,7 @@ func TestExplainParsesBeforeAcquisitionAndPreservesNativeSafeHistory(t *testing.
value: configkit.Explanation{ value: configkit.Explanation{
Path: configkit.Path{}, Path: configkit.Path{},
Effective: configkit.ValueSnapshot{Present: true, Redacted: true}, Effective: configkit.ValueSnapshot{Present: true, Redacted: true},
Origin: configkit.Origin{Layer: configkit.LayerMain},
History: []configkit.ValueChange{{ History: []configkit.ValueChange{{
Before: configkit.ValueSnapshot{Present: true, Redacted: true}, Before: configkit.ValueSnapshot{Present: true, Redacted: true},
After: configkit.ValueSnapshot{Present: true, Redacted: true}, After: configkit.ValueSnapshot{Present: true, Redacted: true},
@@ -460,7 +461,7 @@ func TestExplainParsesBeforeAcquisitionAndPreservesNativeSafeHistory(t *testing.
if outcome.Kind != commandkit.OutcomeSuccess || acquireCalls != 1 || reader.path.String() != "" { if outcome.Kind != commandkit.OutcomeSuccess || acquireCalls != 1 || reader.path.String() != "" {
t.Fatalf("root explanation outcome=%#v calls=%d path=%q", outcome, acquireCalls, reader.path.String()) t.Fatalf("root explanation outcome=%#v calls=%d path=%q", outcome, acquireCalls, reader.path.String())
} }
if strings.Contains(output.String(), "APP_TOKEN_VALUE") || !strings.Contains(output.String(), "redacted: true") || !strings.Contains(output.String(), "history:") || !strings.Contains(output.String(), "dependencies: []") || !strings.Contains(output.String(), "name: APP_TOKEN") { if strings.Contains(output.String(), "APP_TOKEN_VALUE") || !strings.Contains(output.String(), "redacted: true") || !strings.Contains(output.String(), "layer: main") || !strings.Contains(output.String(), "history:") || !strings.Contains(output.String(), "dependencies: []") || !strings.Contains(output.String(), "name: APP_TOKEN") {
t.Fatalf("safe explanation report = %s", output.String()) t.Fatalf("safe explanation report = %s", output.String())
} }

View File

@@ -1,9 +1,10 @@
module go.maximumdirect.net/ckconfig module go.maximumdirect.net/ckconfig
go 1.26.0 go 1.27.0
require ( require (
gitea.maximumdirect.net/eric/ConfigKit v0.8.0 go.maximumdirect.net/commandkit v0.3.0
go.maximumdirect.net/configkit v1.1.0
go.yaml.in/yaml/v4 v4.0.0-rc.6 go.yaml.in/yaml/v4 v4.0.0-rc.6
) )
@@ -11,5 +12,4 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/cobra v1.10.1 // indirect
github.com/spf13/pflag v1.0.9 // indirect github.com/spf13/pflag v1.0.9 // indirect
go.maximumdirect.net/commandkit v0.3.0
) )

View File

@@ -1,5 +1,3 @@
gitea.maximumdirect.net/eric/ConfigKit v0.8.0 h1:xCIhYnOHjw7rFvB+vIremPKGeROOxKTomnUEUipuQno=
gitea.maximumdirect.net/eric/ConfigKit v0.8.0/go.mod h1:C82sbyKHYMV1OwaD2GJanFrwTfcZfjlW2JsGze5b0kA=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
@@ -10,6 +8,8 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
go.maximumdirect.net/commandkit v0.3.0 h1:RCmg2GS8uzlLSJCIqarpn1uFDec0W3ylNNRRPT6kUFE= go.maximumdirect.net/commandkit v0.3.0 h1:RCmg2GS8uzlLSJCIqarpn1uFDec0W3ylNNRRPT6kUFE=
go.maximumdirect.net/commandkit v0.3.0/go.mod h1:ZS98DewKNVBygKVDoh5MFD09CnPlP37dS9pVsID5Eoc= go.maximumdirect.net/commandkit v0.3.0/go.mod h1:ZS98DewKNVBygKVDoh5MFD09CnPlP37dS9pVsID5Eoc=
go.maximumdirect.net/configkit v1.1.0 h1:UzXN2ZMnEkcL0O4YSLqD9qd9M1gb/NWCHQR/H8AaQzA=
go.maximumdirect.net/configkit v1.1.0/go.mod h1:s1zLJ9GGB/1Q4a+aOHMLISonJxWFgNWpA6SpPlOafeA=
go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
) )
type configCommandInput[I, S any] struct { type configCommandInput[I, S any] struct {

View File

@@ -6,8 +6,8 @@ import (
"io" "io"
"strconv" "strconv"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )
@@ -22,12 +22,19 @@ type sourceDTO struct {
Path string `yaml:"path"` Path string `yaml:"path"`
Destination string `yaml:"destination"` Destination string `yaml:"destination"`
Placement string `yaml:"placement"` Placement string `yaml:"placement"`
DestinationUnresolved bool `yaml:"destination_unresolved"` DestinationIsFallback bool `yaml:"destination_is_fallback"`
Layer string `yaml:"layer"` Layer string `yaml:"layer"`
Kind string `yaml:"kind"` Kind string `yaml:"kind"`
UnderlayIndex int `yaml:"underlay_index"` UnderlayIndex int `yaml:"underlay_index"`
ImportedFrom *locationDTO `yaml:"imported_from"` ImportedFrom *locationDTO `yaml:"imported_from"`
VersionCheck *sourceVersionCheckDTO `yaml:"version_check"` VersionEvidence *sourceVersionEvidenceDTO `yaml:"version_evidence"`
EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"`
}
type emptyImportSelectionDTO struct {
Path string `yaml:"path"`
Location locationDTO `yaml:"location"`
Selector string `yaml:"selector"`
} }
type locationDTO struct { type locationDTO struct {
@@ -36,7 +43,7 @@ type locationDTO struct {
Column int `yaml:"column"` Column int `yaml:"column"`
} }
type sourceVersionCheckDTO struct { type sourceVersionEvidenceDTO struct {
Path string `yaml:"path"` Path string `yaml:"path"`
Version versionDTO `yaml:"version"` Version versionDTO `yaml:"version"`
Location *locationDTO `yaml:"location"` Location *locationDTO `yaml:"location"`
@@ -89,17 +96,18 @@ func runConfigSources[I, S any](invocation commandkit.Invocation, plan *configOp
Path: source.Path, Path: source.Path,
Destination: source.Destination.String(), Destination: source.Destination.String(),
Placement: placement, Placement: placement,
DestinationUnresolved: source.DestinationUnresolved, DestinationIsFallback: source.DestinationIsFallback,
Layer: string(source.Layer), Layer: string(source.Layer),
Kind: string(source.Kind), Kind: string(source.Kind),
UnderlayIndex: source.UnderlayIndex, UnderlayIndex: source.UnderlayIndex,
EmptyImportSelections: make([]emptyImportSelectionDTO, 0, len(source.EmptyImportSelections)),
} }
if source.ImportedFrom != nil { if source.ImportedFrom != nil {
item.ImportedFrom = &locationDTO{SourceID: source.ImportedFrom.SourceID, Line: source.ImportedFrom.Line, Column: source.ImportedFrom.Column} item.ImportedFrom = &locationDTO{SourceID: source.ImportedFrom.SourceID, Line: source.ImportedFrom.Line, Column: source.ImportedFrom.Column}
} }
if source.VersionCheck != nil { if source.VersionEvidence != nil {
check := source.VersionCheck check := source.VersionEvidence
item.VersionCheck = &sourceVersionCheckDTO{ item.VersionEvidence = &sourceVersionEvidenceDTO{
Path: check.Path.String(), Path: check.Path.String(),
Version: versionDTO{ Version: versionDTO{
Present: check.Version.Present, Present: check.Version.Present,
@@ -109,9 +117,12 @@ func runConfigSources[I, S any](invocation commandkit.Invocation, plan *configOp
Redacted: check.Redacted, Redacted: check.Redacted,
} }
if check.Location != nil { if check.Location != nil {
item.VersionCheck.Location = &locationDTO{SourceID: check.Location.SourceID, Line: check.Location.Line, Column: check.Location.Column} item.VersionEvidence.Location = &locationDTO{SourceID: check.Location.SourceID, Line: check.Location.Line, Column: check.Location.Column}
} }
} }
for _, selection := range source.EmptyImportSelections {
item.EmptyImportSelections = append(item.EmptyImportSelections, emptyImportSelectionDTO{Path: selection.Path.String(), Location: locationDTO{SourceID: selection.Location.SourceID, Line: selection.Location.Line, Column: selection.Location.Column}, Selector: string(selection.Selector)})
}
document.Sources = append(document.Sources, item) document.Sources = append(document.Sources, item)
} }
if err := invocation.Context.Err(); err != nil { if err := invocation.Context.Err(); err != nil {
@@ -143,7 +154,7 @@ func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
_, _ = fmt.Fprintf(writer, " path: %s\n", strconv.Quote(source.Path)) _, _ = fmt.Fprintf(writer, " path: %s\n", strconv.Quote(source.Path))
_, _ = fmt.Fprintf(writer, " destination: %s\n", strconv.Quote(source.Destination)) _, _ = fmt.Fprintf(writer, " destination: %s\n", strconv.Quote(source.Destination))
_, _ = fmt.Fprintf(writer, " placement: %s\n", strconv.Quote(source.Placement)) _, _ = fmt.Fprintf(writer, " placement: %s\n", strconv.Quote(source.Placement))
_, _ = fmt.Fprintf(writer, " destination_unresolved: %t\n", source.DestinationUnresolved) _, _ = fmt.Fprintf(writer, " destination_is_fallback: %t\n", source.DestinationIsFallback)
_, _ = fmt.Fprintf(writer, " layer: %s\n", strconv.Quote(source.Layer)) _, _ = fmt.Fprintf(writer, " layer: %s\n", strconv.Quote(source.Layer))
_, _ = fmt.Fprintf(writer, " kind: %s\n", strconv.Quote(source.Kind)) _, _ = fmt.Fprintf(writer, " kind: %s\n", strconv.Quote(source.Kind))
_, _ = fmt.Fprintf(writer, " underlay_index: %d\n", source.UnderlayIndex) _, _ = fmt.Fprintf(writer, " underlay_index: %d\n", source.UnderlayIndex)
@@ -153,12 +164,11 @@ func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
_, _ = fmt.Fprintf(writer, " imported_from: {source_id: %s, line: %d, column: %d}\n", _, _ = fmt.Fprintf(writer, " imported_from: {source_id: %s, line: %d, column: %d}\n",
strconv.Quote(source.ImportedFrom.SourceID), source.ImportedFrom.Line, source.ImportedFrom.Column) strconv.Quote(source.ImportedFrom.SourceID), source.ImportedFrom.Line, source.ImportedFrom.Column)
} }
if source.VersionCheck == nil { if source.VersionEvidence == nil {
_, _ = writer.WriteString(" version_check: null\n") _, _ = writer.WriteString(" version_evidence: null\n")
continue } else {
} check := source.VersionEvidence
check := source.VersionCheck _, _ = fmt.Fprintf(writer, " version_evidence:\n path: %s\n", strconv.Quote(check.Path))
_, _ = fmt.Fprintf(writer, " version_check:\n path: %s\n", strconv.Quote(check.Path))
_, _ = fmt.Fprintf(writer, " version:\n present: %t\n null: %t\n text: %s\n", _, _ = fmt.Fprintf(writer, " version:\n present: %t\n null: %t\n text: %s\n",
check.Version.Present, check.Version.Null, strconv.Quote(check.Version.Text)) check.Version.Present, check.Version.Null, strconv.Quote(check.Version.Text))
if check.Location == nil { if check.Location == nil {
@@ -169,6 +179,15 @@ func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
} }
_, _ = fmt.Fprintf(writer, " redacted: %t\n", check.Redacted) _, _ = fmt.Fprintf(writer, " redacted: %t\n", check.Redacted)
} }
if len(source.EmptyImportSelections) == 0 {
_, _ = writer.WriteString(" empty_import_selections: []\n")
} else {
_, _ = writer.WriteString(" empty_import_selections:\n")
for _, selection := range source.EmptyImportSelections {
_, _ = fmt.Fprintf(writer, " - path: %s\n location: {source_id: %s, line: %d, column: %d}\n selector: %s\n", strconv.Quote(selection.Path), strconv.Quote(selection.Location.SourceID), selection.Location.Line, selection.Location.Column, strconv.Quote(selection.Selector))
}
}
}
} }
func encodeYAML(writer io.Writer, document any) error { func encodeYAML(writer io.Writer, document any) error {

View File

@@ -8,8 +8,8 @@ import (
"strings" "strings"
"testing" "testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
configkit "go.maximumdirect.net/configkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )
@@ -34,13 +34,17 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
reader := &sourceInventory{values: []configkit.SourceInfo{ reader := &sourceInventory{values: []configkit.SourceInfo{
{ {
ID: "root", Label: "root source", Path: "root.yml", ID: "root", Label: "root source", Path: "root.yml",
PlacementMode: configkit.PlacementModeMapping, PlacementMode: configkit.PlacementModeMapping, Layer: configkit.LayerMain,
EmptyImportSelections: []configkit.EmptyImportSelection{
{Path: configkit.Keys("imports", "first"), Location: configkit.Location{SourceID: "root.yml", Line: 3, Column: 4}, Selector: configkit.ImportSelectorGlob},
{Path: configkit.Keys("imports", "second"), Location: configkit.Location{}, Selector: configkit.ImportSelectorPath},
},
}, },
{ {
ID: "item", Label: "sequence item", Path: "item.yml", ID: "item", Label: "sequence item", Path: "item.yml",
Destination: servicePath, PlacementMode: configkit.PlacementModeSequenceItem, Destination: servicePath, PlacementMode: configkit.PlacementModeSequenceItem,
DestinationUnresolved: true, DestinationIsFallback: true,
VersionCheck: &configkit.SourceVersionCheck{ VersionEvidence: &configkit.SourceVersionEvidence{
Path: versionPath, Path: versionPath,
Version: configkit.Version{Present: true, Text: "v2"}, Version: configkit.Version{Present: true, Text: "v2"},
Location: &configkit.Location{SourceID: "item.yml", Line: 4, Column: 2}, Location: &configkit.Location{SourceID: "item.yml", Line: 4, Column: 2},
@@ -49,7 +53,7 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
{ {
ID: "null", Label: "null version", Path: "null.yml", ID: "null", Label: "null version", Path: "null.yml",
Destination: otherPath, PlacementMode: configkit.PlacementModeMapping, Destination: otherPath, PlacementMode: configkit.PlacementModeMapping,
VersionCheck: &configkit.SourceVersionCheck{ VersionEvidence: &configkit.SourceVersionEvidence{
Path: nullVersionPath, Path: nullVersionPath,
Version: configkit.Version{Present: true, Null: true}, Version: configkit.Version{Present: true, Null: true},
Redacted: true, Redacted: true,
@@ -73,8 +77,10 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
ID string `yaml:"id"` ID string `yaml:"id"`
Destination string `yaml:"destination"` Destination string `yaml:"destination"`
Placement string `yaml:"placement"` Placement string `yaml:"placement"`
DestinationUnresolved bool `yaml:"destination_unresolved"` Layer string `yaml:"layer"`
VersionCheck *struct { EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"`
DestinationIsFallback bool `yaml:"destination_is_fallback"`
VersionEvidence *struct {
Path string `yaml:"path"` Path string `yaml:"path"`
Version struct { Version struct {
Present bool `yaml:"present"` Present bool `yaml:"present"`
@@ -87,7 +93,7 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
Column int `yaml:"column"` Column int `yaml:"column"`
} `yaml:"location"` } `yaml:"location"`
Redacted bool `yaml:"redacted"` Redacted bool `yaml:"redacted"`
} `yaml:"version_check"` } `yaml:"version_evidence"`
} `yaml:"sources"` } `yaml:"sources"`
} }
if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil { if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil {
@@ -99,21 +105,31 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) { if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) {
t.Fatalf("source order = %v", got) t.Fatalf("source order = %v", got)
} }
if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationUnresolved || root.VersionCheck != nil { if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationIsFallback || root.VersionEvidence != nil || root.Layer != "main" {
t.Errorf("root source projection = %#v", root) t.Errorf("root source projection = %#v", root)
} }
wantSelections := []emptyImportSelectionDTO{
{Path: "/imports/first", Location: locationDTO{SourceID: "root.yml", Line: 3, Column: 4}, Selector: "glob"},
{Path: "/imports/second", Location: locationDTO{}, Selector: "path"},
}
if !reflect.DeepEqual(report.Sources[0].EmptyImportSelections, wantSelections) || report.Sources[1].EmptyImportSelections == nil || len(report.Sources[1].EmptyImportSelections) != 0 {
t.Fatalf("import selections: %#v", report.Sources)
}
if strings.Contains(yamlOutput.String(), "destination_unresolved:") || strings.Contains(yamlOutput.String(), "version_check:") {
t.Fatal("legacy YAML keys present")
}
item := report.Sources[1] item := report.Sources[1]
if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationUnresolved { if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationIsFallback {
t.Errorf("sequence item projection = %#v", item) t.Errorf("sequence item projection = %#v", item)
} }
if check := item.VersionCheck; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted { if check := item.VersionEvidence; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted {
t.Errorf("text version evidence projection = %#v", check) t.Errorf("text version evidence projection = %#v", check)
} }
nullSource := report.Sources[2] nullSource := report.Sources[2]
if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationUnresolved { if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationIsFallback {
t.Errorf("mapping projection = %#v", nullSource) t.Errorf("mapping projection = %#v", nullSource)
} }
if check := nullSource.VersionCheck; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted { if check := nullSource.VersionEvidence; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted {
t.Errorf("null/redacted version evidence projection = %#v", check) t.Errorf("null/redacted version evidence projection = %#v", check)
} }
@@ -122,9 +138,15 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 { if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 {
t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls) t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls)
} }
if strings.Contains(textOutput.String(), "destination_unresolved:") || strings.Contains(textOutput.String(), "version_check:") {
t.Fatal("legacy text keys present")
}
if strings.Index(textOutput.String(), `path: "/imports/first"`) > strings.Index(textOutput.String(), `path: "/imports/second"`) {
t.Fatal("import selection order changed")
}
for _, fragment := range []string{ for _, fragment := range []string{
`id: "root"`, `destination: ""`, `placement: "mapping"`, "destination_unresolved: false", "version_check: null", `id: "root"`, `destination: ""`, `placement: "mapping"`, `layer: "main"`, "destination_is_fallback: false", "version_evidence: null", `path: "/imports/first"`, `location: {source_id: "root.yml", line: 3, column: 4}`, `selector: "glob"`, `path: "/imports/second"`, `location: {source_id: "", line: 0, column: 0}`, `selector: "path"`, "empty_import_selections: []",
`destination: "/services"`, `placement: "sequence_item"`, "destination_unresolved: true", `path: "/version"`, `text: "v2"`, `destination: "/services"`, `placement: "sequence_item"`, "destination_is_fallback: true", `path: "/version"`, `text: "v2"`,
`destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true", `destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true",
} { } {
if !strings.Contains(textOutput.String(), fragment) { if !strings.Contains(textOutput.String(), fragment) {

View File

@@ -7,10 +7,9 @@ Importing it does not install either command family.
## Module ## Module
The module path is The module path is `go.maximumdirect.net/ckprompt`. Version v0.2.0 uses
`gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt`. Its first `go.maximumdirect.net/commandkit v0.3.0`, `go.maximumdirect.net/ckconfig v0.2.0`,
release is prepared as `v0.1.0`. It uses `commandkit`, `ckconfig`, and and PromptKit v0.16.0. See the
PromptKit. See the
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-and-definitions) [consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-and-definitions)
for callback, input, state, and acquisition contracts. for callback, input, state, and acquisition contracts.

View File

@@ -7,10 +7,10 @@ import (
"io" "io"
"strconv" "strconv"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
// PromptRequest selects one named prompt for inspection. // PromptRequest selects one named prompt for inspection.

View File

@@ -11,10 +11,10 @@ import (
"testing" "testing"
"testing/fstest" "testing/fstest"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
const adapterPrompt = `prompts: const adapterPrompt = `prompts:

View File

@@ -9,9 +9,9 @@ import (
"strconv" "strconv"
"strings" "strings"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -10,9 +10,9 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -9,11 +9,11 @@ import (
"testing" "testing"
"testing/fstest" "testing/fstest"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
"go.maximumdirect.net/ckprompt"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -1,6 +1,6 @@
package ckprompt package ckprompt
import commandkit "gitea.maximumdirect.net/eric/CommandKit" import commandkit "go.maximumdirect.net/commandkit"
func completionChoices(values ...string) commandkit.CompletionHint { func completionChoices(values ...string) commandkit.CompletionHint {
choices := make([]commandkit.CompletionChoice, len(values)) choices := make([]commandkit.CompletionChoice, len(values))

View File

@@ -8,11 +8,11 @@ import (
"testing" "testing"
"testing/fstest" "testing/fstest"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
"go.maximumdirect.net/ckprompt"
commandkit "go.maximumdirect.net/commandkit"
) )
type compositionInput struct{ Campaign commandkit.Supplied[string] } type compositionInput struct{ Campaign commandkit.Supplied[string] }

View File

@@ -1,4 +1,5 @@
// Package ckprompt provides optional PromptKit configuration comparison, // Package ckprompt, provided by go.maximumdirect.net/ckprompt, provides optional
// PromptKit configuration comparison,
// prompt catalogs, named inspections, requirements discovery and validation, // prompt catalogs, named inspections, requirements discovery and validation,
// and native smoke testing for CommandKit. Its command factories return // and native smoke testing for CommandKit. Its command factories return
// canonical commandkit.Command declarations. Applications can install // canonical commandkit.Command declarations. Applications can install

View File

@@ -28,16 +28,29 @@ License and notices: [LGPL v3.0](../../LICENSE) |
## ReleaseKit ## ReleaseKit
Selected module: `gitea.maximumdirect.net/eric/ReleaseKit` at `v0.4.2` (transitive Go tool requirement; not a runtime import). Selected module: `gitea.maximumdirect.net/eric/ReleaseKit` at `v0.4.1` (transitive Go tool requirement; not a runtime import).
Copyright (C) 2026 Eric Rakestraw Copyright (C) 2026 Eric Rakestraw
SPDX-License-Identifier: LGPL-3.0-or-later SPDX-License-Identifier: LGPL-3.0-or-later
License and notices: [LGPL v3.0](../../LICENSE) | License and notices: [LGPL v3.0](../../LICENSE) |
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/7d033c5ca1c95aec7db9690293638a0a1ac887b8/LICENSE). [LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469/LICENSE).
[Source](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/7d033c5ca1c95aec7db9690293638a0a1ac887b8). [Source](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469).
## ReleaseKit (vanity module)
Selected module: `go.maximumdirect.net/releasekit` at `v0.9.0` (transitive Go tool requirement; not a runtime import).
Copyright (C) 2026 Eric Rakestraw
SPDX-License-Identifier: LGPL-3.0-or-later
License and notices: [LGPL v3.0](../../LICENSE) |
[LICENSE](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/LICENSE).
[Source](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4).
## JSON Schema ## JSON Schema

View File

@@ -0,0 +1,36 @@
# CommandKit ckprompt v0.2.0
## Summary
CommandKit ckprompt v0.2.0 moves the PromptKit integration to
`go.maximumdirect.net/ckprompt`. It uses core
`go.maximumdirect.net/commandkit v0.3.0`,
`go.maximumdirect.net/ckconfig v0.2.0`, PromptKit v0.16.0, and ConfigKit v0.8.0.
The integration adopts core's invocation reporting and completion contracts
while preserving PromptKit's inspection, validation, and smoke semantics.
## Migration
Replace imports of `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt`
with `go.maximumdirect.net/ckprompt`; update core and ckconfig imports to
`go.maximumdirect.net/commandkit` and `go.maximumdirect.net/ckconfig`. Select
core v0.3.0 and both integration modules at v0.2.0 as a matched set. Old and
new core paths identify different Go packages and their types cannot be mixed.
Handlers use `Invocation.Reporter()` for output and categorized messages;
terminal failures carry an explanation and optional cause. The integration
submits provider diagnostics through the reporter, respecting shared reporting
flags. Replace uses of `Invocation.Streams`, `Outcome.Diagnostics`, and the
old error-first failure API as described in the
[core migration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/v0.3.0/docs/consumers/guide.md#invocation-reporting).
PromptKit commands provide completion hints when the application installs the
core completion command. Command and flag aliases remain application owned.
Go 1.26.0 remains the consumer minimum. Importing ckprompt installs no commands;
compose configuration scopes and the PromptKit command family explicitly. See
the [module README](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/README.md)
and [consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/docs/consumers/guide.md#promptkit-configuration-and-definitions).
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/COPYRIGHT) |
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/LICENSE) |
[ATTRIBUTION](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/docs/oss/attribution.md)

View File

@@ -1,5 +1,9 @@
# Composed consumer # Composed consumer
This example uses `go.maximumdirect.net/commandkit v0.3.0`,
`go.maximumdirect.net/ckconfig v0.2.0`, and
`go.maximumdirect.net/ckprompt v0.2.0`.
This example composes application configuration, PromptKit configuration, This example composes application configuration, PromptKit configuration,
PromptKit comparison and catalogs, definition and requirements inspection, and PromptKit comparison and catalogs, definition and requirements inspection, and
one application-owned command: one application-owned command:
@@ -121,11 +125,7 @@ the selected campaign but leaves artifact bindings to the operator. The
`requirements show` commands remain discovery reports: partial discovery can `requirements show` commands remain discovery reports: partial discovery can
succeed even when a concrete request would fail validation. succeed even when a concrete request would fail validation.
The alias examples use the local CommandKit source because the composed Run `GOWORK=off go test ./...` from this example directory to check it against
module's published core dependency, v0.2.0, predates alias declarations. From the module's declared dependencies. A local workspace can instead select the
the repository root, add the three local modules to `go.work` as described in three current sources, as described in the
the [developer guide](../../../../docs/development.md#documentation-validation), [developer guide](../../../../docs/development.md#documentation-validation).
then run `go test ./...` from this example directory. This checks the example
against the current local core and integration sources; it does not claim that
published v0.2.0 supports aliases. The next core dependency adoption is handled
after the core release is prepared.

View File

@@ -8,11 +8,11 @@ import (
"os" "os"
"strconv" "strconv"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
"go.maximumdirect.net/ckprompt"
commandkit "go.maximumdirect.net/commandkit"
) )
type campaign struct { type campaign struct {

View File

@@ -9,11 +9,11 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
"go.maximumdirect.net/ckprompt"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -1,10 +1,8 @@
module gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt module go.maximumdirect.net/ckprompt
go 1.26.0 go 1.26.0
require ( 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.8.0 gitea.maximumdirect.net/eric/ConfigKit v0.8.0
gitea.maximumdirect.net/eric/promptkit v0.16.0 gitea.maximumdirect.net/eric/promptkit v0.16.0
go.yaml.in/yaml/v4 v4.0.0-rc.6 go.yaml.in/yaml/v4 v4.0.0-rc.6
@@ -15,5 +13,7 @@ require (
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/cobra v1.10.1 // indirect
github.com/spf13/pflag v1.0.9 // indirect github.com/spf13/pflag v1.0.9 // indirect
go.maximumdirect.net/ckconfig v0.2.0
go.maximumdirect.net/commandkit v0.3.0
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
) )

View File

@@ -1,7 +1,3 @@
gitea.maximumdirect.net/eric/CommandKit v0.2.0 h1:UNBjSq6XDZHdPqvZLOL3N5R1E1ol0jnfldgradU7eqw=
gitea.maximumdirect.net/eric/CommandKit v0.2.0/go.mod h1:47DQ6Mo/yZqUVn5PAFRmPck91Zhf1jfaHDMoEZvUzsQ=
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig v0.1.0 h1:qqgaCKrraUL//1vcoU+KUlQ5PNX0EtRpqsUraSiUW/w=
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig v0.1.0/go.mod h1:SFtsgbTVQd+BCGQVCFSAopl55pGYhP1sSF442KFpSYA=
gitea.maximumdirect.net/eric/ConfigKit v0.8.0 h1:xCIhYnOHjw7rFvB+vIremPKGeROOxKTomnUEUipuQno= gitea.maximumdirect.net/eric/ConfigKit v0.8.0 h1:xCIhYnOHjw7rFvB+vIremPKGeROOxKTomnUEUipuQno=
gitea.maximumdirect.net/eric/ConfigKit v0.8.0/go.mod h1:C82sbyKHYMV1OwaD2GJanFrwTfcZfjlW2JsGze5b0kA= gitea.maximumdirect.net/eric/ConfigKit v0.8.0/go.mod h1:C82sbyKHYMV1OwaD2GJanFrwTfcZfjlW2JsGze5b0kA=
gitea.maximumdirect.net/eric/promptkit v0.16.0 h1:g3dhN0QfzQriaVOBmGUZCw2iBM9Mli2AAU4CbMfzcuY= gitea.maximumdirect.net/eric/promptkit v0.16.0 h1:g3dhN0QfzQriaVOBmGUZCw2iBM9Mli2AAU4CbMfzcuY=
@@ -18,6 +14,10 @@ github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
go.maximumdirect.net/ckconfig v0.2.0 h1:gcv9Opp9RFgx1cupXq7Uf+P2UWh2FZGYwp+pFY7gmfg=
go.maximumdirect.net/ckconfig v0.2.0/go.mod h1:FR25dNBQCB3rPkmmrccct19SIlbW9mHra6DHx98h10c=
go.maximumdirect.net/commandkit v0.3.0 h1:RCmg2GS8uzlLSJCIqarpn1uFDec0W3ylNNRRPT6kUFE=
go.maximumdirect.net/commandkit v0.3.0/go.mod h1:ZS98DewKNVBygKVDoh5MFD09CnPlP37dS9pVsID5Eoc=
go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=

View File

@@ -8,9 +8,9 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
func TestBundledNativeFailuresReachTerminalExplanation(t *testing.T) { func TestBundledNativeFailuresReachTerminalExplanation(t *testing.T) {

View File

@@ -5,8 +5,8 @@ import (
"errors" "errors"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
commandkit "go.maximumdirect.net/commandkit"
) )
type cancelDuringYAML struct{ cancel context.CancelFunc } type cancelDuringYAML struct{ cancel context.CancelFunc }

View File

@@ -9,9 +9,9 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -5,9 +5,9 @@ import (
"errors" "errors"
"fmt" "fmt"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
// SmokeRequest pairs the configuration selection with the seed request for one // SmokeRequest pairs the configuration selection with the seed request for one

View File

@@ -8,9 +8,9 @@ import (
"reflect" "reflect"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -6,9 +6,9 @@ import (
"io" "io"
"strconv" "strconv"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
type smokeCommandInput[I any] struct { type smokeCommandInput[I any] struct {

View File

@@ -8,9 +8,9 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -9,9 +9,9 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
func TestSmokeTestCommandRetainsSingletonValuesAndResetsInvocations(t *testing.T) { func TestSmokeTestCommandRetainsSingletonValuesAndResetsInvocations(t *testing.T) {

View File

@@ -8,8 +8,8 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )

View File

@@ -1,8 +1,8 @@
package ckprompt package ckprompt
import ( import (
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
) )
// ValidationRequest carries the configuration selection and seed PromptKit // ValidationRequest carries the configuration selection and seed PromptKit

View File

@@ -7,10 +7,10 @@ import (
"testing" "testing"
"testing/fstest" "testing/fstest"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
) )
type validationFailOnGenerate struct{ calls int } type validationFailOnGenerate struct{ calls int }

View File

@@ -4,8 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
commandkit "go.maximumdirect.net/commandkit"
) )
type validationCommandInput[I any] struct { type validationCommandInput[I any] struct {

View File

@@ -9,10 +9,10 @@ import (
"strings" "strings"
"testing" "testing"
commandkit "gitea.maximumdirect.net/eric/CommandKit"
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
configkit "gitea.maximumdirect.net/eric/ConfigKit" configkit "gitea.maximumdirect.net/eric/ConfigKit"
promptkit "gitea.maximumdirect.net/eric/promptkit" promptkit "gitea.maximumdirect.net/eric/promptkit"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
"go.yaml.in/yaml/v4" "go.yaml.in/yaml/v4"
) )