Define identified configuration resources

This commit is contained in:
2026-11-02 03:53:09 +00:00
parent 0b271267a0
commit aba890aa86
3 changed files with 51 additions and 12 deletions

View File

@@ -243,6 +243,14 @@ Validation: inspect the registration selectors and schema; when runnable, load
one headerless root list and one version-2 collection. Resolution/validation one headerless root list and one version-2 collection. Resolution/validation
callers are completed in the following stages. callers are completed in the following stages.
Completion: the typed document now uses identified resource slices, registers
all six root and collection identity rules, and checks specification version 2.
Added a focused root/collection list fixture and reviewed the selectors and
schema. The focused test cannot yet compile because field capture, resolution,
validation, indexing, prompt materialization, and older fixtures still expect
maps; those migrations are assigned to the following stages. Formatting and
`git diff --check` passed; execution of the new fixture remains deferred.
## Stage 4: Preserve Field Presence And Resolution At List Paths ## Stage 4: Preserve Field Presence And Resolution At List Paths
Scope: backend/profile field capture, normalization, and defaulting in Scope: backend/profile field capture, normalization, and defaulting in

View File

@@ -18,20 +18,21 @@ import (
type document struct { type document struct {
Version *string `yaml:"version"` Version *string `yaml:"version"`
Backends map[string]backendConfig `yaml:"backends"` Backends []backendConfig `yaml:"backends"`
Profiles map[string]profileConfig `yaml:"profiles"` Profiles []profileConfig `yaml:"profiles"`
Prompts map[string]promptConfig `yaml:"prompts"` Prompts []promptConfig `yaml:"prompts"`
Collections map[string]collectionConfig `yaml:"collections"` Collections map[string]collectionConfig `yaml:"collections"`
} }
type collectionConfig struct { type collectionConfig struct {
ReleaseVersion *string `yaml:"release_version"` ReleaseVersion *string `yaml:"release_version"`
Backends map[string]backendConfig `yaml:"backends"` Backends []backendConfig `yaml:"backends"`
Profiles map[string]profileConfig `yaml:"profiles"` Profiles []profileConfig `yaml:"profiles"`
Prompts map[string]promptConfig `yaml:"prompts"` Prompts []promptConfig `yaml:"prompts"`
} }
type backendConfig struct { type backendConfig struct {
ID string `yaml:"id"`
Endpoint *string `yaml:"endpoint"` Endpoint *string `yaml:"endpoint"`
APIKeyEnv *string `yaml:"api_key_env"` APIKeyEnv *string `yaml:"api_key_env"`
ConcurrencyLimit *int `yaml:"concurrency_limit"` ConcurrencyLimit *int `yaml:"concurrency_limit"`
@@ -56,6 +57,7 @@ type authenticationProbeConfig struct {
} }
type profileConfig struct { type profileConfig struct {
ID string `yaml:"id"`
Backend *string `yaml:"backend"` Backend *string `yaml:"backend"`
Endpoint *string `yaml:"endpoint"` Endpoint *string `yaml:"endpoint"`
Model *string `yaml:"model"` Model *string `yaml:"model"`
@@ -71,7 +73,7 @@ type profileConfig struct {
} }
type promptConfig struct { type promptConfig struct {
Version *string `yaml:"version"` ID string `yaml:"id"`
DefaultProfile *string `yaml:"default_profile"` DefaultProfile *string `yaml:"default_profile"`
Description *string `yaml:"description"` Description *string `yaml:"description"`
SessionID *string `yaml:"session_id"` SessionID *string `yaml:"session_id"`
@@ -141,9 +143,9 @@ type resourceSet struct {
isCollection bool isCollection bool
namespace string namespace string
bases resourceBases bases resourceBases
backends map[string]backendConfig backends []backendConfig
profiles map[string]profileConfig profiles []profileConfig
prompts map[string]promptConfig prompts []promptConfig
} }
func rootResourceBases() resourceBases { func rootResourceBases() resourceBases {
@@ -230,6 +232,14 @@ func load(main configkit.Input, underlays []configkit.Underlay) (*loaded, error)
Underlays: underlays, Underlays: underlays,
SourceVersionMode: configkit.SourceVersionModeIfPresent, SourceVersionMode: configkit.SourceVersionModeIfPresent,
Definition: configkit.Definition[document]{ Definition: configkit.Definition[document]{
SequenceIdentities: []configkit.SequenceIdentity{
configkit.SequenceIdentityAt(configkit.Keys("backends"), "id"),
configkit.SequenceIdentityAt(configkit.Keys("profiles"), "id"),
configkit.SequenceIdentityAt(configkit.Keys("prompts"), "id"),
configkit.SequenceIdentityMatching(configkit.SequenceSelector{configkit.SequenceLiteralKey("collections"), configkit.SequenceAnyMappingKey(), configkit.SequenceLiteralKey("backends")}, "id"),
configkit.SequenceIdentityMatching(configkit.SequenceSelector{configkit.SequenceLiteralKey("collections"), configkit.SequenceAnyMappingKey(), configkit.SequenceLiteralKey("profiles")}, "id"),
configkit.SequenceIdentityMatching(configkit.SequenceSelector{configkit.SequenceLiteralKey("collections"), configkit.SequenceAnyMappingKey(), configkit.SequenceLiteralKey("prompts")}, "id"),
},
Version: &configkit.VersionRule{ Version: &configkit.VersionRule{
Path: configkit.Keys("version"), Path: configkit.Keys("version"),
Check: checkConfigurationVersion, Check: checkConfigurationVersion,
@@ -302,7 +312,7 @@ func checkConfigurationVersion(version configkit.Version, validation *configkit.
if !version.Present { if !version.Present {
return nil return nil
} }
if version.Null || version.Text != "1" { if version.Null || version.Text != "2" {
validation.Error(configkit.Keys("version"), "unsupported configuration specification version") validation.Error(configkit.Keys("version"), "unsupported configuration specification version")
} }
return nil return nil

View File

@@ -12,6 +12,27 @@ func mapping(label string, values map[string]any) configkit.Input {
return configkit.Input{Source: configkit.Mapping(label, values)} return configkit.Input{Source: configkit.Mapping(label, values)}
} }
func TestLoadIdentifiedResourceLists(t *testing.T) {
for _, header := range []bool{false, true} {
values := map[string]any{
"backends": []any{map[string]any{"id": "local", "endpoint": "https://example.invalid/v1"}},
"collections": map[string]any{"team": map[string]any{
"backends": []any{map[string]any{"id": "local", "endpoint": "https://example.invalid/v1"}},
}},
}
if header {
values["version"] = "2"
}
loaded, err := load(mapping("identified resources", values), nil)
if err != nil {
t.Fatalf("load identified resources with header %t: %v", header, err)
}
if loaded.result.Config.Backends[0].ID != "local" || loaded.result.Config.Collections["team"].Backends[0].ID != "local" {
t.Fatal("identified root and collection resources were not retained")
}
}
}
func TestLoadChecksOptionalConfigurationVersion(t *testing.T) { func TestLoadChecksOptionalConfigurationVersion(t *testing.T) {
for _, test := range []struct { for _, test := range []struct {
name string name string