Index and validate identified resources

This commit is contained in:
2026-11-02 03:55:28 +00:00
parent b7565affe5
commit 8e8f61f53f
4 changed files with 68 additions and 39 deletions

View File

@@ -299,6 +299,13 @@ Validation: target tests cover a root resource, namespaced resources sharing a
local ID, and partial-profile completion. Upstream duplicates must fail before
an execution map can silently overwrite a record.
Completion: final backend, profile, and prompt IDs and references are validated
at list-entry paths; backend and profile runtime indexes use full identities.
Added root and independent namespace target coverage and converted the strict
duplicate fixture to identified lists. The focused tests remain deferred because
prompt materialization and remaining configuration fixtures have not yet been
migrated. Formatting and `git diff --check` passed.
## Stage 6: Materialize Prompts From Effective List Entries
Scope: prompt resolution/capture in `internal/configuration/prompts.go` and

View File

@@ -194,8 +194,8 @@ func indexedResourceID(namespace, localKey string) string {
func indexedBackends(config *document) map[string]backendConfig {
backends := make(map[string]backendConfig)
for _, resources := range resourceSets(config) {
for localKey, definition := range resources.backends {
backends[indexedResourceID(resources.namespace, localKey)] = definition
for _, definition := range resources.backends {
backends[indexedResourceID(resources.namespace, definition.ID)] = definition
}
}
return backends
@@ -204,8 +204,8 @@ func indexedBackends(config *document) map[string]backendConfig {
func indexedProfiles(config *document) map[string]profileConfig {
profiles := make(map[string]profileConfig)
for _, resources := range resourceSets(config) {
for localKey, definition := range resources.profiles {
profiles[indexedResourceID(resources.namespace, localKey)] = definition
for _, definition := range resources.profiles {
profiles[indexedResourceID(resources.namespace, definition.ID)] = definition
}
}
return profiles
@@ -476,16 +476,15 @@ func validateEffective(config *document, validation *configkit.Validation) {
if resources.isCollection && !domain.IsValidResourceNamespace(resources.namespace) {
validation.Error(configkit.Keys("collections", resources.namespace), "collection namespace must be nonblank and contain no slash")
}
for localKey := range resources.backends {
backendIDs[indexedResourceID(resources.namespace, localKey)] = struct{}{}
for _, backend := range resources.backends {
backendIDs[indexedResourceID(resources.namespace, backend.ID)] = struct{}{}
}
}
for _, resources := range sets {
for _, id := range sortedKeys(resources.backends) {
backend := resources.backends[id]
base := resources.bases.backends.Key(id)
if !domain.IsValidLocalResourceKey(id) {
validation.Error(base, "backend key must be a nonblank local key without a slash")
for index, backend := range resources.backends {
base := resources.bases.backends.Index(index)
if !domain.IsValidLocalResourceKey(backend.ID) {
validation.Error(base.Key("id"), "backend ID must be a nonblank local key without a slash")
}
if backend.Endpoint == nil || *backend.Endpoint == "" {
validation.Error(base.Key("endpoint"), "endpoint is required")
@@ -526,11 +525,10 @@ func validateEffective(config *document, validation *configkit.Validation) {
}
}
}
for _, id := range sortedKeys(resources.profiles) {
profile := resources.profiles[id]
base := resources.bases.profiles.Key(id)
if !domain.IsValidLocalResourceKey(id) {
validation.Error(base, "profile key must be a nonblank local key without a slash")
for index, profile := range resources.profiles {
base := resources.bases.profiles.Index(index)
if !domain.IsValidLocalResourceKey(profile.ID) {
validation.Error(base.Key("id"), "profile ID must be a nonblank local key without a slash")
}
if profile.Backend != nil && *profile.Backend != "" {
if !domain.IsValidResourceID(*profile.Backend) {
@@ -564,11 +562,10 @@ func validateEffective(config *document, validation *configkit.Validation) {
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
}
for _, id := range sortedKeys(resources.prompts) {
prompt := resources.prompts[id]
base := resources.bases.prompts.Key(id)
if !domain.IsValidLocalResourceKey(id) {
validation.Error(base, "prompt key must be a nonblank local key without a slash")
for index, prompt := range resources.prompts {
base := resources.bases.prompts.Index(index)
if !domain.IsValidLocalResourceKey(prompt.ID) {
validation.Error(base.Key("id"), "prompt ID must be a nonblank local key without a slash")
}
if prompt.DefaultProfile != nil && *prompt.DefaultProfile != "" && !domain.IsValidResourceID(*prompt.DefaultProfile) {
validation.Error(base.Key("default_profile"), "default profile reference is malformed")

View File

@@ -440,8 +440,8 @@ func TestLoadCapturesProfilePresence(t *testing.T) {
func TestLoadRejectsStrictGroupConflict(t *testing.T) {
_, err := load(configkit.Input{Source: configkit.NoSource()}, []configkit.Underlay{{Inputs: []configkit.Input{
mapping("first", map[string]any{"profiles": map[string]any{"shared": map[string]any{"model": "one"}}}),
mapping("second", map[string]any{"profiles": map[string]any{"shared": map[string]any{"model": "one"}}}),
mapping("first", map[string]any{"profiles": []any{map[string]any{"id": "shared", "model": "one"}}}),
mapping("second", map[string]any{"profiles": []any{map[string]any{"id": "shared", "model": "one"}}}),
}}})
var loadError *configkit.LoadError
if !errors.As(err, &loadError) {

View File

@@ -15,30 +15,55 @@ import (
profilepkg "gitea.maximumdirect.net/eric/promptkit/internal/profile"
)
func TestLoadIndexesIdentifiedTargets(t *testing.T) {
values := map[string]any{
"backends": []any{map[string]any{"id": "local", "endpoint": "https://root.example/v1"}},
"profiles": []any{map[string]any{"id": "partial", "backend": "local"}},
"collections": map[string]any{},
}
collections := values["collections"].(map[string]any)
for _, namespace := range []string{"north", "south"} {
collections[namespace] = map[string]any{
"backends": []any{map[string]any{"id": "local", "endpoint": "https://" + namespace + ".example/v1"}},
"profiles": []any{map[string]any{"id": "partial", "backend": namespace + "/local"}},
}
}
state, err := load(mapping("identified targets", values), nil)
if err != nil {
t.Fatal(err)
}
for id, backendID := range map[string]string{"partial": "local", "north/partial": "north/local", "south/partial": "south/local"} {
profile, err := state.GetProfile(context.Background(), id)
if err != nil || profile.ID != id || profile.ResolvedTarget == nil || profile.ResolvedTarget.Model != "" || profile.ResolvedTarget.BackendID != backendID {
t.Fatalf("partial profile %q = %+v, %v", id, profile, err)
}
}
}
func TestLoadBuildsEffectiveTargetsAfterInheritance(t *testing.T) {
state, err := load(mapping("effective-targets", map[string]any{
"backends": map[string]any{
"first": map[string]any{"endpoint": "https://first.example/v1", "api_key_env": "FIRST_KEY",
"backends": []any{
map[string]any{"id": "first", "endpoint": "https://first.example/v1", "api_key_env": "FIRST_KEY",
"extra_params": map[string]any{"source": "first", "nested": map[string]any{"old": true}}},
"second": map[string]any{"endpoint": "https://second.example/v1", "api_key_env": "SECOND_KEY",
map[string]any{"id": "second", "endpoint": "https://second.example/v1", "api_key_env": "SECOND_KEY",
"concurrency_limit": 2, "queue_capacity": 0,
"extra_params": map[string]any{"source": "second", "nested": map[string]any{"backend": true}}},
},
"profiles": map[string]any{
"base": map[string]any{"backend": "first", "model": "model", "temperature": 0.8,
"profiles": []any{
map[string]any{"id": "base", "backend": "first", "model": "model", "temperature": 0.8,
"top_p": 0.9, "max_tokens": 100, "timeout_seconds": 30, "api_key_required": true,
"extra_params": map[string]any{"nested": map[string]any{"profile": true}}},
"child": map[string]any{"extends": "base", "backend": "second", "temperature": 0.0,
map[string]any{"id": "child", "extends": map[string]any{"id": "base"}, "backend": "second", "temperature": 0.0,
"top_p": nil, "max_tokens": 0, "timeout_seconds": nil, "api_key_env": nil,
"api_key_required": false,
"extra_params": map[string]any{"nested": map[string]any{"child": nil}}},
"direct-key": map[string]any{"backend": "second", "api_key_required": true},
"named-key": map[string]any{"backend": "second", "api_key_required": true, "api_key_env": "CUSTOM_KEY"},
"no-provider-map": map[string]any{"backend": "second", "extra_params": nil},
"no-timeout": map[string]any{"backend": "second", "timeout_seconds": 0},
"partial": map[string]any{},
"endpoint-only": map[string]any{"endpoint": "https://standalone.example/v1"},
"cleared-endpoint": map[string]any{"extends": "base", "endpoint": nil},
map[string]any{"id": "direct-key", "backend": "second", "api_key_required": true},
map[string]any{"id": "named-key", "backend": "second", "api_key_required": true, "api_key_env": "CUSTOM_KEY"},
map[string]any{"id": "no-provider-map", "backend": "second", "extra_params": nil},
map[string]any{"id": "no-timeout", "backend": "second", "timeout_seconds": 0},
map[string]any{"id": "partial"},
map[string]any{"id": "endpoint-only", "endpoint": "https://standalone.example/v1"},
map[string]any{"id": "cleared-endpoint", "extends": map[string]any{"id": "base"}, "endpoint": nil},
},
}), nil)
if err != nil {
@@ -133,9 +158,9 @@ func TestLoadedZeroControlsReachBuiltInRequest(t *testing.T) {
}))
defer server.Close()
state, err := load(mapping("wire-controls", map[string]any{
"backends": map[string]any{"local": map[string]any{"endpoint": server.URL + "/v1"}},
"profiles": map[string]any{"direct": map[string]any{
"backend": "local", "model": "example", "temperature": 0.0, "max_tokens": 0, "top_p": nil,
"backends": []any{map[string]any{"id": "local", "endpoint": server.URL + "/v1"}},
"profiles": []any{map[string]any{
"id": "direct", "backend": "local", "model": "example", "temperature": 0.0, "max_tokens": 0, "top_p": nil,
}},
}), nil)
if err != nil {