Separate config normalization from validation

This commit is contained in:
2026-09-07 03:32:50 +00:00
parent f8e3e651e6
commit 10a2e89965
6 changed files with 202 additions and 71 deletions

View File

@@ -169,8 +169,11 @@ func TestNotariusReferenceValidationAndNormalization(t *testing.T) {
"spells": "narratio.input.spell_catalog",
}
if err := NormalizePipelineConfig(&PipelineConfig{Notarius: cfg}); err != nil {
t.Fatalf("NormalizePipelineConfig() error = %v", err)
}
if err := validateNotarius(cfg, nil); err != nil {
t.Fatalf("validateNotarius() error = %v", err)
t.Fatalf("validateNotarius() after normalization error = %v", err)
}
want := map[string]string{
"party": "narratio.input.party",
@@ -207,7 +210,7 @@ func TestNotariusReferenceValidationRejectsInvalidBindings(t *testing.T) {
" chunk . party ": "narratio.input.players",
},
wantField: "pipeline.notarius.references",
wantReason: "normalize to",
wantReason: "must be normalized",
},
}
@@ -264,19 +267,17 @@ func TestNotariusValidationFailureDoesNotMutateConfig(t *testing.T) {
{
name: "reference",
mutate: func(cfg *NotariusConfig) {
cfg.Binary = " notarius "
cfg.References = map[string]string{" party ": "unsupported"}
},
want: "pipeline.notarius.references.party",
want: "pipeline.notarius.references selector",
},
{
name: "output",
mutate: func(cfg *NotariusConfig) {
cfg.Binary = " notarius "
cfg.References = map[string]string{" party ": " narratio.input.party "}
cfg.References = map[string]string{"party": "narratio.input.party"}
cfg.Outputs["npc_registry"] = NotariusOutputConfig{LaneID: " missing-schema "}
},
want: "pipeline.notarius.outputs.npc_registry.media_type",
want: "pipeline.notarius.outputs.npc_registry.lane_id",
},
}
@@ -314,8 +315,11 @@ func TestNotariusNormalizationProducesCanonicalValues(t *testing.T) {
},
}
if err := NormalizePipelineConfig(&PipelineConfig{Notarius: cfg}); err != nil {
t.Fatalf("NormalizePipelineConfig() error = %v", err)
}
if err := validateNotarius(cfg, nil); err != nil {
t.Fatalf("validateNotarius() error = %v", err)
t.Fatalf("validateNotarius() after normalization error = %v", err)
}
wantReferences := map[string]string{
"party": "narratio.input.party",
@@ -330,6 +334,24 @@ func TestNotariusNormalizationProducesCanonicalValues(t *testing.T) {
if got := cfg.Outputs["npc_registry"]; got.LaneID != "npc-registry" || got.MediaType != "application/json" || got.SchemaID != "notarius.dnd.npc_registry" || got.SchemaVersion != "v1" {
t.Fatalf("normalized npc_registry output = %#v", got)
}
beforeSecondPass := cloneNotariusConfigForTest(cfg)
if err := NormalizePipelineConfig(&PipelineConfig{Notarius: cfg}); err != nil {
t.Fatalf("second NormalizePipelineConfig() error = %v", err)
}
if !reflect.DeepEqual(cfg, beforeSecondPass) {
t.Fatalf("normalization is not deterministic:\n got: %#v\nwant: %#v", cfg, beforeSecondPass)
}
}
func TestNotariusValidationDoesNotMutateAcceptedConfig(t *testing.T) {
cfg := validNotariusConfig()
before := cloneNotariusConfigForTest(cfg)
if err := validateNotarius(cfg, nil); err != nil {
t.Fatalf("validateNotarius() error = %v", err)
}
if !reflect.DeepEqual(cfg, before) {
t.Fatalf("accepted config mutated during validation:\n got: %#v\nwant: %#v", cfg, before)
}
}
func TestNotariusDiagnosticsUseSortedMapKeys(t *testing.T) {
@@ -421,7 +443,7 @@ func validNotariusConfig() *NotariusConfig {
return &NotariusConfig{
Enabled: true,
Binary: "notarius",
ConfigPath: "./notarius.yml",
ConfigPath: "notarius.yml",
PipelineID: "dnd-session",
Timeout: "45m",
WorkingDirectory: ".",
@@ -497,6 +519,14 @@ func TestNotariusEnabledValidation(t *testing.T) {
pipelinePath, sessionPath := writeConfigFiles(t, testPipelineBaseYAML+"\n"+tt.section, testSessionBaseYAML)
cfg, err := Load(pipelinePath, sessionPath)
if err != nil {
if len(tt.wantErr) > 0 {
for _, fragment := range tt.wantErr {
if !strings.Contains(err.Error(), fragment) {
t.Fatalf("Load() error = %v, want containing %q", err, fragment)
}
}
return
}
t.Fatalf("Load() error = %v", err)
}
err = Validate(cfg)