Add validator chain config overrides
This commit is contained in:
@@ -182,6 +182,143 @@ func TestResolvePipelineRejectsUnknownDefaultValidator(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineValidatorOverrideReplacesDefaultChain(t *testing.T) {
|
||||
catalog := newProfileCatalog(t)
|
||||
registerProfileValidatorSpec(t, catalog, ValidatorSpec{Key: "second-validator", ExecutionClass: contracts.ExecutionClassLLMBacked})
|
||||
if err := catalog.ValidatorChains.Register(ValidatorChainMapping{
|
||||
Stage: StageExtract,
|
||||
Module: "event-extractor",
|
||||
Validators: []ModuleBinding{Binding("grounded")},
|
||||
}); err != nil {
|
||||
t.Fatalf("register validator chain: %v", err)
|
||||
}
|
||||
|
||||
profile := PipelineProfile{
|
||||
ID: "validated",
|
||||
Input: Binding("text"),
|
||||
Artifacts: map[string]ArtifactLaneProfile{
|
||||
"events": {
|
||||
Extract: ModuleBinding{
|
||||
Module: "event-extractor",
|
||||
Validators: ValidatorOverride{
|
||||
Set: true,
|
||||
Validators: []ModuleBinding{
|
||||
{Module: "second-validator", LLMProfile: "careful"},
|
||||
Binding("grounded"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resolved, err := ResolvePipeline(profile, ResolveOptions{}, catalog)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolvePipeline() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
extractChain := findResolvedValidatorChain(resolved.ValidatorChains, StageExtract, "events", "event-extractor")
|
||||
if extractChain == nil {
|
||||
t.Fatal("extract validator chain not found")
|
||||
}
|
||||
if len(extractChain.Validators) != 2 {
|
||||
t.Fatalf("extract validators = %#v, want explicit two-validator override", extractChain.Validators)
|
||||
}
|
||||
if extractChain.Validators[0].Binding.Module != "second-validator" || extractChain.Validators[0].Binding.LLMProfile != "careful" {
|
||||
t.Fatalf("first validator = %#v, want explicit LLM-backed validator first", extractChain.Validators[0])
|
||||
}
|
||||
if extractChain.Validators[1].Binding.Module != "grounded" {
|
||||
t.Fatalf("second validator = %#v, want grounded second", extractChain.Validators[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineExplicitEmptyValidatorOverrideSuppressesDefaultChain(t *testing.T) {
|
||||
catalog := newProfileCatalog(t)
|
||||
if err := catalog.ValidatorChains.Register(ValidatorChainMapping{
|
||||
Stage: StageExtract,
|
||||
Module: "event-extractor",
|
||||
Validators: []ModuleBinding{Binding("grounded")},
|
||||
}); err != nil {
|
||||
t.Fatalf("register validator chain: %v", err)
|
||||
}
|
||||
|
||||
profile := PipelineProfile{
|
||||
ID: "validated",
|
||||
Input: Binding("text"),
|
||||
Artifacts: map[string]ArtifactLaneProfile{
|
||||
"events": {
|
||||
Extract: ModuleBinding{
|
||||
Module: "event-extractor",
|
||||
Validators: ValidatorOverride{Set: true},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resolved, err := ResolvePipeline(profile, ResolveOptions{}, catalog)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolvePipeline() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
extractChain := findResolvedValidatorChain(resolved.ValidatorChains, StageExtract, "events", "event-extractor")
|
||||
if extractChain == nil {
|
||||
t.Fatal("extract validator chain not found")
|
||||
}
|
||||
if len(extractChain.Validators) != 0 {
|
||||
t.Fatalf("extract validators = %#v, want explicit empty override", extractChain.Validators)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineRejectsUnknownOverrideValidator(t *testing.T) {
|
||||
_, err := ResolvePipeline(PipelineProfile{
|
||||
ID: "validated",
|
||||
Input: Binding("text"),
|
||||
Artifacts: map[string]ArtifactLaneProfile{
|
||||
"events": {
|
||||
Extract: ModuleBinding{
|
||||
Module: "event-extractor",
|
||||
Validators: ValidatorOverride{
|
||||
Set: true,
|
||||
Validators: []ModuleBinding{Binding("missing-validator")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, ResolveOptions{}, newProfileCatalog(t))
|
||||
if err == nil {
|
||||
t.Fatal("ResolvePipeline() error = nil, want unknown validator error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "missing-validator") {
|
||||
t.Fatalf("ResolvePipeline() error = %q, want missing validator context", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineRejectsLLMProfileForDeterministicValidator(t *testing.T) {
|
||||
_, err := ResolvePipeline(PipelineProfile{
|
||||
ID: "validated",
|
||||
Input: Binding("text"),
|
||||
Artifacts: map[string]ArtifactLaneProfile{
|
||||
"events": {
|
||||
Extract: ModuleBinding{
|
||||
Module: "event-extractor",
|
||||
Validators: ValidatorOverride{
|
||||
Set: true,
|
||||
Validators: []ModuleBinding{
|
||||
{Module: "grounded", LLMProfile: "careful"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, ResolveOptions{}, newProfileCatalog(t))
|
||||
if err == nil {
|
||||
t.Fatal("ResolvePipeline() error = nil, want deterministic validator profile error")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "grounded") || !strings.Contains(err.Error(), "llm_profile") {
|
||||
t.Fatalf("ResolvePipeline() error = %q, want validator profile context", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolvePipelineSelectsOnlyRequestedLanes(t *testing.T) {
|
||||
profile := multiLaneProfile()
|
||||
resolved, err := ResolvePipeline(profile, ResolveOptions{Only: []string{" summaries ", "events", "summaries"}}, newProfileCatalog(t))
|
||||
@@ -850,7 +987,7 @@ func TestResolvePipelineRejectsConfiguredValidators(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatal("ResolvePipeline() error = nil, want error")
|
||||
}
|
||||
assertErrorContains(t, err, "baseline", "events", "configured validators", "not supported")
|
||||
assertErrorContains(t, err, "baseline", "events", "validators", "extract.validators")
|
||||
}
|
||||
|
||||
func TestResolvePipelineOrdersLanesDeterministically(t *testing.T) {
|
||||
@@ -1139,6 +1276,13 @@ func registerProfileSpecs(t *testing.T, catalog ModuleCatalog, specs ...ModuleSp
|
||||
}
|
||||
}
|
||||
|
||||
func registerProfileValidatorSpec(t *testing.T, catalog ModuleCatalog, spec ValidatorSpec) {
|
||||
t.Helper()
|
||||
if err := catalog.Validators.RegisterWithSpec(spec, profileValidatorConstructor(spec.Key)); err != nil {
|
||||
t.Fatalf("register validator spec %#v: %v", spec, err)
|
||||
}
|
||||
}
|
||||
|
||||
func profileInputConstructor(key string) InputAdapterConstructor {
|
||||
return func() (contracts.InputAdapter, error) {
|
||||
return profileInputAdapter{key: key}, nil
|
||||
|
||||
Reference in New Issue
Block a user