diff --git a/docs/consumers/guide.md b/docs/consumers/guide.md index 08bcf76..d02ba93 100644 --- a/docs/consumers/guide.md +++ b/docs/consumers/guide.md @@ -103,10 +103,12 @@ values. Use `ckconfig.Command(ckconfig.Suite[I, S]{...})` when the application needs multiple named scopes, selector flags, scope-aware input checks, or shared -acquisition state. Each selected scope receives its own initialized input. The -suite's `NewState` runs once for the inspection invocation after selected input -checks pass, and the resulting state is shared by selected acquisitions. The -application owns the state type and what it caches. `ckconfig.FromConfigKit` +acquisition state. Input is initialized separately for each selected scope; +state is shared by selected acquisitions. Factory results remain caller-owned, +so separate initialization calls do not guarantee distinct objects. See +[ckconfig.Suite's GoDoc](../../integrations/ckconfig/contracts.go) for factory +timing, omitted-factory zero values (including nil pointers), and ownership. +The application owns the state type and what it caches. `ckconfig.FromConfigKit` adapts a typed ConfigKit loader without calling it during construction. The `config` family provides scope discovery, validation, native effective YAML, @@ -124,16 +126,19 @@ it under `config`; it does not install named definition commands. inspection callbacks. Set its `NewInput`, `NewState`, selectors, or validation when the application needs them, then pass `ckprompt.Command(suite)` to core. Prompt and profile capabilities can be installed independently by providing -only the corresponding callback. Each selected inspection gets a fresh input -and one shared state value for that invocation. The loader receives the -invocation context, explicitly supplied selection, input, and state. The adapter +only the corresponding callback. Each selected inspection prepares one input +and one state value when those steps are reached. See +[ckprompt.Suite's GoDoc](../../integrations/ckprompt/adapters.go) for factory +timing, omitted-factory zero values, and caller-owned objects and effects. +The loader receives invocation context, explicitly supplied selection, input, +and state. The adapter uses PromptKit's public inspection methods and preserves acquisition diagnostics and error identity. -Definition inspection does not execute a prompt, contact a model provider, or -resolve credential values. Credential fields in reports identify environment -variable names and requirements only; they do not report credential -availability. +CommandKit-owned inspection code does not execute prompts, contact model +providers, or resolve credential values; application loaders and direct callbacks +retain their own effects. The [CLI reference](../cli.md#promptkit-definition-inspection) +owns the inspection boundary and credential-report semantics. The [composed example](../../integrations/ckprompt/examples/composed/README.md) combines app and PromptKit config scopes, independently registers profile diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index 37876e8..b75f725 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -126,7 +126,17 @@ require callbacks to run after failure. ## R3: Make public documentation precise about ownership and the final API -**Status:** Open. **Priority:** P2. +**Status:** Completed (2026-10-11). **Priority:** P2. + +**Completed work:** the suites' GoDoc now specifies initialization timing, +omitted-factory zero values (including nil pointers), early-failure limits, and +caller ownership of objects, aliases, and effects. Family GoDoc and consumer +guidance link to those owners. Inspection claims are qualified, the composed +example describes `NewInput`/`NewState`, and `Scope.Summary` no longer promises +discovery output. Reviewed against current preparation/acquisition code and the +example; current consumer/example Markdown has no obsolete context API names. +Changed local links/fragments and whitespace checks pass. Runtime rules and +report fields are unchanged. **Evidence and corrections:** diff --git a/integrations/ckconfig/contracts.go b/integrations/ckconfig/contracts.go index 160b323..22e197c 100644 --- a/integrations/ckconfig/contracts.go +++ b/integrations/ckconfig/contracts.go @@ -69,7 +69,7 @@ type View struct { type Scope[I, S any] struct { // Name identifies the scope in CLI selection and reports. Name string - // Summary is shown when the scope is listed. + // Summary describes the scope. Scope discovery reports name and operations only. Summary string // Operations selects the standard handlers exposed for this scope. Operations []Operation @@ -89,10 +89,21 @@ type Selector[I any] struct { // Suite declares the typed input, shared state, selectors, and configuration // scopes used to assemble configuration commands. +// +// Input initialization is separate for each selected scope; state is shared +// by that invocation's acquisitions. Factory results and callback effects remain +// caller-owned: Command does not deep-copy arbitrary objects or repair aliases +// returned by factories. Core-owned repeated flag collections are copied when +// applied to separate inputs. Factories are not invoked during construction, +// installation, help, version, or scope discovery, and need not run after failure. type Suite[I, S any] struct { - // NewInput creates fresh input storage for each selected scope. + // NewInput is called once for each selected scope reached after operation + // preflight, before applying its selectors and calling CheckInput. + // If nil, input is the zero value of I, including nil for pointer types. NewInput func() I - // NewState creates shared acquisition state once per inspection invocation. + // NewState is called once when acquisition is reached, after all selected + // inputs pass their checks. The result is shared by selected acquisitions. + // If nil, state is the zero value of S, including nil for pointer types. NewState func() S // Selectors declares typed flags and their applicable scopes. Selectors []Selector[I] diff --git a/integrations/ckconfig/family.go b/integrations/ckconfig/family.go index efcb45b..f8bec8a 100644 --- a/integrations/ckconfig/family.go +++ b/integrations/ckconfig/family.go @@ -43,9 +43,9 @@ type preparedSuite[I, S any] struct { // Command eagerly captures a configuration suite as a root-only config family. // It copies suite slices, retains callback references, and returns a reusable // declaration; installation does not invoke factories or providers. During an -// inspection, it creates separate input for each selected scope, validates -// those inputs before acquisition, and creates shared state once for that -// invocation. +// inspection, it initializes input separately for each selected scope and +// validates those inputs before acquisition. Suite documents factory timing, +// zero values, shared state, and caller ownership of returned objects. func Command[I, S any](suite Suite[I, S]) commandkit.Command { prepared := captureSuite(suite) if len(prepared.scopes) == 0 { diff --git a/integrations/ckprompt/README.md b/integrations/ckprompt/README.md index 4d29ff0..4e374c7 100644 --- a/integrations/ckprompt/README.md +++ b/integrations/ckprompt/README.md @@ -21,8 +21,11 @@ Add `ckprompt.ConfigScope(loadEngine)` to the scopes passed to the `config` family. Install `ckprompt.Command(ckprompt.FromEngine(loadEngine))` separately for named prompt and profile inspection. `FromEngine` supplies PromptKit-backed callbacks; applications may provide their own callbacks with -`ckprompt.Suite`. Inspection does not execute prompts, contact model providers, -or resolve credentials. The maintained +`ckprompt.Suite`. CommandKit-owned inspection code does not execute prompts, +contact model providers, or resolve credentials; application loaders and direct +callbacks retain their own effects. See the +[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#promptkit-definition-inspection) +for the inspection boundary and report semantics. The maintained [composed example](examples/composed) shows complete application wiring. ## License and attribution diff --git a/integrations/ckprompt/adapters.go b/integrations/ckprompt/adapters.go index edb1402..9447694 100644 --- a/integrations/ckprompt/adapters.go +++ b/integrations/ckprompt/adapters.go @@ -33,10 +33,17 @@ type ProfileRequest struct { // Suite describes application-owned input, shared state, and named inspection // capabilities. Its private issues retain adapter construction failures. +// Factory results and callback effects remain caller-owned: Command does not +// deep-copy arbitrary objects or repair aliases returned by factories. +// Factories are not invoked during construction, installation, help, or version, +// and need not run after failure. type Suite[I, S any] struct { - // NewInput creates input storage once for the selected definition command. + // NewInput is called once when definition input preparation is reached, + // before applying selectors and calling CheckInput. + // If nil, input is the zero value of I, including nil for pointer types. NewInput func() I - // NewState creates shared inspection state once for that invocation. + // NewState is called once when inspection is reached, after input checks + // pass. If nil, state is the zero value of S, including nil for pointer types. NewState func() S // Selectors declares the original typed flags accepted by definition commands. Selectors []commandkit.Flag[I] diff --git a/integrations/ckprompt/command.go b/integrations/ckprompt/command.go index 13181d5..f9a9849 100644 --- a/integrations/ckprompt/command.go +++ b/integrations/ckprompt/command.go @@ -26,8 +26,8 @@ type definitionInput[I any] struct { // Command captures the optional named PromptKit inspection tree and adds only // the inspection capabilities present in suite. It adds no configuration // family; callers compose ConfigScope independently. Construction and -// installation do not run suite callbacks. A selected definition command gets -// its own input and one shared state value for that invocation. +// installation do not run suite callbacks. Suite documents invocation input +// and state initialization, zero values, and caller ownership of returned objects. func Command[I, S any](suite Suite[I, S]) commandkit.Command { if suite.InspectPrompt == nil && suite.InspectProfile == nil { command := commandkit.NoCommand() diff --git a/integrations/ckprompt/examples/composed/README.md b/integrations/ckprompt/examples/composed/README.md index 5321426..040f6c4 100644 --- a/integrations/ckprompt/examples/composed/README.md +++ b/integrations/ckprompt/examples/composed/README.md @@ -13,6 +13,10 @@ go run . session restore session-42 --campaign spring The sources and session store are small in-memory fixtures. `--campaign` is a typed selector shared by the app and PromptKit configuration scopes. Their -scope contexts share a per-invocation cache created by `ConfigSuite.NewContext`. -Prompt/profile inspection has its own invocation context and composes the same -application and engine loader functions. +`ckconfig.Suite[*inspectionInput, *runCache]` uses `NewInput` to initialize each +selected scope's input separately and `NewState` to create one cache shared by +that invocation's acquisitions. Prompt/profile inspection prepares its input and +cache independently for its invocation, using the same application and engine +loader functions. See the +[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md) +and the suites' GoDoc for initialization timing and ownership.