From b0bfe857fe5ccdb6fa881f02fd54f65cb922cc4a Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 2 Nov 2026 12:58:39 +0000 Subject: [PATCH] Document the consumer migration to identified resources --- README.md | 4 +- docs/consumers/configuration-migration.md | 93 ++++++++++++++++------- docs/consumers/pkg-promptkit.md | 72 ++++++++++-------- docs/release.md | 2 +- docs/roadmap/implementation.md | 7 ++ 5 files changed, 118 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 73da77f..348b427 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ boundary and constraints that framework work must preserve. The [v0.16.0 release notes](docs/releases/v0.16.0.md) cover explicit smoke diagnostics, configuration collections, scoped engine views, and discovery. -Upgrading consumers should review the breaking changes to bundled configuration -and prompt version selection and follow the linked migration guide. +Upgrading consumers should also review the current identified-resource and +ConfigKit v1 changes in the [migration guide](docs/consumers/configuration-migration.md). The [v0.15.0 release notes](docs/releases/v0.15.0.md) cover error-only validation of concrete requests with `Engine.ValidateRequest`. diff --git a/docs/consumers/configuration-migration.md b/docs/consumers/configuration-migration.md index f1ae20d..ba74464 100644 --- a/docs/consumers/configuration-migration.md +++ b/docs/consumers/configuration-migration.md @@ -1,8 +1,9 @@ # Configuration And API Migration -Promptkit no longer installs a provider catalog or selects prompt definitions -by descriptive version labels. Applications now choose configuration inputs -explicitly, and execution selects one prompt by its exact ID. This guide +This breaking pre-v1 minor migration changes the v0.16-era keyed resources to +identified lists, adopts ConfigKit v1, and removes prompt-version labels. +Promptkit does not install a provider catalog; applications choose configuration +inputs explicitly, and execution selects one prompt by its exact ID. This guide explains the shape changes and decisions an application must make; it is not an automatic migration tool. The [framework format reference](../formats.md) owns the current configuration contract, and the root package GoDoc owns exact API @@ -30,21 +31,19 @@ engine, err := promptkit.NewEngine(promptkit.Config{ }) ``` -Collection resource keys are local keys, while their runtime identities are -qualified. For example, `collections.openrouter.profiles.gemini-flash-latest` -is selected as `openrouter/gemini-flash-latest`. Stored backend, prompt-default, -and other resource references must use their exact intended IDs; Promptkit does -not rewrite references when a source is mounted. Profile `extends` remains a -sibling local key in the same collection, not a cross-collection reference. +Collection resource IDs are local IDs, while their runtime identities are +qualified. For example, a profile with `id: gemini-flash-latest` in collection +`openrouter` is selected as `openrouter/gemini-flash-latest`. Stored backend, +prompt-default, and other resource references must use their exact intended IDs; +Promptkit does not rewrite references when a source is mounted. `extends` +selects a sibling ID in the same list, not a cross-collection reference. Review collisions and all references when moving resources into collections. -The root `version` is an optional ConfigKit source header. A collection's -`release_version` and a prompt's `version` are optional descriptive labels; -neither selects a resource or changes execution. Preserve a label only when it -is useful to your application. A formerly version-keyed prompt mapping must be -reduced to one deliberately chosen definition per prompt ID, with its old label -retained as prompt metadata if desired. Promptkit cannot choose a winner from a -consumer's version history. +The optional source-root `version` header now accepts `2` or `"2"`; headerless +sources remain valid. A collection's `release_version` remains an optional +label. Prompt-version labels have been removed: choose one definition per ID +and store any application-specific release label outside Promptkit. In a +standalone imported prompt item, root `version` is a source header, not a label. For example, change a version-keyed definition: @@ -60,12 +59,11 @@ prompts: validation_mode: none ``` -to one direct definition. Its optional `version` is only a label: +to one identified definition: ```yaml prompts: - report: - version: "2.0" + - id: report messages: - role: user content: Review this report. @@ -74,6 +72,51 @@ prompts: validation_mode: none ``` +The same conversion applies to backends and profiles. Sibling inheritance uses +identity references, and a later same-ID record replaces the whole lower record: + +```yaml +profiles: + - id: base + endpoint: https://example.invalid/v1 + model: example-model + - id: fast + extends: {id: base} + timeout_seconds: 30 +``` + +To customize a lower resource's fields, add a distinct inherited variant as +above; when replacing the same ID, supply the complete intended record. Generic +append, replace, imports, and inheritance are described by the +[ConfigKit v1 configuration contract](https://forge.maximumdirect.net/base-layer/configkit/src/tag/v1.0.0/docs/config.md). +Source-root controls are now `config:`, not `configkit:`. Imports are optional +unless the selected import declares `required: true`. + +Update ConfigKit imports to `go.maximumdirect.net/configkit` at v1.0.0: its Go +types are incompatible with the old module path. Promptkit now requires Go +1.27.0 or newer. Source builders take ordered slices with explicit IDs: + +```go +endpoint, model := "https://example.invalid/v1", "example-model" +base := "base" +source := promptkit.ProfileSource("application", []promptkit.ProfileConfig{ + {ID: "base", Endpoint: &endpoint, Model: &model}, + {ID: "fast", Extends: &base}, +}) +``` + +Replace former maps passed to `BackendSource` in the same way, setting each +`BackendConfig.ID`. Duplicates are retained for loading to reject. Resource +inspection paths now address list indexes, for example +`configkit.Keys("profiles").Index(0).Key("model")`. Configuration inspection +and diffs expose composed values and provenance, while `InspectProfile` and +other interpreted views expose Promptkit normalization and defaults; the views +are not promised to be identical. + +Remove `PromptVersion` and `PromptIdentity.Version` uses and the corresponding +`prompt_version` JSON members. Prompt hashes are opaque equality values and may +change when the removed field no longer participates in hashing. + ## Identity Mapping The reviewed catalog identities have slash-free profile keys. Their documented @@ -100,8 +143,8 @@ Gemini profile in the same `openrouter` collection: collections: openrouter: profiles: - standard: - extends: gemini-flash-latest + - id: standard + extends: {id: gemini-flash-latest} ``` An optional auto profile may instead select the exact backend and model values: @@ -110,7 +153,7 @@ An optional auto profile may instead select the exact backend and model values: collections: openrouter: profiles: - auto: + - id: auto backend: openrouter/default model: openrouter/auto ``` @@ -142,10 +185,8 @@ if err != nil { ``` If the former format contained multiple versions under one ID, choose the one -definition the application should install, and optionally keep its label in -the prompt's `version` field. That label remains descriptive metadata and is -reported by inspection or results where applicable; it never chooses the -definition. +definition the application should install. Promptkit no longer retains or +returns its former descriptive label. The public inventory APIs can help an operator inspect a captured effective configuration: `ListProfiles`, `ListPrompts`, and `ListBackends` return exact diff --git a/docs/consumers/pkg-promptkit.md b/docs/consumers/pkg-promptkit.md index 5057504..ce2f9c5 100644 --- a/docs/consumers/pkg-promptkit.md +++ b/docs/consumers/pkg-promptkit.md @@ -15,6 +15,9 @@ Import the package as: import "gitea.maximumdirect.net/eric/promptkit" ``` +Configuration APIs use `go.maximumdirect.net/configkit` v1.0.0. Its types are +not interchangeable with the old ConfigKit module path. + The maintained [offline preparation example](../../examples/go-library/prepare/main.go) demonstrates explicit collection composition and inventory. Applications adapting older provider or versioned-prompt configuration can use the @@ -28,7 +31,8 @@ programs. ## Go Compatibility The `go` directive in the selected release's [module metadata](../../go.mod) -declares its minimum supported consumer Go version. Maintainers build and +declares its minimum supported consumer Go version, currently Go 1.27.0. +Maintainers build and validate releases with the locally selected Go patch release; the minimum does not simply track that patch version. @@ -108,8 +112,8 @@ defaults, err := promptkit.FilesystemInputs("embedded defaults", applicationFS, if err != nil { return err } operator, err := promptkit.DirectoryInputs(operatorDirectory) if err != nil { return err } -profile := promptkit.ProfileSource("application choices", map[string]promptkit.ProfileConfig{ - "summary": {Model: &selectedModel}, +profile := promptkit.ProfileSource("application choices", []promptkit.ProfileConfig{ + {ID: "summary", Endpoint: &selectedEndpoint, Model: &selectedModel}, }) engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{ Underlays: []configkit.Underlay{ @@ -120,7 +124,9 @@ engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.Configura }}) ``` -Only add the operator group when the application selects that directory; an +Each later same-ID resource replaces the complete earlier record; use a distinct +inherited sibling for field-level customization. Only add the operator group +when the application selects that directory; an explicitly selected missing or unreadable root is an error. Each helper finds `.yaml` and `.yml` files recursively and disables imports by default. The caller may enable imports on individual inputs. A nil `Sources.Main` is an @@ -131,8 +137,8 @@ labeled mapping as an input. A mapping owns a snapshot of supported values: ```go document := configkit.Mapping("application configuration", map[string]any{ - "profiles": map[string]any{ - "local-summary": map[string]any{ + "profiles": []any{ + map[string]any{"id": "local-summary", "backend": "local", "model": "example-model", "temperature": nil, // Suppress an inherited provider control. }, @@ -202,15 +208,15 @@ sensitive application data. ## Inspect The Captured Configuration Use [`Engine.InspectConfiguration`](../../configuration_inspection.go) for an -operator-selected report of effective configuration, source descriptions, -diagnostics, and path history. Configuration inspection uses the collection's -nested configuration path rather than its qualified runtime ID. For profile -`team/summary`, construct the semantic path with `configkit.Keys`: +operator-selected report of composed configuration, source descriptions, +diagnostics, and path history. Configuration inspection uses list indexes in +the collection's nested path rather than qualified runtime IDs. For a profile +at index `i` in collection `team`, construct the path with `configkit.Keys`: ```go view, err := engine.InspectConfiguration() if err != nil { return err } -path := configkit.Keys("collections", "team", "profiles", "summary", "model") +path := configkit.Keys("collections", "team", "profiles").Index(i).Key("model") explanation, found := view.Explain(path) if found && explanation.Effective.Redacted { // Apply the application's disclosure policy before sharing the report. @@ -221,8 +227,9 @@ if found && explanation.Effective.Redacted { the application decides whether those reports may be disclosed. Credential- shaped provider keys are redacted, but arbitrary prompt and provider content is not necessarily safe to share. Inspection uses the engine's captured result -and does not reopen sources or resolve credentials. `InspectProfile` instead -shows backend-completed execution settings for one profile, and `Prepare` or +and does not reopen sources or resolve credentials. It retains composed values +and provenance rather than Promptkit's normalized/defaulted interpretation. +`InspectProfile` instead shows backend-completed execution settings for one profile, and `Prepare` or `PreparedExecution.Details` shows request-specific rendered messages, inputs, and validation resources. None of those views is a substitute for the others. @@ -253,7 +260,7 @@ for _, difference := range differences { ``` See the [`ConfigurationInspection.Diff` GoDoc](../../configuration_inspection.go) -and ConfigKit's [v0.8.0 effective-configuration diff guidance](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.8.0/docs/config.md#effective-configuration-diffs) +and ConfigKit's [v1.0.0 effective-configuration diff guidance](https://forge.maximumdirect.net/base-layer/configkit/src/tag/v1.0.0/docs/config.md#effective-configuration-diffs) for the exact comparison contract. The operation compares only frozen effective configuration values: it does not reread external files or compare their contents, resolved credential contents, later execution preparation, or @@ -621,7 +628,7 @@ copy, and credential behavior. The interact with prompt definitions, layered profiles, built-ins, schemas, and framework defaults. -For programmatic profiles, use [`ProfileSource`](../../profiles.go) with keyed +For programmatic profiles, use [`ProfileSource`](../../profiles.go) with identified `ProfileConfig` values. Nil fields are omitted; pointers preserve explicit zero, false, and blank values. Raw `configkit.Mapping` expresses explicit null. @@ -634,13 +641,13 @@ and `WithBackend` options have no compatibility wrappers. Use `DirectoryInputs` or `FilesystemInputs` for a strict-composition file group, ConfigKit file inputs for individual files, and `ProfileSource`, `BackendSource`, or `configkit.Mapping` for programmatic values. Backend IDs -are keys in configuration, not registrations. Choose caller underlays in +are fields in configuration, not registrations. Choose caller underlays in fallback-to-operator-to-programmatic order; use `Sources.Main` for one final highest-priority input. -Move embedded IDs into keyed `profiles` and `prompts` maps; each prompt ID now -contains one installed definition, with any descriptive `version` label inside -that definition. Convert `base_profile` to ConfigKit `extends`. For the current +Move resource IDs into identified `backends`, `profiles`, and `prompts` lists; +each prompt ID identifies one installed definition without a version label. +Convert `base_profile` to ConfigKit `extends: {id: parent}`. For the current collection identity mapping, ID-only prompt selection, and required caller-owned choices, see the [configuration migration guide](configuration-migration.md). Exact current @@ -656,7 +663,7 @@ application selects. PromptKit does not install provider catalogs or built-in profile inventories; conventional backend ID constants are names only. Define the model, endpoint, credentials lookup, and settings that your application intends to support. A profile may inherit a sibling profile by its local key in -the same root or collection mapping; its backend reference uses the exact +the same root or collection list; its backend reference uses the exact configured identity. Caller-selected source layers determine the final values. The [format reference](../formats.md) describes the definition fields and composition rules. @@ -729,8 +736,8 @@ it and shared backend identity or capacity policy is unnecessary: ```go endpoint, model := "http://localhost:8000/v1", "example-model" -profile := promptkit.ProfileSource("local profile", map[string]promptkit.ProfileConfig{ - "local-summary": {Endpoint: &endpoint, Model: &model}, +profile := promptkit.ProfileSource("local profile", []promptkit.ProfileConfig{ + {ID: "local-summary", Endpoint: &endpoint, Model: &model}, }) // Add configkit.Input{Source: profile} to a caller underlay. ``` @@ -745,11 +752,13 @@ identity, endpoint, and concurrency limit: ```go backendID, model := promptkit.BackendLocal, "example-model" -backend := promptkit.BackendSource("local backend", map[string]promptkit.BackendConfig{ - backendID: promptkit.LocalBackend("http://localhost:8000/v1", 2), +localBackend := promptkit.LocalBackend("http://localhost:8000/v1", 2) +localBackend.ID = backendID +backend := promptkit.BackendSource("local backend", []promptkit.BackendConfig{ + localBackend, }) -profile := promptkit.ProfileSource("local profile", map[string]promptkit.ProfileConfig{ - "local-summary": {Backend: &backendID, Model: &model}, +profile := promptkit.ProfileSource("local profile", []promptkit.ProfileConfig{ + {ID: "local-summary", Backend: &backendID, Model: &model}, }) // Add both sources as inputs in a caller underlay. ``` @@ -760,13 +769,14 @@ capacity of 1024. #### Configure A Complete Backend -Use a keyed `BackendConfig` value for authentication, extra request parameters, an +Use an identified `BackendConfig` value for authentication, extra request parameters, an explicit queue capacity, a custom ID, or multiple local endpoints: ```go endpoint, keyName, limit, noWaiting := "http://gpu-host:8000/v1", "LOCAL_GPU_API_KEY", 2, 0 -backend := promptkit.BackendSource("GPU backend", map[string]promptkit.BackendConfig{ - "local-gpu": { +backend := promptkit.BackendSource("GPU backend", []promptkit.BackendConfig{ + { + ID: "local-gpu", Endpoint: &endpoint, APIKeyEnv: &keyName, ConcurrencyLimit: &limit, QueueCapacity: &noWaiting, ExtraParams: map[string]any{"provider_option": "enabled"}, @@ -775,7 +785,7 @@ backend := promptkit.BackendSource("GPU backend", map[string]promptkit.BackendCo ``` Place `backend` in a caller underlay and select `"local-gpu"` from a -`ProfileConfig.Backend` pointer or a keyed file profile. All backend +`ProfileConfig.Backend` pointer or an identified file profile. All backend contributions use the same ConfigKit layering rules, including overlays of maintained definitions. The [`BackendConfig` and `LocalBackend` GoDoc](../../backends.go) defines exact omission and construction behavior. @@ -805,7 +815,7 @@ backend := promptkit.BackendConfig{ } ``` -The pointer distinguishes an explicit zero from omission. Use keyed +The pointer distinguishes an explicit zero from omission. Use identified `BackendConfig` literals inside `BackendSource` for programmatic definitions. Capacity belongs to one engine and the selected backend ID; endpoint-only profiles and custom backends without a configured limit remain unrestricted. diff --git a/docs/release.md b/docs/release.md index 41461cb..f38e665 100644 --- a/docs/release.md +++ b/docs/release.md @@ -29,7 +29,7 @@ release_go_series=${release_go_series%.*} go mod edit "-go=${release_go_series}.0" ``` -For example, Go 1.26.8 normally results in `go 1.26.0`. Keep a higher patch +For example, Go 1.27.1 normally results in `go 1.27.0`. Keep a higher patch minimum if a dependency or identified correctness fix requires it. For a patch release, leave the consumer minimum unchanged; using a newer validation toolchain does not itself raise that minimum. If the candidate needs a higher diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 084781b..418761f 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -869,6 +869,13 @@ Validation: render/read affected GoDoc; check local document links and snippets against implemented APIs. Keep current documentation free of obsolete contracts; old syntax may remain explicitly labeled in migration explanations and history. +Completion: the consumer migration guide covers the breaking identified-list, +ConfigKit v1, Go 1.27, source-control, builder, inspection, and prompt-label +changes while retaining earlier deployment guidance. Updated consumer examples, +README, and release-toolchain guidance. Reviewed builder GoDoc and snippets, +checked local link targets and `git diff --check`; release selection and +publication remain separate. + ## Stage 22: Verify The Integrated Sprint And Record Completion Scope: acceptance review and residual corrections, not another feature stage.