From a0ec67c256cd441e6881a4469917599b96fd9b7e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 13 Oct 2026 21:29:36 +0000 Subject: [PATCH] Reserve slash for namespace-qualified identifiers --- docs/roadmap/namespaces.md | 165 +++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 63 deletions(-) diff --git a/docs/roadmap/namespaces.md b/docs/roadmap/namespaces.md index b734065..14b8bcc 100644 --- a/docs/roadmap/namespaces.md +++ b/docs/roadmap/namespaces.md @@ -1,8 +1,8 @@ # Namespaces And Scoped Resource Lookup -Status: proposed feature roadmap; not implemented. The consumer need is -established, but the API shape and naming rules below remain proposals unless -identified as existing behavior. +Status: feature roadmap; not implemented. The reserved-slash naming convention +and reference-resolution rules are accepted target behavior. The public scope +API, discovery surface, and migration details remain open as identified below. ## Purpose @@ -43,19 +43,25 @@ composition, and inheritance to ConfigKit. This proposal adds interpretation of consumer-supplied resource names against the final effective configuration, without a second source-composition pass. -## Proposed Identity Convention +## Accepted Identity Convention -Use `namespace/local-name` as the qualified identifier. The first slash is the -namespace boundary; the rest of the local name is literal and may contain dots -or additional slashes. This is the recommended convention, not a settled -format change. +Reserve `/` exclusively as the namespace separator in PromptKit prompt, profile, +and backend identifiers and references. A qualified identifier has exactly two +nonempty components: `namespace/local-name`. Neither component can contain `/`. +Dots remain available within local names. An unqualified identifier has no slash +and remains valid under the existing nonblank-ID rule. + +Reject resource identifiers or supplied references with multiple slashes or an +empty qualified component, such as `a/b/c`, `/name`, and `namespace/`. These +rules do not apply to provider model values, endpoints, resource paths, or prompt +versions. Preserve exact spelling; do not silently trim or rewrite IDs. | Resource | Namespace | Local name | Qualified ID | | --- | --- | --- | --- | | Prompt | `weatherreporter` | `summarize.alerts` | `weatherreporter/summarize.alerts` | | Prompt | `homewatch` | `summarize.alerts` | `homewatch/summarize.alerts` | -| Profile | `openrouter` | `google/gemma-4-31b-it` | `openrouter/google/gemma-4-31b-it` | -| Profile | `rakestrawhome` | `google/gemma-4-31b-it` | `rakestrawhome/google/gemma-4-31b-it` | +| Profile | `openrouter` | `google.gemma-4-31b-it` | `openrouter/google.gemma-4-31b-it` | +| Profile | `rakestrawhome` | `google.gemma-4-31b-it` | `rakestrawhome/google.gemma-4-31b-it` | Prompt, profile, and backend identities remain separate resource types. The same namespace can contain all three, and resources in it may come from @@ -64,14 +70,16 @@ package, provider model identifier, or security boundary. 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. Different profiles may select the same model with +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. -Retain existing exact IDs, including unqualified and dotted names. Before -formalizing namespace discovery, audit slash-containing IDs in maintained -catalogs and representative consumer configurations: interpreting their first -component as a namespace may affect grouping even when exact lookup is unchanged. +Retain unqualified and dotted IDs. Existing slash-containing IDs need review: +those with one slash and nonempty components become qualified identities, while +those outside the new grammar require migration. This intentional format break +is accepted in favor of unambiguous resolution; the migration work is described +below. ## Proposed Consumer Scope @@ -89,13 +97,15 @@ machinery. Selecting a namespace would not rebuild the engine or duplicate its backend capacity accounting. Consumers could use different views concurrently without changing a shared current-namespace setting. -The proposed resolution rules are: +The accepted resolution rules, independent of the final scope API, are: -1. A supplied local name is qualified using the selected scope for its resource - type, then looked up exactly. +1. A supplied name without a slash is qualified using the selected scope for its + resource type, then looked up exactly. Without that scope, it is looked up as + an exact unqualified ID. 2. A missing scoped resource does not trigger a search in other namespaces or among unqualified IDs. Loading another collection cannot redirect lookup. -3. An operation without a selected scope retains existing exact-ID behavior. +3. A valid supplied name containing one slash is fully qualified and is looked + up exactly, regardless of scope. Malformed resource references are rejected. 4. Scope applies to caller-supplied resource names. Stored references, including prompt default profiles, profile backends, inheritance references, and backend smoke-test default profiles, retain their existing exact meaning. They are @@ -112,19 +122,21 @@ prompt/profile inspection, and applicable smoke-test selections. Namespace selection must not change request override precedence, prompt version selection, or provider model strings. -### Local Names Versus Exact IDs +### Local And Qualified References In One Operation -The presence of a slash cannot distinguish local and qualified references: -`google/gemma-4-31b-it` is a legitimate local profile name under `openrouter`. -Do not decide whether to qualify a name by checking whether the unqualified -candidate happens to exist; that would make resolution depend on loaded content. +Syntax alone distinguishes local and qualified references. Do not decide whether +to qualify a name by checking which candidates exist; that would make resolution +depend on loaded content. -The recommended initial approach is that a scoped resource field consistently -accepts a local name, while the original engine remains available for exact IDs. -Under that approach, even a string that looks qualified is treated as local -when passed through the corresponding scope. An explicit per-reference exact-ID -mechanism is an alternative if mixed local and qualified selections in one -request justify it. Settle this before defining the public API. +Within a `weatherreporter` prompt scope, `summarize.alerts` resolves only to +`weatherreporter/summarize.alerts`, while `homewatch/summarize.alerts` explicitly +selects that other library's prompt. A qualified profile override similarly +bypasses the profile scope. Scoped operations accept both forms without a +separate reference type or requiring a return to the original engine for +cross-namespace access. + +The original engine remains the way to select an exact unqualified ID without +applying a scope. No escape syntax for unqualified IDs is introduced here. ### Separate Resource Scopes @@ -136,8 +148,9 @@ profile scope because the stored reference is already exact. Independent scopes are recommended where the consumer needs shorthand, but the scope options and the meaning of a convenience `InNamespace` operation are -still open. Do not silently apply a prompt scope to an otherwise exact profile -override. Include any directly supplied backend selection in this decision. +still open. Define which scopes apply to unqualified names in each request +field; qualified references always bypass them. Include any directly supplied +backend selection in this decision. ## Discovery And Collection Organization @@ -151,10 +164,9 @@ full identities, or another explicit shape. A caller must be able to tell how to pass a listed name back to a scoped operation without double qualification. Retain the existing unscoped listing contracts. -If namespace membership is derived from the recommended prefix convention, -match the complete namespace boundary: `weather` must not include -`weatherreporter/...`. Additional slashes within the local name do not imply -recursive namespace traversal. +Derive namespace membership from the qualified identifier's namespace component: +`weather` must not include `weatherreporter/...`. Nested slash-separated +namespaces are outside the accepted grammar. The initial proposal does not require a collection manifest. Titles, descriptions, and other collection metadata can be considered if consumers @@ -172,12 +184,30 @@ introduce implicit qualification of definition keys, mounting under caller-chose prefixes, or rewriting of stored references as part of consumer scope. Those would be separate configuration-design work. -Existing unscoped engine calls and catalog identifiers must continue to work. -Adoption of the new convention by maintained catalogs needs an explicit -migration decision. Renaming a profile or backend can affect configured -references; duplicating a backend under another ID can also separate capacity -accounting. Do not treat blanket aliases or duplicate catalog entries as a -cost-free compatibility mechanism. +Existing unscoped exact lookup remains available for IDs valid under the new +grammar. Compatibility with arbitrary slash-containing resource IDs is +intentionally broken. The migration must: + +- Audit maintained catalogs and representative consumer definitions for invalid + IDs and for valid one-slash IDs whose namespace meaning needs review. +- Choose explicit old-to-new mappings and check for collisions. Do not + automatically replace slashes with dots: distinct existing IDs could collapse + to the same new identity. +- Update renamed keys and their references together, including inheritance, + prompt default profiles, profile backend references, backend smoke-test + defaults, and affected examples and consumer request IDs. +- Keep provider model strings unchanged. Renaming a profile does not rename + the upstream model. +- Document consumer action and coordinate the PromptKit format change with + catalog adoption under the [release policy](../policy/release.md). Its catalog + profile-data exception does not cover this general format/API behavior change; + account for its explicitly retained built-in profile names when selecting + migrations. + +Renaming a backend changes its identity; duplicating it under another ID can +separate capacity accounting. Do not use blanket aliases or duplicate catalog +entries as an automatic compatibility mechanism. Exact release versions and +catalog mappings remain implementation-planning work. The [architecture policy](../policy/architecture.md) continues to assign CLI syntax, flags, and application policy to consumers such as Scriptorium. PromptKit @@ -196,8 +226,9 @@ if a concrete consumer need emerges. ## Delivery Outline -1. Settle the open naming and API decisions below and audit existing identifier - usage. Record any catalog migration as explicit coordinated work. +1. Settle the open API decisions below and audit existing identifier usage + against the accepted grammar. Record explicit mappings and coordinated + migration work. 2. Implement the smallest public scope surface with shared name qualification and existing engine collaborators. Cover supported operations consistently. 3. Add the selected discovery behavior and representative consumer examples. @@ -206,39 +237,47 @@ if a concrete consumer need emerges. format reference, consumer guide, and relevant internal documentation as behavior lands; retire this roadmap when its work is complete. -Suggested acceptance cases, subject to the selected API contract: +Acceptance cases for the settled rules, with scope/discovery details subject to +the selected API contract: - Two prompt scopes resolve the same local name to their respective prompts; a missing name never resolves from the other scope or an unqualified entry. -- Two provider profile scopes preserve a slash-containing local name and select - different profiles without changing the configured provider model value. +- Two provider profile scopes resolve the same local name, such as + `google.gemma-4-31b-it`, to different profiles without changing the configured + provider model value `google/gemma-4-31b-it`. +- A qualified reference bypasses the selected scope without double qualification; + adding another collection does not change local or qualified resolution. +- Multiple slashes and empty qualified components are rejected in resource IDs + and references, while provider model values retain their existing syntax. - Prompt shorthand and a profile override use their intended scopes, while stored default references and omitted selections retain their meaning. - Scoped views coexist concurrently and share backend capacity with ordinary calls on the underlying engine. -- Existing exact-ID calls, intentional overlays, and prompt versions retain - their behavior. +- 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 and reported identities support the chosen local/full-ID round trip. - Representative validation, inspection, execution, and smoke-test paths use the same qualification rules without duplicating every test at every layer. ## Open Decisions -1. **Naming convention:** adopt the first-slash boundary, or select another - separator? What namespace syntax is needed without narrowing existing IDs? -2. **Public scope shape:** immutable view, scope options, or another small +1. **Public scope shape:** immutable view, scope options, or another small surface? Which resource scopes can be selected independently, and what does a one-namespace convenience operation mean? -3. **Exact access within scoped requests:** use the original engine for exact - selections, or provide an explicit per-reference distinction? -4. **Scope validation:** when should an empty, malformed, or currently absent - namespace produce an error? Distinguish syntax from resource existence and - do not accidentally change omitted-ID defaults. -5. **Discovery:** which listing/filtering operations are needed, how are legacy +2. **Scope validation:** how does the scope API represent no scope, report an + invalid namespace selection, and handle a well-formed but currently absent + namespace? Apply the accepted separator rules, distinguish syntax from + existence, and preserve omitted-ID defaults. Do not add case folding or other + character restrictions without a separate decision. +3. **Discovery:** which listing/filtering operations are needed, how are legacy IDs grouped, and how are local and full identities represented? -6. **Catalog adoption:** which maintained IDs, if any, should change, and what - compatibility and release plan would accompany those changes? +4. **Catalog migration:** what exact old-to-new mappings and coordinated release + plan will implement the accepted breaking change, and which otherwise valid + IDs should additionally adopt provider/application namespaces? -Resolve these choices before treating the proposed mechanics as implementation -requirements. The central requirement is already clear: consumers select a -scope once and use local names predictably within an assembled library. +The delimiter, two-component qualified grammar, syntax-based resolution, and +acceptance of the required breaking migration are settled. Resolve the remaining +API and delivery choices around that foundation: consumers select a scope once +and use local or explicitly qualified names predictably within an assembled +library.