Explain namespace design recommendations and alternatives

This commit is contained in:
2026-10-13 21:33:21 +00:00
parent a0ec67c256
commit cf997c2034

View File

@@ -88,10 +88,16 @@ sketch illustrates the consumer experience only; it does not settle a method
name, return type, error behavior, or final signature:
```go
weather := engine.InNamespace("weatherreporter")
// Operations through weather can select the local prompt "summarize.alerts".
weather, err := engine.WithNamespaces(Namespaces{
Prompt: "weatherreporter",
Profile: "openrouter",
})
// Handle err, then use local prompt and profile names through weather.
```
This sketch follows the recommendation in open decision 1; these declarations
do not exist yet.
The view would share the engine's captured configuration, clients, and execution
machinery. Selecting a namespace would not rebuild the engine or duplicate its
backend capacity accounting. Consumers could use different views concurrently
@@ -260,21 +266,165 @@ the selected API contract:
- Representative validation, inspection, execution, and smoke-test paths use
the same qualification rules without duplicating every test at every layer.
## Open Decisions
## Open Decisions And Recommendations
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?
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?
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?
Each recommendation below is a proposal for the next decision, not an accepted
contract. Alternatives preserve the settled naming and resolution rules.
### 1. Public Scope Shape
**Recommended: an immutable view with independent resource scopes.** Provide one
engine operation that accepts a small value with prompt, profile, and backend
namespace fields and returns a scoped view or an error. The illustrative
`WithNamespaces` and `Namespaces` names above are provisional. Empty fields mean
no scope for that resource type. The view captures the value and delegates to
the same engine; it does not expose a mutable namespace setting. Apply the
prompt field to caller-supplied prompt IDs, the profile field to profile IDs,
and the backend field to backend IDs wherever those selections are supported.
Qualified references bypass the corresponding field.
This directly serves the select-once workflow and the common mixed case of an
application prompt namespace with a provider profile namespace. It also keeps
scope out of stored configuration and makes concurrent use independent of call
order. The cost is an additional facade surface whose supported operations must
remain consistent with the engine. Keep qualification shared rather than
duplicating selection logic in each wrapper.
Initially omit an ambiguous one-string `InNamespace` shorthand. Repeating the
same namespace in several fields happens once when creating a view and states
exactly which resource types it affects. A convenience operation can follow if
that repetition is a demonstrated burden.
**Alternative: one namespace per immutable view, applied to all resource
types.** A one-string operation would scope every unqualified prompt, profile,
and backend selection; callers would use qualified references for resources in
other namespaces. This is smaller and reads naturally for self-contained
application collections. It is less convenient when prompts and profiles
habitually come from different namespaces, because profile overrides would
repeatedly need qualification. Prefer it if consumers primarily use prompts'
configured defaults and rarely select profiles themselves.
**Alternative: explicit scope values supplied per operation.** Add scope to
request values and appropriate inspection/listing options instead of returning
a view. This makes every invocation self-contained and suits applications that
choose a different scope for every request. It spreads scope through more call
sites and API shapes, and consumers would need their own reusable wrapper to
achieve the requested select-once experience. The immutable view is therefore
the better default for the use case discussed so far.
### 2. Scope Validation
**Recommended: validate syntax when creating the view; resolve existence when
an operation selects a resource.** In the recommended scope value, the empty
string means no scope. Reject a nonempty namespace containing `/` or consisting
only of whitespace. Otherwise preserve its exact spelling, with no trimming,
case folding, or additional character whitelist. This distinguishes omission
from an unusable namespace without inventing normalization rules. Report invalid
scope construction through PromptKit's existing public error conventions.
Allow a well-formed namespace even when it has no current members. Its scoped
listing would be empty, and selection of a missing local resource would produce
the ordinary lookup error. Qualified selections would remain usable regardless
of the view's default scope. An empty optional request ID continues to mean
omission under that operation's existing contract; it is never qualified.
This keeps scope as a naming context and supports uniform application setup
across installations with different library contents. It also avoids treating
successful scope construction as validation of a prompt or execution profile.
The tradeoff is that a misspelled but syntactically valid namespace is detected
only when listed or used, rather than during view construction.
**Alternative: require each selected namespace to have resources of its
corresponding type when creating the view.** For an immutable assembled engine,
this can catch spelling mistakes immediately and gives startup checks useful
feedback without attempting execution. However, it rejects empty optional
collections and a view intended to use qualified references outside its default
namespace. A namespace having one member also does not establish that the
particular required prompt/profile exists. Prefer this approach only if eager
inventory validation is itself an intended consumer contract; it should not be
an accidental consequence of implementing scope creation.
### 3. Discovery
**Recommended: namespace enumeration and resource listings that retain full
IDs.** Enumerate the distinct named namespaces present in final effective
prompts, profiles, and backends. Allow filtering that enumeration by resource
type so a prompt picker need not show profile-only namespaces. Provide scoped
listings for the supported resource types, adding a backend inventory surface
as part of this work if needed. Keep the existing unscoped listing signatures
and their all-resource behavior.
A scoped listing filters by the selected scope for that resource type and
returns full IDs, retaining prompt versions as separate identity fields.
Without a scope, it lists all resources of that type. Unqualified resources
remain in unscoped listings; provide an explicit unqualified-only listing filter
so callers can distinguish that group from all namespaces. Do not invent a
named namespace such as `default` for those IDs. Namespace enumeration excludes
that unnamed group. Use deterministic ordering consistent with existing listing
contracts.
Full IDs can be passed unchanged to either scoped or unscoped operations, which
avoids double qualification and preserves identity in logs and user interfaces.
A small public name-splitting helper can supply namespace/local components for
display without requiring applications to duplicate parsing rules. This keeps
existing identity shapes useful and avoids introducing collection metadata just
to support filtering. The tradeoff is that consumers wanting separate display
fields perform that explicit decomposition.
**Alternative: add a richer inventory API returning full ID, namespace, local
name, resource type, and prompt version where applicable.** Preserve existing
list methods and expose the structured form separately. This is attractive for
Scriptorium-style library browsers: grouping and display require no parsing,
and one inventory operation can cover all resource kinds. It creates another
public representation and overlaps existing listing APIs, so its value should
justify that maintenance. Prefer it if downstream clients routinely need a
combined catalog view rather than a resource picker or namespace filter. In
either approach, the full ID remains the authoritative selection value.
### 4. Catalog Migration
**Recommended: coordinate the grammar change with adoption of provider
namespaces for ordinary maintained catalog profiles.** Use provider namespaces
such as `openrouter` and `rakestrawhome`, with descriptive slash-free local
profile names. Use `google.gemma-4-31b-it` for the illustrative model-based
profile name; profiles with distinct execution settings need distinct local
names even when they select the same model. Assign every renamed profile an
explicit old-to-new mapping after auditing the catalog, including valid old IDs
that currently encode a provider prefix differently. Do not infer mappings by
blind punctuation replacement.
Retain the two unqualified built-in profile names explicitly guaranteed by the
release policy. Keep existing valid backend IDs unless there is a concrete
collision or organizational reason to rename them; provider-qualified profiles
can reference those exact backend IDs without duplicating backend identity or
capacity accounting. Application-owned prompt libraries choose their own
namespace and migration mappings rather than being silently rewritten by
PromptKit.
Prepare catalog data, affected references, consumer migration instructions, and
the PromptKit grammar change as coordinated work. Select compatible catalog
revisions for the PromptKit release and follow each repository's release rules.
Choose a PromptKit version permitted to break the format contract: a minor
release before v1, or a major release at/after v1, under the current release
policy. Exact versions and actual old-to-new mappings require the catalog audit;
this recommendation does not claim those mappings have already been established.
This makes the initial feature useful with maintained provider catalogs and
concentrates consumer migration into one planned transition. Retaining the
explicitly supported unqualified profile names preserves their selected
contract. The cost is a broader coordinated change than grammar enforcement
alone, including renames of otherwise valid ordinary profile IDs.
**Alternative: migrate only IDs that violate the new grammar, and defer broader
catalog naming changes.** Keep all other exact IDs, including valid one-slash
IDs whose first component would now be their namespace. Ship scope support and
let new libraries adopt provider/application namespaces incrementally. This
reduces immediate consumer changes and makes the format update easier to review
and release independently. It leaves existing catalogs with inconsistent
grouping, may expose model-vendor rather than provider namespaces, and can
require another migration to realize the intended provider shorthand. Prefer
it if the audit reveals that broad catalog renaming would impose substantial
downstream disruption relative to current demand.
The delimiter, two-component qualified grammar, syntax-based resolution, and
acceptance of the required breaking migration are settled. Resolve the remaining