diff --git a/docs/roadmap/configuration-collections-current-configkit.md b/docs/roadmap/configuration-collections-current-configkit.md deleted file mode 100644 index f826bad..0000000 --- a/docs/roadmap/configuration-collections-current-configkit.md +++ /dev/null @@ -1,372 +0,0 @@ -# Proposal 1: Namespaced Collections With Current ConfigKit - -Status: proposed PromptKit configuration standard; not implemented or accepted. -This proposal addresses the pending configuration decision in the -[namespace and collection roadmap](namespaces.md). It requires PromptKit changes -but no ConfigKit extension. Proposal 2, which may assume upstream changes, is -outside this document. - -## Recommendation - -Keep the existing top-level `backends`, `profiles`, and `prompts` mappings, and -use fully qualified resource IDs as their actual YAML keys. Add a `collections` -mapping keyed by namespace for release metadata. The application's main input -owns `version: 1`; reusable collection contributions omit that top-level field. - -Compose independently maintained peer collections in one ConfigKit underlay -group. Put intentional application/operator overrides in later groups or the -main input. This uses ConfigKit's distinction between strict composition and -explicit precedence to protect independent contributions while retaining -ordinary configuration customization. - -Namespace identity exists in the configuration tree before composition. A -separate `id` field inside an otherwise unqualified prompt definition would be -too late: ConfigKit merges mapping keys before PromptKit interprets definitions. - -## Reviewed Baseline And Evidence - -Reviewed the local `../ConfigKit` checkout at commit -`6fffde4af8f31f99d3ee295c426eb3234cb0fb77` (v0.7.1), the version selected by -PromptKit. The governing upstream sources are its -[configuration contract](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.7.1/docs/config.md) -and [composition/overlay decision](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.7.1/docs/adr/0001-separate-composition-and-overlay.md). -Implementation evidence includes `internal/engine/compose_test.go`, -`internal/engine/load_request_test.go`, `internal/engine/imports_test.go`, and -the public `VersionRule` and `LoadLayered` declarations in that checkout. - -The relevant current rules are: - -| ConfigKit behavior | Consequence for this proposal | -| --- | --- | -| Within a composition group, mappings combine recursively; every other overlapping pair conflicts, even equal scalars | Distinct qualified keys coexist; repeated metadata versions or message sequences conflict within the group | -| Between underlay groups, later values overlay earlier ones; main has higher precedence | Directory order must not accidentally become collection precedence; intentional overrides are separate layers | -| Overlay mappings combine recursively; scalars, sequences, and null replace lower values | An override can replace a setting or message sequence without replacing the entire prompt | -| Syntax and strict-composition failures happen before final domain validation | A higher layer cannot repair a conflicting peer group | -| The configured specification-version path belongs to main; underlays and imported fragments cannot claim it | There is one assembled-configuration specification declaration, not independently checked collection headers | -| Sibling `extends` resolves after composition and precedence | Fully qualified profile keys work as exact cross-collection inheritance references | -| Defaults, typed decoding, resolution, and semantic validation operate on final assembled values | PromptKit need not validate each collection separately | -| Source origins retain resource context and inspection history | File-backed content and explicit provenance inspection can retain existing behavior | - -PromptKit already provides directory and embedded-source helpers, and its -configuration adapter calls `configkit.LoadLayered` once. Its current document -schema only exposes `backends`, `profiles`, and `prompts`; this proposal adds -version and metadata fields rather than claiming they work today. The -[current format reference](../formats.md) remains authoritative until adoption. - -## Proposed Document Shape - -The effective configuration has these application fields. Source documents may -also use supported ConfigKit directives, which ConfigKit consumes before the -application handoff: - -| Field | Proposed meaning | -| --- | --- | -| `version` | PromptKit configuration/collection specification identifier, owned by the main input | -| `collections` | Optional mapping from namespace to collection release metadata | -| `backends` | Existing backend definitions, keyed by exact resource ID | -| `profiles` | Existing profile definitions, keyed by exact resource ID | -| `prompts` | Existing prompt definitions, keyed first by exact resource ID and then by prompt version | - -The namespace roadmap's accepted grammar applies to resource keys: either an -unqualified ID or exactly `namespace/local-name`. Neither qualified component -contains `/`; dots remain available within local names. Published collections -use qualified keys. Unqualified application definitions remain supported. - -Keep IDs in mapping keys, including the prompt's outer key; do not introduce -another embedded `id` or `namespace` field in each definition. Collection -metadata does not prefix or rewrite keys. Filenames and directory names have -no effect on identity. Namespace comparison and references remain exact. - -The following compact contribution could be supplied by a provider collection. -The endpoint and model are synthetic configuration examples, not live targets: - -```yaml -collections: - provider: - version: "2026.10.14" -backends: - provider/default: - endpoint: https://inference.example.invalid/v1 -profiles: - provider/brief: - backend: provider/default - model: vendor/example-model - temperature: 0.2 -``` - -Two independently maintained application collections can then supply the same -local prompt name without colliding: - -```yaml -collections: - weatherreporter: - version: "2.4.0" -prompts: - weatherreporter/alerts.summarize: - "1": - default_profile: provider/brief - messages: - - role: user - content: Summarize the weather alerts. - output: - format: text - validation_mode: none -``` - -```yaml -collections: - homewatch: - version: "3.1.0" -prompts: - homewatch/alerts.summarize: - "1": - default_profile: provider/brief - messages: - - role: user - content: Summarize the household alerts. - output: - format: text - validation_mode: none -``` - -ConfigKit sees separate keys under `prompts`. It never needs to understand -PromptKit namespaces to preserve both definitions. The quoted `"1"` keys are -individual prompt versions, unrelated to the main specification version or the -collection release strings. - -## Specification And Collection Versions - -Configure ConfigKit's existing `VersionRule` at `configkit.Keys("version")`. -Recommend requiring an explicit supported value on the selected main input for -this new standard: canonical YAML is `version: 1`. ConfigKit exposes both integer -`1` and string `"1"` as version text `1`; accept both, while documenting the -integer spelling. Reject absent, null, and unsupported versions through the -configured checker. These are proposed PromptKit format choices, implemented -through ConfigKit's supported callback, not a separate input-scanning pass. - -A minimal main input is: - -```yaml -version: 1 -``` - -Programmatic applications can supply the same main input with `configkit.Mapping`. -Do not infer the specification from a directory name or collection release, strip -version fields from fragments, or silently inject a version to hide a missing -declaration. Requiring main instead of accepting an omitted main is an additional -explicit migration cost of this proposal. - -Reusable collection files, including a collection's root metadata file, omit -top-level `version`. So do operator underlays and imported fragments. ConfigKit -protects the configured version path even if a repeated value would equal `1`. -The version checker is invoked by ConfigKit once, at its normal point before -underlay assembly; it selects the contract for the complete configuration. - -For collection metadata, propose an ordinary optional `collections` mapping: - -- Its keys are exact nonblank namespace names without `/`. -- Each effective entry is a non-null mapping with a required nonblank string - `version`. Quote collection release identifiers; this nested field does not - receive ConfigKit's special integer-to-string handling for top-level `version`. -- Release strings are descriptive publisher identifiers, not executable - dependency constraints or implicit precedence. No SemVer ordering is needed. -- An omitted, null, or empty top-level `collections` mapping means no declared - collection metadata. Null individual entries are invalid final descriptors; - null is not a new per-entry deletion operator. - -Validate this metadata only in final effective values. Do not require a metadata -entry for every resource namespace or require every metadata entry to have -resources. This lets ordinary application configuration add definitions or -overrides without fabricating a collection release. Collection publishing -guidance recommends declaring its own namespace and version, but PromptKit -does not audit which source file originally contributed a resource. - -## Source Selection And Layering - -Recommend this caller-selected assembly: - -| Tier | Contents | Relationship | -| --- | --- | --- | -| First underlay group | All selected peer collection inputs | Strict composition across the entire group | -| Later underlay groups, if selected | Application defaults or operator override documents, in caller-chosen priority order | Strict within each group; later groups overlay earlier groups | -| Main input | Specification declaration and optional highest-priority local settings | Overlays the underlays | - -These are integration guidance, not a new enforced source policy. The application -still selects ConfigKit groups and precedence explicitly. In particular, separate -directories do not each require their own underlay tier. Append their discovered -inputs into one group when they are independent peer libraries. Putting each -directory into a successive group intentionally enables later overrides. - -An illustrative caller arrangement using existing source APIs is: - -```go -var peers []configkit.Input -for _, directory := range collectionDirectories { - inputs, err := promptkit.DirectoryInputs(directory) - if err != nil { return err } - peers = append(peers, inputs...) -} -main := configkit.Input{Source: configkit.File(applicationConfigFile)} -sources := promptkit.ConfigurationSources{ - Underlays: []configkit.Underlay{{Inputs: peers}}, - Main: &main, -} -// Pass sources to NewEngine after the proposed document schema is implemented. -``` - -The helpers already supply filesystem context, recursively select YAML, and -leave imports disabled. An operator may install a collection with an ordinary -`collection.yml` metadata contribution and definition files in subdirectories. -That filename is a recommended packaging convention, not a special loader -instruction. All selected YAML files participate normally; resource files should -be outside that scan or use suitable non-configuration formats. - -For explicit imports instead, select only collection entry-point files, enable -imports on those inputs, and let ConfigKit traverse their fragments. Do not both -recursively select all files and import those same files in the same group: -ConfigKit rejects repeated sources. Imports remain root-contained, relative, -opt-in paths/globs; they neither fetch repositories nor establish precedence. -Each directory input can have its own filesystem root, so peers need not share -an installation directory. - -Importing all peers from main is also possible under ConfigKit's rules, but -main's own definitions and its imports then compose strictly. A main document -cannot override something in its own import graph. The recommended underlay -arrangement keeps main available for ordinary application overrides without -requiring a selected-overlay API addition to PromptKit. - -## Collisions, Partial Contributions, And Overrides - -| Contributions | Current ConfigKit outcome | -| --- | --- | -| `weatherreporter/alerts.summarize` and `homewatch/alerts.summarize` | Both definitions remain | -| Same qualified prompt ID, different prompt-version keys | Both versions remain; PromptKit's existing version selection applies | -| Same ID/version, disjoint definition fields in one group | Fields compose into one definition | -| Same ID/version, overlapping message sequences in one group | `compose.conflict`, even if the sequences are identical | -| Same `collections..version` in two peer inputs | `compose.conflict`, even if release strings are equal | -| Same namespace with disjoint metadata/resource contributions | Contributions can compose; there is no namespace-ownership error | -| Same qualified ID or collection metadata in a later layer | Ordinary recursive overlay semantics apply | - -This does not promise that every repeated resource ID or collection namespace -is fatal. ConfigKit permits disjoint mapping contributions by design. Namespace -qualification avoids accidental *cross-namespace* collisions; strict grouping -detects conflicting leaves among peers. Deliberately sharing an exact key in -different precedence layers still allows overrides. - -For example, main can override only the selected profile's temperature: - -```yaml -version: 1 -profiles: - provider/brief: - temperature: 0.1 -``` - -The lower backend and model remain. Replacing `messages` would replace the -entire sequence, not append messages. An empty mapping does not clear inherited -children. Explicit null retains existing PromptKit field-specific meanings; -this proposal adds no generic delete or replace-whole-resource directive. - -Do not inspect provenance to reject a higher-priority metadata edit, or declare -that a collection namespace is locked to one input. Provenance is for explicit -operator explanation. Final domain validation can reject an invalid resulting -profile or descriptor, but cannot resurrect or reject displaced source values. - -## References, Inheritance, And Resources - -Stored references remain exact IDs. A collection prompt can select -`provider/brief`; a profile can inherit `provider/brief` by writing that exact -key as `extends`. Profile mappings remain siblings under `profiles`, so this -uses ConfigKit's existing inheritance without moving definitions into nested -collection containers. A consumer's selected namespace never rebinds those -stored references. Provider `model` strings remain unchanged and may contain `/`. - -Prompt versions remain an inner mapping. ConfigKit's sibling inheritance is -generic, but it does not make another prompt's outer ID a sibling of an inner -version definition. This proposal introduces no cross-prompt reference resolver. - -Keep existing resource semantics: ConfigKit records the effective field's origin -and source context, and PromptKit uses that context for file-backed prompt -content. Do not derive content paths from namespaces or a collection metadata -filename. Schema roots and runtime artifacts retain their existing separately -configured behavior; a metadata file does not automatically mount schemas or -change their resource resolution. Moving to configuration collections must not -claim broader resource portability than those contracts provide. - -## Collection Inventory - -Propose a public `ListCollections` operation returning detached descriptors from -the engine's captured effective metadata. Exact Go names and signatures remain -to be chosen. Each descriptor contains namespace and declared collection release -version. Expose the effective specification version once at engine/configuration -level, not as a falsely independently checked version on each collection. - -An absent metadata map returns no collection descriptors. Sort by namespace for -stable inspection. Report resources separately through the accepted namespace -listing/filter APIs; unregistered namespaces can exist there without fabricated -collection versions. A metadata-only declaration can appear in collection -inventory even when no resources remain under that namespace. - -This API means "effective declared collections," not "every manifest ever -loaded" or "verified installed package versions." Metadata and resources can -be changed by later layers. A declared release does not certify that all effective -definitions are identical to a publisher's release. ConfigKit inspection explains -the sources and edits; the domain API does not replay history or reread files. - -## PromptKit Changes And Deliberate Limits - -Adoption would add the version field/checker and collection metadata schema, -final-value validation, captured inventory, and the public collection API. It -would also implement the accepted scoped lookup and discovery behavior and -remove automatically bundled catalogs and built-in profiles, as tracked in the -parent roadmap. Update canonical contracts and migration guidance only when -those changes land. Existing documents with no main specification declaration -would need an explicit migration under the proposed version policy. - -There is no ConfigKit change, per-collection loading/validation pass, source-level -namespace registry, key-rewriting stage, or automatic configuration installation. -Definitions retain their qualified keys throughout assembly. Invalid effective -domain values are PromptKit's responsibility; composition, imports, inheritance, -and version-path protection remain ConfigKit's responsibility under -[ADR 0001](../adr/0001-configuration-boundary.md). - -The main limitation is independent specification compatibility: a reusable -collection cannot carry its own protected top-level `version: 1` when imported -or used as an underlay. Publishers/operators must select configuration compatible -with the main standard. Strict decoding catches unsupported surviving fields, -but it is not an independent compatibility check for each collection release. -This is the principal issue to compare with proposal 2. - -## Validation And Review Criteria - -Review verification on 2026-10-14: the focused ConfigKit composition, grouped -loading, and import-version tests passed in the local checkout. A temporary -offline consumer using that checkout also loaded the five YAML examples above -through a prospective document schema and verified distinct identities, equal -and unequal peer conflicts, disjoint contributions, main overrides, atomic -sequence replacement, main/underlay/import version ownership, and qualified -inheritance. This establishes feasibility with current ConfigKit; it does not -implement the proposed PromptKit schema or inventory API. No temporary harness -or module replacement is part of either repository. - -Review this proposal against these observable cases: - -- Two collections using the same local prompt name survive composition under - distinct qualified keys. -- Equal and unequal overlapping metadata versions fail in one peer group; - disjoint contributions compose, and later metadata overrides remain allowed. -- Main overrides one profile field while preserving other fields; sequence - overrides replace whole sequences. -- A strict peer conflict cannot be hidden by a higher layer. -- Main `version: 1` succeeds, while omitted/null/unsupported versions fail the - proposed checker and imported/underlay declarations fail ConfigKit's existing - version ownership checks. -- Fully qualified inheritance resolves through the assembled sibling mappings; - file-backed content retains its declaring source's context. -- Inventory reflects final metadata and remains captured when source files - change; resource namespace discovery does not require a metadata declaration. - -The configuration schema, explicit-version requirement, metadata null rules, -inventory shape, and recommended peer-group layout are proposal choices to -review. They do not resolve the parent roadmap's decision 5 merely by being -written here. diff --git a/docs/roadmap/configuration-collections-identified-records.md b/docs/roadmap/configuration-collections-identified-records.md deleted file mode 100644 index 2728171..0000000 --- a/docs/roadmap/configuration-collections-identified-records.md +++ /dev/null @@ -1,434 +0,0 @@ -# Proposal 2: Namespaced Collections As Identified Records - -Status: proposed alternative; not implemented or accepted. This is a middle -ground between [proposal 1](configuration-collections-current-configkit.md), -which uses current ConfigKit, and -[proposal 3](configuration-collections-mounted-fragments.md), which changes -source placement and document organization. Proposal 3 also adopts the later -requirement for one installed definition per prompt and an optional version; -this proposal retains versioned record identities for comparison. The parent -[namespace and collection roadmap](namespaces.md) retains the accepted product -decisions and the pending configuration decision. - -## Recommendation And Scope - -Represent prompts, profiles, and backends as sequences of records with explicit -identity fields. Prefer separate `namespace` and local `id` fields. Ask ConfigKit -to support opt-in, application-declared identity rules at selected configuration -paths, so those records compose and overlay by identity rather than position. - -The extension is one cohesive capability: identified record sequences, including -their strict composition, overlay, inheritance, and provenance behavior. It is -not a general user-defined merge framework. ConfigKit continues to own the -complete assembly process and hands PromptKit one final resolved configuration. - -Keep the root `prompts:`, `profiles:`, and `backends:` keys. Keep collection -metadata as the ordinary namespace-keyed mapping from proposal 1. Keep the main -input's specification declaration and the existing source/layer model. This -proposal does not add bare single-record files, source mounting, implicit -namespace injection, or per-import specification checking. Those are separate -questions for proposal 3. - -## Current Baseline And Required Extension - -The reviewed ConfigKit baseline remains v0.7.1, local checkout commit -`6fffde4af8f31f99d3ee295c426eb3234cb0fb77`. Its -[configuration contract](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.7.1/docs/config.md) -and the implementation/tests reviewed for proposal 1 establish that: - -- Sequences are atomic: overlapping sequences conflict during strict composition - and replace one another across precedence layers. -- ConfigKit can already decode a single sequence of mappings into application - records. It does not currently use their fields as merge identities. -- `extends` currently identifies immediate mapping siblings. A sequence-element - mapping cannot establish its own sibling relationship, and mapping-valued - `extends` is not a supported reference form. -- Final decoding, application resolution, and semantic validation happen after - configuration assembly and inheritance. - -Consequently, changing PromptKit's document structs alone would not implement -this proposal. Concatenating sequences in PromptKit or converting each source -to keyed mappings before calling ConfigKit would violate the chosen boundary. - -## Proposed Authoring Format - -Each prompt record describes one prompt version, without a nested version-key -mapping. Use explicit strings for identity fields: - -```yaml -collections: - weatherreporter: - version: "2.4.0" -prompts: - - namespace: weatherreporter - id: summarize.alerts - version: "1" - default_profile: openrouter/gemini-flash-latest - messages: - - role: user - content: Summarize the weather alerts. - output: - format: text - validation_mode: none -``` - -A second collection can use the same local ID without colliding: - -```yaml -collections: - homewatch: - version: "3.1.0" -prompts: - - namespace: homewatch - id: summarize.alerts - version: "1" - default_profile: openrouter/gemini-flash-latest - messages: - - role: user - content: Summarize the household alerts. - output: - format: text - validation_mode: none -``` - -The profile name is an illustrative configured reference, not a statement about -current provider inventory. A synthetic provider contribution shows the same -record shape for backends and profiles: - -```yaml -collections: - provider: - version: "2026.10.14" -backends: - - namespace: provider - id: default - endpoint: https://inference.example.invalid/v1 -profiles: - - namespace: provider - id: brief - backend: provider/default - model: vendor/example-model - temperature: 0.2 -``` - -These are independent format examples; the synthetic provider does not satisfy -the earlier examples' OpenRouter reference. An assembled configuration must -supply its selected references through ordinary configuration and existing -PromptKit validation/selection rules. - -Retain the existing `default_profile` field instead of also renaming it to -`profile`. Reducing nesting and making identity explicit are the changes under -evaluation; unrelated field renames are unnecessary. - -### Identity And Public References - -Register these record identities with ConfigKit: - -| Configuration path | Identity fields, in order | -| --- | --- | -| `backends` | `namespace`, `id` | -| `profiles` | `namespace`, `id` | -| `prompts` | `namespace`, `id`, `version` | - -PromptKit turns each final `(namespace, id)` pair into its public -`namespace/id` identifier after handoff; the prompt version remains a separate -selection dimension. The conversion creates runtime indexes, not another merge -or source-processing pass. It must reject invalid final domain identities rather -than silently re-keying them. - -Require identity fields to be explicitly present strings in every record, -including partial override records. A prompt's nested `version` is a prompt -identity component, not the protected top-level specification declaration. -Do not derive any identity component from a typed default, parent, filename, -collection metadata entry, or caller execution scope: matching happens before -those application-level interpretations. - -For unqualified application definitions, use `namespace: ""` explicitly; their -public identifier is the local `id` alone, without a leading slash. -Nonempty namespaces and local IDs follow the accepted namespace grammar; -local IDs cannot contain `/`. Preserve exact spelling. PromptKit owns these -domain checks on the final values; ConfigKit only requires usable structural -identity fields and compares exact string tuples. Distinct tuples must never -be conflated by concatenating fields with an unescaped delimiter internally. - -Stored `default_profile` and `backend` references remain fully qualified or -exact unqualified strings, as already selected in the namespace roadmap. -Provider model values retain their existing syntax, including slashes. - -## Proposed ConfigKit Contract - -### Explicit Registration - -The application's ConfigKit definition declares record-sequence rules at exact -semantic paths, with ordered identity field names. The table above is a -conceptual registration, not a proposed Go API declaration. ConfigKit does not -guess from field names such as `id`, and configuration files cannot silently -switch their own merge policy. No arbitrary merge callbacks are required. - -An initial implementation only needs direct string identity fields at explicitly -registered paths. Wildcard registration, computed keys, key normalization, -implicit identity defaults, and nested identity expressions are not required -by this proposal. - -At a registered path, a non-null contribution must be a sequence of mappings. -Every record must supply all structural identity fields with the declared -string type. Missing/null/non-string identity fields or non-mapping records -are ConfigKit structural errors: the loader cannot assign them a record identity. -These errors cannot be hidden by a later layer. Nonidentity body fields retain -the existing final-value decoding/validation lifecycle. - -For consistency with duplicate mapping-key handling, recommend rejecting two -records with the same tuple within a single source sequence. Across separate -sources, matching tuples participate in normal composition as described below. -This is a proposed explicit upstream rule, not a claim about current ConfigKit -or a PromptKit source-level duplicate scan. - -### Strict Composition And Overlay - -Treat identity fields as the record's structural key. Their repeated equal -values are not overlapping body fields that cause composition conflicts. -Retain the fields in the final record and preserve their origin information. -All remaining fields form the body to which existing mapping rules apply. - -| Contributions at a registered path | Proposed result | -| --- | --- | -| Different identity tuples in one group or different layers | Retain both records | -| Same tuple across peer sources, disjoint body fields | Recursively compose one body | -| Same tuple across peer sources, overlapping non-mapping body values | Composition conflict, even if equal | -| Same tuple in a higher-priority layer | Recursively overlay the higher body on the lower body | -| Same prompt namespace/local ID but different prompt version | Distinct records | -| Identity field changed in a later contribution | A different record; never an implicit rename of the old record | - -Once a tuple is selected for matching, identity fields cannot themselves be -overlaid into a different tuple. This avoids record identity changing during -composition. A higher layer need only repeat the tuple and changed body fields: - -```yaml -version: 1 -profiles: - - namespace: provider - id: brief - temperature: 0.1 -``` - -The provider/backend/model fields inherited through layering remain. A new -record introduced by an override still undergoes ordinary final validation; -matching by identity does not guarantee it is a complete runnable profile. - -For registered sequences, recommend that `[]` contributes no records and does -not clear lower records, like an empty keyed mapping. This differs deliberately -from ordinary sequence replacement. Explicit null at the whole registered path -uses ordinary cross-layer replacement and can clear that whole collection when -the application's final schema permits null. Within strict composition, null -conflicts with another present value as usual. No per-record deletion marker, -rename operation, or general patch language is added. - -Process tiers in precedence-assembly order, lowest first, with deterministic -source order within a tier. Preserve first-contribution order for distinct -records, retain a matched record's position, and append newly encountered -tuples. This makes output deterministic without giving position precedence or -identity meaning; acquisition order need not equal assembly order. PromptKit -can still sort its public inventory independently. - -**Unregistered sequences keep all current semantics.** In particular, `messages` -remains atomic: it conflicts across strict peer definitions and is replaced -as a whole by a later override. Identified record support must not turn every -sequence into a union or keyed merge. - -### Inheritance Within A Registered Sequence - -The extension must give identified records a sibling identity space. For -composite identities, recommend a structural `extends` mapping containing the -complete parent tuple. A profile example is: - -```yaml -profiles: - - namespace: weatherreporter - id: brief - extends: - namespace: provider - id: brief - temperature: 0.4 -``` - -ConfigKit resolves this relationship within the same registered `profiles` -sequence after all composition and precedence. It overlays the child's body -over the parent's resolved body, retains the child's identity fields, and -consumes `extends` before typed decoding. Parent identity fields are never -inherited into the child. References for a three-field identity, such as a -prompt record, must include all three fields; no version guessing or namespace -fallback is introduced. References cannot cross resource paths. - -Preserve existing behavior for omitted relationships, `extends: null`, missing -parents, cycles, and overridden relationships. A partial child contribution -can retain a lower-layer relationship, and only final active relationships are -resolved. Inherited file-backed content keeps the declaring field's source -context, not the child's source directory. - -This structural reference form is only enabled for records at registered paths. -Existing mapping-sibling string inheritance remains unchanged elsewhere. A -future single-field record rule could use that same field in the reference -mapping; no PromptKit-specific interpretation of slash-separated parent strings -is needed inside ConfigKit. - -### Provenance, Inspection, And Typed Handoff - -ConfigKit owns record matching and provenance throughout assembly. A conflict -must identify the record and conflicting source locations, not merely report -that two sequences occupy `prompts`. Preserve ConfigKit's safe diagnostic -contract when representing that identity; do not indiscriminately echo input -field values in error messages. Identity-field declarations retain their -contributing locations even when those equal structural fields do not conflict. - -Keep the final application-facing shape as a sequence of records, suitable for -ordinary slice decoding and effective-config rendering. ConfigKit can use a -private identity index, but should not expose private normalized nodes to -PromptKit. Final body presence/null state, field origins, inheritance history, -redaction, and passive source resource contexts must survive matching. - -No new public identity-selector path language is required for this proposal. -Inspection may address final records by sequence index, with ConfigKit mapping -effective field paths to the appropriate historical source locations internally. -Indexes are snapshot-specific; consumers locate a record by its identity before -constructing an indexed path. Histories must not become attached to another -record merely because its source position differed. Existing positional diff -behavior need not become an identity-aware cross-snapshot diff in this work. - -Rules must apply consistently to all enabled source kinds and composition -entry points, including imports and layered input. Existing explicit CLI -overrides must not leave duplicate or malformed structural identities in the -final registered sequences; ConfigKit owns their integration and consistency -checks. Ordinary application resolution must not trigger another merge or -inheritance pass. Detailed public option declarations and implementation -mechanics belong in the upstream design if this proposal is selected. - -## Collection Metadata, Versions, And Assembly - -Retain proposal 1's ordinary `collections..version` metadata and -effective-descriptor inventory. It is distinct from the generic ConfigKit term -"record sequence." Collection declarations still follow mapping composition; -they are not a source registry or exclusive ownership claim. Repeated metadata -release strings conflict in a strict peer group and can be overridden in a -later layer. PromptKit does not add an independent duplicate-namespace scan. - -Also retain proposal 1's main-owned `version: 1` declaration and its proposed -explicit-version requirement. The value denotes the specification for the -assembled configuration, not each imported package. Prompt record versions and -collection release strings do not change that ownership rule. These proposals -are alternative candidates for a future standard; they are not two simultaneously -supported meanings for a released specification version. - -Combine peer collection inputs in one strict underlay group; use later groups -or main for intentional overrides. Callers continue to choose grouping and -precedence. Directory inputs and explicit imports use existing ConfigKit -selection and resource-context rules. There is no PromptKit pre-parser that -reformats records, removes version fields, or replays the original sources. - -**Independent collection specification checks remain unresolved.** This bounded -extension does not permit imported or underlay roots to declare their own -protected top-level `version`. A publisher must still supply configuration -compatible with the selected main standard. Proposal 3 may consider a broader -source/version contract; proposal 2 must not imply that record identity solves -that separate issue. - -## Ergonomic Alternatives And Tradeoffs - -The first syntax discussed is also compatible with the generic extension: - -```yaml -prompts: - - id: weatherreporter/summarize.alerts - version: "1" - default_profile: openrouter/gemini-flash-latest - messages: - - role: user - content: Summarize the weather alerts. - output: - format: text - validation_mode: none -``` - -That alternative registers prompt identity as `(id, version)` and profile/backend -identity as `(id)`. It is simpler to align with public reference strings and -requires fewer identity fields in partial overrides. It repeats the namespace -inside each full ID and gives authors no separate namespace field. - -Prefer the composite form for explicit author-facing fields and easier editing -of local names. Do not support both forms opportunistically in the same standard: -that would require aliasing or normalization before identity matching. Select -one representation for the adopted specification. The first form remains a -reasonable alternative if the extra namespace line proves more cumbersome than -the qualified string. - -Retaining keyed mappings only for profiles could avoid extending inheritance -to records, but would give authors different identity conventions by resource -type. The recommendation favors a consistent record model and includes the -necessary generic inheritance work explicitly. - -| Concern | Proposal 1 | Proposal 2 | -| --- | --- | --- | -| Author identity | Qualified YAML mapping key | Explicit namespace/local-ID fields | -| Prompt version | Nested mapping key | Field in each prompt record | -| Cross-source composition | Current ConfigKit | Opt-in record identity extension | -| Body conflicts and precedence | Mapping rules | Same mapping rules after tuple matching | -| Root `prompts:` wrapper | Required | Required | -| Provider model strings and execution references | Unchanged | Unchanged | -| Independent imported specification checks | Unavailable | Still unavailable | -| Main maintenance cost | PromptKit schema/API work | PromptKit work plus ConfigKit record lifecycle support | - -This is more than a syntax-only change, but remains bounded: it introduces one -generic representation for identified entries while preserving configuration -source ownership and ordinary merge policy. It does not introduce collection -installation, dependency resolution, namespace ownership, mounted sources, -arbitrary transforms, or a general-purpose merge strategy system. - -## Delivery And Validation - -If selected, agree the upstream ConfigKit record contract first, implement and -test it there, then adopt that capability in PromptKit's prospective schema. -PromptKit would decode final records, validate domain identities/settings, build -its ordinary execution indexes, and implement the already accepted scope and -resource-discovery behavior plus the proposed collection inventory. Bundled -catalog/profile removal remains the accepted direction. - -Migration must convert each old keyed resource into its chosen record identity, -flatten prompt-version entries, update any inheritance reference syntax, and -preserve provider model strings. Choose specification and software release -versions deliberately; do not silently reinterpret deployed configuration. - -The upstream acceptance cases should include: - -- Different tuples coexist; same local prompt names in different namespaces - never collide; different versions of one prompt remain separate. -- Matching tuples compose disjoint bodies but reject overlapping scalar/null/ - ordinary-sequence body fields, including equal values. -- Matching tuples overlay across tiers without deleting unrelated records. - Changing a tuple adds another record; `[]`, whole-path null, and ordinary - message sequences follow their distinct documented semantics. -- Missing or malformed identity fields and repeated tuples in one source fail - structurally; identity comparisons cannot collide through delimiter encoding. -- Composite inheritance resolves final relationships, preserves child identity, - rejects missing/cyclic parents, and retains declaring resource contexts. -- Matching, effective indexes, source positions, sensitivity, and provenance - remain consistent through imports, overrides, inheritance, and rendering. -- Unregistered configuration loads and ordinary sequence behavior are unchanged. -- Existing version-path protections remain intact; record `version` fields are - not mistaken for the protected root field. - -PromptKit acceptance should exercise the authoring examples, final identity -conversion, scoped selection, metadata inventory, and migrated references with -offline collaborators. The record composition and inheritance examples require -the proposed upstream extension; they are not executable supported workflows -on ConfigKit v0.7.1 today. Syntax checks and current-behavior probes can establish -the starting point, but cannot validate an unimplemented extension. - -Review verification on 2026-10-14: a temporary offline consumer of the local -ConfigKit checkout decoded the five examples without the new inheritance form, -confirmed that the composite `extends` example is rejected today, and confirmed -current sequence conflict/replacement behavior across peer and precedence layers. -Local documentation links and whitespace checks passed. The temporary consumer -and its module replacement are outside both repositories. - -This proposal remains for evaluation alongside proposal 1. The parent roadmap's -configuration decision remains open. Proposal 3 develops the alternative based -on source placement; independent collection specification checking remains open. diff --git a/docs/roadmap/configuration-collections-mounted-fragments.md b/docs/roadmap/configuration-collections-mounted-fragments.md index 2d33efd..50f0252 100644 --- a/docs/roadmap/configuration-collections-mounted-fragments.md +++ b/docs/roadmap/configuration-collections-mounted-fragments.md @@ -1,15 +1,15 @@ # Proposal 3: Collections With Mounted Configuration Fragments -Status: proposed PromptKit standard; not implemented in PromptKit. Required +Status: selected configuration direction; not implemented in PromptKit. Required ConfigKit capabilities are implemented on its development branch, reviewed at `e66c371` on 2026-10-16, but are not in PromptKit's selected v0.7.1 dependency. The recommended direction uses collection-local mapping keys, one installed definition per prompt, and an optional flat prompt `version` field. The latest review agrees on shared source checks using `IfPresent` and a distinct collection -`release_version` field; remaining PromptKit decisions are listed below. Compare -[proposal 1](configuration-collections-current-configkit.md) and -[proposal 2](configuration-collections-identified-records.md); the parent -[namespace roadmap](namespaces.md) owns the shared decisions. +`release_version` field; remaining PromptKit decisions are listed below. The +parent [namespace roadmap](namespaces.md) owns the shared decisions. Unselected +proposals 1 and 2 have been retired; their history and the separately captured +upstream request are recorded below. ## Recommendation @@ -25,8 +25,8 @@ keys after ConfigKit hands off the resolved configuration. There is one installed definition per qualified prompt ID. Its optional `version` field describes that definition; it does not create another identity -or select a merge strategy. This removes the need for proposal 2's identified -record sequences and for the current nested prompt-version mapping. +or select a merge strategy. This avoids identified record sequences and the +current nested prompt-version mapping. Placement belongs to ConfigKit. PromptKit must not parse, wrap, or rewrite each source itself, nor impose duplicate-namespace checks before composition. This @@ -241,8 +241,8 @@ To retain unqualified application resources, recommend optional root-level using the same definition shapes. They produce unqualified public IDs. Under this proposal, namespaced definitions belong under `collections`, not a second qualified-key spelling in those root maps. This avoids two configuration paths -producing the same public identity. This representation is a recommendation -for proposal 3, not a change to today's accepted format. +producing the same public identity. This representation belongs to the selected +future direction; it does not change today's implemented format. Stored references such as `default_profile`, profile `backend`, and smoke-test profile defaults remain exact public references. Nesting does not automatically @@ -272,10 +272,9 @@ is a simpler alternative but requires more consumer changes; settle the public API shape before implementation. Listings should identify one prompt per ID and expose the optional declared version separately from identity. -This intentionally supersedes multi-version preservation for this alternative. -Proposals 1 and 2 retain their earlier assumptions for comparison. The parent -roadmap's version-selection and listing language needs corresponding revision -if proposal 3 is adopted. +This deliberately replaces the earlier multi-version preservation assumption. +The selected direction identifies prompts by ID and exposes an optional version +label; the request-version and listing API details remain open below. ## ConfigKit Composition Boundary @@ -346,8 +345,8 @@ unsupported declarations through the ConfigKit checker. The handling of an absent main declaration remains an explicit decision below. Accept additional versions only when PromptKit actually supports their format semantics: accepting a header does not migrate its payload or independently validate a fragment's -complete schema. The three proposals are alternative candidate formats, not -interchangeable released meanings of specification version 1. +complete schema. The retired proposals were alternatives, not released formats +sharing specification version 1. The selected initial direction is `SourceVersionModeIfPresent`: @@ -424,25 +423,33 @@ historical source ownership, or proof of unchanged published contents. Operator overrides may change resources while retaining a release label. Engine construction captures definitions; edits require a replacement engine. -## Comparison And Migration +## Retired Alternatives And Upstream Request -| Concern | Proposal 1 | Proposal 2 | Proposal 3 | -| --- | --- | --- | --- | -| Author identity | Qualified mapping key | Namespace/local-ID fields | Local mapping key beneath a mounted collection | -| Prompt version | Required nested key | Required identity field | Optional descriptive field | -| Multiple installed versions per prompt | Supported | Supported | Not supported | -| Repeated resource wrapper in fragments | Required | Required | Omitted through placement | -| Composition machinery | Existing mappings | Identified record sequences | Existing mappings after placement | -| Upstream prerequisite | None beyond its original baseline | Proposed record composition and inheritance | Placement, relative imports, and shared source checks implemented in development | -| Cross-collection inheritance | Existing qualified sibling keys | Proposed tuple references | Requires a separate extension or authored flattening | -| Source specification checks as described | Main only | Main only | Shared policy; non-main declarations checked when present | +The unselected proposals were retired after the identified-record design was +captured for separate upstream consideration. Both original documents remain +available in PromptKit Git history at `b5866dd`: -Proposals 1 and 2 retain their original assumptions for historical comparison. -Proposal 3 is the recommended direction for the stated one-installed-prompt -requirement. Its authoring economy follows from the configuration hierarchy, -and it retains ordinary map composition. The tradeoffs are explicit assembly -destinations, changed inheritance scope, and a deliberate reduction of prompt -version selection to one installed definition. +```sh +git show b5866dd:docs/roadmap/configuration-collections-current-configkit.md +git show b5866dd:docs/roadmap/configuration-collections-identified-records.md +``` + +Proposal 1 used fully qualified mapping keys and the then-current ConfigKit +composition behavior. Proposal 2 used explicit identity fields in record +sequences and requested identity-based composition and inheritance. Neither is +an active PromptKit implementation option. The selected mounted-mapping design +meets the one-installed-prompt requirement with compact local keys and ordinary +mapping composition. + +Proposal 2's generic extension is preserved in the ConfigKit repository as +`docs/roadmap/promptkit-identified-records-feature-request.md`. It requests +explicit record-identity registration, composition and overlay by identity, +record inheritance, deterministic ordering, and coherent inspection. That +request is for upstream evaluation, not an accepted ConfigKit capability or a +prerequisite of this roadmap. Retirement does not resolve the six remaining +PromptKit decisions below. + +## Migration Migration must choose one installed definition for each former multi-version prompt, move any retained version into its optional field, and relocate @@ -524,7 +531,6 @@ remain before the PromptKit contract is complete: and migration examples. Direct mounted fragments remain a useful alternative for applications that already assemble sources themselves. -The parent roadmap still owns the overall configuration decision. Its older -version-selection and metadata examples describe earlier alternatives; adopting -this standard requires reconciling those details and updating current contracts -when implementation lands. +The parent roadmap records this selected direction. Resolve the remaining +PromptKit choices here and update current contracts when implementation lands; +retiring the alternatives does not authorize feature implementation. diff --git a/docs/roadmap/namespaces.md b/docs/roadmap/namespaces.md index 280fc17..6e292d4 100644 --- a/docs/roadmap/namespaces.md +++ b/docs/roadmap/namespaces.md @@ -3,9 +3,10 @@ Status: feature roadmap; not implemented. The reserved-slash naming convention, reference-resolution rules, decisions 1–3 (scope shape, validation, and integrated discovery filtering), and decision 4's move to application/operator-supplied -configuration are accepted target behavior. Collection metadata, inventory, and -specification-version integration remain pending in decision 5, subject to the -ConfigKit boundary. Exact Go names and option types remain delivery details. +configuration are accepted target behavior. Decision 5 selects mounted collections +and shared source-version checking; its remaining policy and API choices are +tracked in the collection roadmap, subject to the ConfigKit boundary. Exact Go +names and option types remain delivery details. ## Purpose @@ -82,8 +83,9 @@ A profile ID identifies execution settings. Its configured model value is still the identifier passed to the provider; qualifying the profile ID does not modify that value. Both example profiles may retain the configured model `google/gemma-4-31b-it`. Different profiles may select the same model with -different settings. Prompt versions also remain separate from namespaces and -continue to use the existing selection rules. +different settings. Prompt version labels remain separate from namespaces. The +selected collection format installs one definition per prompt ID; optional +request-version handling remains a decision in the collection roadmap. Retain unqualified and dotted IDs. Existing slash-containing IDs need review: those with one slash and nonempty components become qualified identities, while @@ -135,8 +137,8 @@ The accepted resolution rules, independent of the final scope API, are: Keep qualification consistent across execution, preparation, request validation, prompt/profile inspection, and applicable smoke-test selections. Namespace -selection must not change request override precedence, prompt version selection, -or provider model strings. +selection must not change request override precedence, the chosen request-version +semantics, or provider model strings. ### Local And Qualified References In One Operation @@ -288,11 +290,11 @@ follow the eventual decision 5: and all-namespaces filters override that default for the current listing only. - A valid namespace with no matches produces an empty listing. Namespace filtering respects resource type and exact namespace boundaries. -- Existing exact-ID calls using valid IDs, intentional overlays, and prompt - versions retain their behavior. Migrated catalog references resolve to their - intended resources without collisions. -- Listings preserve full IDs and separate prompt versions. Qualified results - round-trip through either engine or view; unqualified results round-trip +- Exact-ID calls using valid IDs and intentional overlays retain their behavior. + Migrated catalog references resolve without collisions; the collection roadmap + owns migration to one installed prompt and optional version labels. +- Listings preserve full IDs and separate optional prompt version labels. + Qualified results round-trip through either engine or view; unqualified results round-trip through the engine without a corresponding scope. - Representative validation, inspection, execution, and smoke-test paths use the same qualification rules without duplicating every test at every layer. @@ -410,9 +412,10 @@ with no matching resources returns an empty listing. Represent default, named, unqualified-only, and all-namespaces selections distinctly in the API; do not overload an empty string to mean several of them. -Return full IDs, retaining prompt versions as separate identity fields. Do not -invent a named namespace such as `default` for unqualified resources. Namespace -enumeration excludes that unnamed group. Use deterministic ordering consistent +Return full IDs with optional prompt version labels separately; the full ID +identifies the installed prompt. Do not invent a named namespace such as `default` +for unqualified resources. Namespace enumeration excludes that unnamed group. +Use deterministic ordering consistent with existing listing contracts. Qualified result IDs can be passed unchanged to either scoped or unscoped @@ -485,89 +488,35 @@ dependencies instead. ### 5. Collection Metadata And Specification Versioning (Open) -[Proposal 1: current ConfigKit](configuration-collections-current-configkit.md) -develops a concrete configuration standard for the existing composition rules. -[Proposal 2: identified records](configuration-collections-identified-records.md) -uses an opt-in upstream extension for identity-based record composition and -inheritance. [Proposal 3: mounted fragments](configuration-collections-mounted-fragments.md) -uses explicit upstream source placement and collection-local mapping keys, -with one installed definition per prompt and an optional flat version field. -Proposal 3 now targets implemented ConfigKit development-branch capabilities, -including relative imports and shared source-version checks with `IfPresent`. It -uses `release_version` for collection metadata; proposals 1 and 2 preserve their -earlier baselines for comparison. This overall decision remains open. Proposal 3 -deliberately revises the version-selection, metadata, and listing assumptions -elsewhere in this roadmap if that alternative is adopted. Its remaining questions -are PromptKit policy/API choices, not pending requests for those ConfigKit features. +**Selected direction: [mounted collections](configuration-collections-mounted-fragments.md).** +Proposal 3 is the active configuration roadmap. It uses collection-local mapping +keys, one installed definition per prompt, and an optional flat prompt version. +Input destinations, relative imports, and shared source-version checks are +implemented in ConfigKit's reviewed development branch. PromptKit still needs +to adopt a suitable dependency release and implement its new schema. -**Desired capability:** describe collection namespace and release version in -configuration and expose an API through which downstream applications can list -effective collection declarations captured by an engine. A collection release -version is distinct from an individual prompt version and from the PromptKit -software version. Use top-level `version: 1` for PromptKit specification version -1, following ConfigKit's version mechanism, rather than introducing a -`promptkit_spec` field. The ownership and placement of that version declaration -across multiple sources remain part of this open decision. +Use shared specification checking with `IfPresent` and distinct collection +`release_version` metadata. Collection entries can describe their layout through +relative imports; applications select their sources and namespaces. PromptKit +interprets the final collection/resource keys as qualified IDs after ConfigKit's +handoff. It adds no manifest pre-parser, source-level namespace ownership rule, +or history-based validation pass. Stored references remain exact public IDs. -The initially discussed root manifest contained `collection.namespace` and -`collection.version`. That shape and a standard manifest filename are not -settled. In particular, the proposal to load/check each manifest separately in -PromptKit before composing definitions is withdrawn. PromptKit must respect the -ConfigKit boundary described above, including for version checks and duplicate -declarations. +Proposals 1 and 2 were not selected and have been retired. Their original +contents and the separately preserved ConfigKit identified-record request are +recorded in the collection roadmap's +[retirement note](configuration-collections-mounted-fragments.md#retired-alternatives-and-upstream-request). +The record-sequence request is independent future upstream work and does not +block the selected mapping design. -ConfigKit v0.7.1's layered-loading contract checks the configured application -version path on the main input only. Underlay roots cannot claim that path, -and imported fragments cannot independently declare it. ConfigKit supplies the -version mechanism while the application defines supported specification values; -this does not give PromptKit permission to implement an independent collection -assembly or compatibility-checking pass. +The collection roadmap owns the candidate schema, examples, version policies, +metadata inventory, and migration requirements. Inventory describes effective +collection declarations captured by the engine, not historical manifests or +proof of unchanged published releases. Source explanation remains ConfigKit's +inspection concern. -**Recommended starting point, pending decision: ordinary ConfigKit composition -with collection metadata in final effective values.** For example, the main -configuration could own `version: 1`, with a namespace-keyed collection mapping: - -```yaml -version: 1 -collections: - openrouter: - version: "2026.10.13" - weatherreporter: - version: "2.4.0" -``` - -This is a candidate shape, not an implemented or accepted schema. Other sources -could contribute to `collections` without claiming the main version field. -ConfigKit would decide whether contributions conflict or combine; PromptKit -would interpret and validate only the final metadata. A namespace key would -identify one effective entry without requiring a source-level uniqueness rule. -It would not automatically qualify definition keys or stored references. - -This approach reuses the existing composition contract and avoids a parallel -manifest loader. Its limitation is that it does not independently check a -specification declaration for each imported collection. An effective declared -release version also does not prove that every resource still matches that -release after operator overrides. - -**Alternative: add collection/import compatibility support within ConfigKit -before adopting independently versioned collection roots.** If every collection -must declare its own specification version, design that capability in ConfigKit, -including how versions and metadata interact with imports and layers. PromptKit -would consume its resulting handoff and diagnostics. This could provide useful -per-collection compatibility checks without violating ownership, but it expands -the work into ConfigKit and requires a supported contract there before PromptKit -can depend on it. No ConfigKit change is selected by this roadmap yet. - -Under either approach, the inventory should describe effective collection -metadata captured at engine construction, not reconstruct a historical list of -loaded manifests. Source contributions and explanations remain ConfigKit -inspection concerns. Inventory should not reread installed files or claim that -declared versions prove unmodified published contents. Namespace enumeration -from resource IDs remains independent of this metadata API. - -**Pending question:** is ordinary composed collection metadata with one main -specification declaration sufficient, or are independently version-checked -collection roots essential enough to warrant ConfigKit work? Settle that before -finalizing metadata schema, root-file conventions, inventory API values, or -collection compatibility rules. Removal of bundled catalogs and built-in -profiles remains accepted in either case. +**Still open:** the [six remaining PromptKit decisions](configuration-collections-mounted-fragments.md#remaining-promptkit-decisions) +cover main declaration requirements, exposing stricter checking, resources named +`version`, request-version assertions, cross-collection inheritance, and consumer +APIs/packaging. Selecting proposal 3 and retiring its alternatives does not settle +those choices. Removal of bundled catalogs and built-in profiles remains accepted.