Separate final configuration record validation

This commit is contained in:
2026-11-05 14:22:34 +00:00
parent 68668cee56
commit 2e2fba4993
2 changed files with 103 additions and 89 deletions

View File

@@ -626,6 +626,11 @@ documentation is updated.
focused changed-seam cases retain final values, paths and relevant error meaning.
This stage changes organization, not configuration acceptance policy.
Completion: final-handoff traversal retains its resource index and delegates
backend, profile, and prompt records to focused validators. Configuration tests
and focused public configuration, validation, inspection, and source tests pass
on Go 1.27.3; the extracted checks preserve their existing paths and rules.
## Stage 24: Separate Prompt Capture And Effective Target Construction
**Catalog:** 22, completion. **Files:** configuration prompts/targets and tests.

View File

@@ -419,101 +419,110 @@ func validateEffective(config *document, validation *configkit.Validation) {
}
for _, resources := range sets {
for index, backend := range resources.backends {
base := resources.bases.backends.Index(index)
validateBackendEndpoints(backend, base, validation)
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")
}
if backend.APIKeyEnv != nil && *backend.APIKeyEnv != "" && !envName.MatchString(*backend.APIKeyEnv) {
validation.Error(base.Key("api_key_env"), "environment variable name is invalid")
}
if backend.ConcurrencyLimit != nil && *backend.ConcurrencyLimit < 0 {
validation.Error(base.Key("concurrency_limit"), "concurrency limit must not be negative")
}
if backend.QueueCapacity != nil {
if *backend.QueueCapacity < 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity must not be negative")
}
if backend.ConcurrencyLimit == nil || *backend.ConcurrencyLimit <= 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity requires a positive concurrency limit")
} else if *backend.QueueCapacity > int(^uint(0)>>1)-*backend.ConcurrencyLimit {
validation.Error(base.Key("queue_capacity"), "total capacity overflows int")
}
}
validateExtraParams(backend.ExtraParams, base.Key("extra_params"), true, validation)
if smokeTests := backend.SmokeTests; smokeTests != nil {
smokePath := base.Key("smoke_tests")
if smokeTests.DefaultProfile != nil {
if strings.TrimSpace(*smokeTests.DefaultProfile) == "" {
validation.Error(smokePath.Key("default_profile"), "default profile must not be blank")
} else if !domain.IsValidResourceID(*smokeTests.DefaultProfile) {
validation.Error(smokePath.Key("default_profile"), "default profile reference is malformed")
}
}
if authentication := smokeTests.Authentication; authentication != nil {
kindPath := smokePath.Key("authentication").Key("kind")
if authentication.Kind == nil {
validation.Error(kindPath, "authentication kind is required")
} else if *authentication.Kind != "none" && *authentication.Kind != "openrouter_key" {
validation.Error(kindPath, "authentication kind must be none or openrouter_key")
}
}
}
validateBackendRecord(backend, resources.bases.backends.Index(index), validation)
}
for index, profile := range resources.profiles {
base := resources.bases.profiles.Index(index)
if profile.Endpoint != nil && *profile.Endpoint != "" {
if _, err := domain.NormalizeOpenAICompatibleBaseEndpoint(*profile.Endpoint); err != nil {
validation.Error(base.Key("endpoint"), err.Error())
}
}
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) {
validation.Error(base.Key("backend"), "backend reference is malformed")
} else if _, exists := backendIDs[*profile.Backend]; !exists {
validation.Error(base.Key("backend"), "backend is not defined")
}
}
if profile.Model != nil && *profile.Model != "" && strings.TrimSpace(*profile.Model) == "" {
validation.Error(base.Key("model"), "model must not be blank")
}
if profile.Temperature != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{Temperature: *profile.Temperature}); err != nil {
validation.Error(base.Key("temperature"), err.Error())
}
}
if profile.TopP != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TopP: *profile.TopP}); err != nil {
validation.Error(base.Key("top_p"), err.Error())
}
}
if profile.MaxTokens != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{MaxTokens: *profile.MaxTokens}); err != nil {
validation.Error(base.Key("max_tokens"), err.Error())
}
}
if profile.TimeoutSeconds != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TimeoutSeconds: *profile.TimeoutSeconds}); err != nil {
validation.Error(base.Key("timeout_seconds"), err.Error())
}
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
validateProfileRecord(profile, resources.bases.profiles.Index(index), backendIDs, validation)
}
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")
validatePromptRecord(prompt, resources.bases.prompts.Index(index), validation)
}
}
}
func validateBackendRecord(backend backendConfig, base configkit.Path, validation *configkit.Validation) {
validateBackendEndpoints(backend, base, validation)
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")
}
if backend.APIKeyEnv != nil && *backend.APIKeyEnv != "" && !envName.MatchString(*backend.APIKeyEnv) {
validation.Error(base.Key("api_key_env"), "environment variable name is invalid")
}
if backend.ConcurrencyLimit != nil && *backend.ConcurrencyLimit < 0 {
validation.Error(base.Key("concurrency_limit"), "concurrency limit must not be negative")
}
if backend.QueueCapacity != nil {
if *backend.QueueCapacity < 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity must not be negative")
}
if backend.ConcurrencyLimit == nil || *backend.ConcurrencyLimit <= 0 {
validation.Error(base.Key("queue_capacity"), "queue capacity requires a positive concurrency limit")
} else if *backend.QueueCapacity > int(^uint(0)>>1)-*backend.ConcurrencyLimit {
validation.Error(base.Key("queue_capacity"), "total capacity overflows int")
}
}
validateExtraParams(backend.ExtraParams, base.Key("extra_params"), true, validation)
if smokeTests := backend.SmokeTests; smokeTests != nil {
smokePath := base.Key("smoke_tests")
if smokeTests.DefaultProfile != nil {
if strings.TrimSpace(*smokeTests.DefaultProfile) == "" {
validation.Error(smokePath.Key("default_profile"), "default profile must not be blank")
} else if !domain.IsValidResourceID(*smokeTests.DefaultProfile) {
validation.Error(smokePath.Key("default_profile"), "default profile reference is malformed")
}
}
if authentication := smokeTests.Authentication; authentication != nil {
kindPath := smokePath.Key("authentication").Key("kind")
if authentication.Kind == nil {
validation.Error(kindPath, "authentication kind is required")
} else if *authentication.Kind != "none" && *authentication.Kind != "openrouter_key" {
validation.Error(kindPath, "authentication kind must be none or openrouter_key")
}
}
}
}
func validateProfileRecord(profile profileConfig, base configkit.Path, backendIDs map[string]struct{}, validation *configkit.Validation) {
if profile.Endpoint != nil && *profile.Endpoint != "" {
if _, err := domain.NormalizeOpenAICompatibleBaseEndpoint(*profile.Endpoint); err != nil {
validation.Error(base.Key("endpoint"), err.Error())
}
}
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) {
validation.Error(base.Key("backend"), "backend reference is malformed")
} else if _, exists := backendIDs[*profile.Backend]; !exists {
validation.Error(base.Key("backend"), "backend is not defined")
}
}
if profile.Model != nil && *profile.Model != "" && strings.TrimSpace(*profile.Model) == "" {
validation.Error(base.Key("model"), "model must not be blank")
}
if profile.Temperature != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{Temperature: *profile.Temperature}); err != nil {
validation.Error(base.Key("temperature"), err.Error())
}
}
if profile.TopP != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TopP: *profile.TopP}); err != nil {
validation.Error(base.Key("top_p"), err.Error())
}
}
if profile.MaxTokens != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{MaxTokens: *profile.MaxTokens}); err != nil {
validation.Error(base.Key("max_tokens"), err.Error())
}
}
if profile.TimeoutSeconds != nil {
if err := domain.ValidateExecutionTargetSettings(domain.ExecutionTarget{TimeoutSeconds: *profile.TimeoutSeconds}); err != nil {
validation.Error(base.Key("timeout_seconds"), err.Error())
}
}
validateExtraParams(profile.ExtraParams, base.Key("extra_params"), false, validation)
}
func validatePromptRecord(prompt promptConfig, base configkit.Path, validation *configkit.Validation) {
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")
}
}