Centralize output schema and module key validation catalogs

This commit is contained in:
2026-05-23 17:39:13 +00:00
parent fa1bd237d1
commit 938bfe88c1
14 changed files with 233 additions and 101 deletions

View File

@@ -3,6 +3,8 @@ package config
import (
"fmt"
"strings"
"gitea.maximumdirect.net/eric/audita/internal/core/modulecatalog"
)
type WorkDirRetention string
@@ -14,7 +16,7 @@ const (
)
const (
DefaultModulesCSV = "glossary,homophones,glossary,spoken_word,grammar"
DefaultModulesCSV = modulecatalog.KeyGlossary + "," + modulecatalog.KeyHomophones + "," + modulecatalog.KeyGlossary + "," + modulecatalog.KeySpokenWord + "," + modulecatalog.KeyGrammar
DefaultOutputSchema = "bare-segments"
DefaultPrimaryModel = "openrouter/google/gemma-4-31b-it"
DefaultPrimaryBaseURL = "https://openrouter.ai/api/v1"

View File

@@ -4,6 +4,9 @@ import (
"reflect"
"strings"
"testing"
"gitea.maximumdirect.net/eric/audita/internal/core/modulecatalog"
"gitea.maximumdirect.net/eric/audita/internal/core/outputschema"
)
func TestDefaultConfigValues(t *testing.T) {
@@ -318,6 +321,38 @@ func TestValidationFailures(t *testing.T) {
}
}
func TestValidationRejectsUnsupportedModuleKey(t *testing.T) {
cfg := Default()
cfg.Modules = []string{modulecatalog.KeyGlossary, "made_up"}
err := cfg.Validate()
if err == nil {
t.Fatalf("expected validation error for unsupported module key")
}
if !strings.Contains(err.Error(), `unsupported module key "made_up"`) {
t.Fatalf("expected unsupported module key error, got %q", err.Error())
}
}
func TestValidationAllowsRepeatedSupportedModuleKeys(t *testing.T) {
cfg := Default()
cfg.Modules = []string{modulecatalog.KeyGlossary, modulecatalog.KeyGlossary, modulecatalog.KeyGrammar}
if err := cfg.Validate(); err != nil {
t.Fatalf("expected repeated supported module keys to validate, got %v", err)
}
}
func TestValidationAcceptsAllSupportedOutputSchemas(t *testing.T) {
for _, schemaKey := range outputschema.SupportedKeys() {
cfg := Default()
cfg.OutputSchema = schemaKey
if err := cfg.Validate(); err != nil {
t.Fatalf("expected output schema %q to validate, got %v", schemaKey, err)
}
}
}
func TestEffectiveValidationLLMInheritance(t *testing.T) {
cfg := Default()
cfg.PrimaryLLM.APIKey = "primary-key"

View File

@@ -3,6 +3,9 @@ package config
import (
"fmt"
"strings"
"gitea.maximumdirect.net/eric/audita/internal/core/modulecatalog"
"gitea.maximumdirect.net/eric/audita/internal/core/outputschema"
)
func (c Config) Validate() error {
@@ -12,19 +15,19 @@ func (c Config) Validate() error {
issues = append(issues, "modules must not be empty")
}
for _, module := range c.Modules {
if strings.TrimSpace(module) == "" {
moduleKey := strings.TrimSpace(module)
if moduleKey == "" {
issues = append(issues, "modules must not contain empty values")
break
}
if !modulecatalog.IsSupported(moduleKey) {
issues = append(issues, fmt.Sprintf("unsupported module key %q", moduleKey))
}
}
if strings.TrimSpace(c.OutputSchema) == "" {
issues = append(issues, "output schema must not be empty")
} else {
switch strings.TrimSpace(c.OutputSchema) {
case "bare-segments", "audita-v1":
default:
issues = append(issues, fmt.Sprintf("unsupported output schema %q", c.OutputSchema))
}
} else if !outputschema.IsSupported(c.OutputSchema) {
issues = append(issues, fmt.Sprintf("unsupported output schema %q", c.OutputSchema))
}
if c.PrimaryLLM.TimeoutSeconds <= 0 {

View File

@@ -0,0 +1,35 @@
package modulecatalog
import "strings"
const (
KeyGlossary = "glossary"
KeyHomophones = "homophones"
KeySpokenWord = "spoken_word"
KeyGrammar = "grammar"
)
var supportedKeys = []string{
KeyGlossary,
KeyHomophones,
KeySpokenWord,
KeyGrammar,
}
var supportedKeySet = map[string]struct{}{
KeyGlossary: {},
KeyHomophones: {},
KeySpokenWord: {},
KeyGrammar: {},
}
func SupportedKeys() []string {
out := make([]string, len(supportedKeys))
copy(out, supportedKeys)
return out
}
func IsSupported(key string) bool {
_, ok := supportedKeySet[strings.TrimSpace(key)]
return ok
}

View File

@@ -0,0 +1,24 @@
package modulecatalog
import (
"reflect"
"testing"
)
func TestSupportedKeys(t *testing.T) {
want := []string{KeyGlossary, KeyHomophones, KeySpokenWord, KeyGrammar}
if got := SupportedKeys(); !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected supported keys: got=%v want=%v", got, want)
}
}
func TestIsSupported(t *testing.T) {
for _, key := range SupportedKeys() {
if !IsSupported(key) {
t.Fatalf("expected key %q to be supported", key)
}
}
if IsSupported("made_up") {
t.Fatalf("did not expect made_up to be supported")
}
}

View File

@@ -31,15 +31,31 @@ var definitions = map[string]Definition{
},
}
var supportedKeys = []string{
SchemaBareSegments,
SchemaAuditaV1,
}
func SupportedKeys() []string {
out := make([]string, len(supportedKeys))
copy(out, supportedKeys)
return out
}
func IsSupported(key string) bool {
_, ok := definitions[strings.TrimSpace(key)]
return ok
}
func Resolve(key string) (Definition, error) {
normalized := strings.TrimSpace(key)
if normalized == "" {
return Definition{}, fmt.Errorf("output schema must not be empty")
}
def, ok := definitions[normalized]
if !ok {
if !IsSupported(normalized) {
return Definition{}, fmt.Errorf("unsupported output schema %q", normalized)
}
def := definitions[normalized]
return def, nil
}

View File

@@ -2,6 +2,7 @@ package outputschema
import (
"encoding/json"
"reflect"
"strings"
"testing"
@@ -56,3 +57,19 @@ func TestResolveUnknown(t *testing.T) {
t.Fatalf("expected unsupported output schema error, got %v", err)
}
}
func TestSupportedKeysAndIsSupported(t *testing.T) {
want := []string{SchemaBareSegments, SchemaAuditaV1}
if got := SupportedKeys(); !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected supported schema keys: got=%v want=%v", got, want)
}
for _, key := range want {
if !IsSupported(key) {
t.Fatalf("expected schema key %q to be supported", key)
}
}
if IsSupported("seriatim-intermediate") {
t.Fatalf("did not expect unsupported schema to be reported as supported")
}
}