Reject ambiguous configuration and reference bindings

This commit is contained in:
2026-08-09 00:29:04 +00:00
parent 90c7fa6381
commit 41a8a80dda
7 changed files with 212 additions and 58 deletions

View File

@@ -159,6 +159,85 @@ func TestResolvePipelineAppliesDefaults(t *testing.T) {
}
}
func TestResolvePipelineRejectsReferenceSlotCollisionsAfterTrimming(t *testing.T) {
for _, tt := range []struct {
name string
configure func(*PipelineProfile)
want []string
}{
{
name: "chunk",
configure: func(profile *PipelineProfile) {
profile.Chunk = ModuleBinding{Module: DefaultChunkModule, References: map[string]ReferenceSource{" rules ": ExternalReference("rules.md"), "rules": ExternalReference("other.md")}}
},
want: []string{`pipeline "references"`, "chunk", `reference slot "rules" is duplicated after trimming`},
},
{
name: "extract",
configure: func(profile *PipelineProfile) {
lane := profile.Artifacts["lane"]
lane.Extract.References = map[string]ReferenceSource{" rules ": ExternalReference("rules.md"), "rules": ExternalReference("other.md")}
profile.Artifacts["lane"] = lane
},
want: []string{`pipeline "references"`, `step "default"`, `lane "lane"`, "extract", `reference slot "rules" is duplicated after trimming`},
},
{
name: "merge",
configure: func(profile *PipelineProfile) {
lane := profile.Artifacts["lane"]
lane.Merge = ModuleBinding{Module: DefaultMergeModule, References: map[string]ReferenceSource{" rules ": ExternalReference("rules.md"), "rules": ExternalReference("other.md")}}
profile.Artifacts["lane"] = lane
},
want: []string{`pipeline "references"`, `step "default"`, `lane "lane"`, "merge", `reference slot "rules" is duplicated after trimming`},
},
{
name: "normalize",
configure: func(profile *PipelineProfile) {
lane := profile.Artifacts["lane"]
lane.Normalize = ModuleBinding{Module: DefaultNormalizeModule, References: map[string]ReferenceSource{" rules ": ExternalReference("rules.md"), "rules": ExternalReference("other.md")}}
profile.Artifacts["lane"] = lane
},
want: []string{`pipeline "references"`, `step "default"`, `lane "lane"`, "normalize", `reference slot "rules" is duplicated after trimming`},
},
} {
t.Run(tt.name, func(t *testing.T) {
profile := PipelineProfile{
ID: "references",
Input: Binding("text"),
Artifacts: map[string]ArtifactLaneProfile{
"lane": {Extract: Binding("event-extractor")},
},
}
tt.configure(&profile)
_, err := ResolvePipeline(profile, ResolveOptions{}, newProfileCatalog(t))
if err == nil {
t.Fatal("ResolvePipeline() error = nil, want normalized reference collision")
}
for _, fragment := range tt.want {
if !strings.Contains(err.Error(), fragment) {
t.Fatalf("ResolvePipeline() error = %q, want context %q", err, fragment)
}
}
})
}
}
func TestResolvePipelineRejectsEmptyReferenceSlotAfterTrimming(t *testing.T) {
_, err := ResolvePipeline(PipelineProfile{
ID: "references",
Input: Binding("text"),
Chunk: ModuleBinding{Module: DefaultChunkModule, References: map[string]ReferenceSource{
" \t ": ExternalReference("rules.md"),
}},
Artifacts: map[string]ArtifactLaneProfile{
"lane": {Extract: Binding("event-extractor")},
},
}, ResolveOptions{}, newProfileCatalog(t))
if err == nil || !strings.Contains(err.Error(), `pipeline "references" chunk reference slot must not be empty`) {
t.Fatalf("ResolvePipeline() error = %v, want contextual empty reference-slot rejection", err)
}
}
func TestResolvePipelineAppliesEffectiveLLMProfiles(t *testing.T) {
for _, test := range []struct {
name string