Avoid copying output during basic validation

This commit is contained in:
2026-10-09 00:13:23 +00:00
parent 05fe13d80b
commit ed7c27324d
3 changed files with 45 additions and 24 deletions

View File

@@ -151,7 +151,8 @@ control into the rendered prompt. The
`internal/validate` provides validators backed by an operating-system `internal/validate` provides validators backed by an operating-system
filesystem or an `fs.FS`. Invalid generated content is returned as a validation filesystem or an `fs.FS`. Invalid generated content is returned as a validation
result; inability to load, register, or compile a schema is an operational result; inability to load, register, or compile a schema is an operational
error. error. Basic validation checks body emptiness on the byte slice directly
instead of first making a response-sized string copy.
Every preparation operation creates one operation-local validation plan. None, Every preparation operation creates one operation-local validation plan. None,
basic, and JSON modes retain the effective output contract without source basic, and JSON modes retain the effective output contract without source

View File

@@ -188,7 +188,7 @@ func validateArtifact(ctx context.Context, artifact *domain.Artifact, contract d
res.IsValid = true res.IsValid = true
return res, nil return res, nil
case domain.ValidationBasic: case domain.ValidationBasic:
empty := strings.TrimSpace(string(artifact.Body)) == "" empty := len(bytes.TrimSpace(artifact.Body)) == 0
if err := ctx.Err(); err != nil { if err := ctx.Err(); err != nil {
return domain.ValidationResult{}, err return domain.ValidationResult{}, err
} }

View File

@@ -36,32 +36,51 @@ func TestStandardValidatorNoneSkipped(t *testing.T) {
func TestStandardValidatorBasicSuccess(t *testing.T) { func TestStandardValidatorBasicSuccess(t *testing.T) {
v := NewStandardValidator("") v := NewStandardValidator("")
for _, tc := range []struct {
res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte("hello")}, domain.OutputContract{ name string
ValidationMode: domain.ValidationBasic, body []byte
}) }{
if err != nil { {name: "text", body: []byte("hello")},
t.Fatalf("expected no error, got %v", err) {name: "invalid UTF-8 byte", body: []byte{0xff}},
} } {
if res.Status != domain.ValidationPassed || !res.IsValid { t.Run(tc.name, func(t *testing.T) {
t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid) res, err := v.Validate(context.Background(), &domain.Artifact{Body: tc.body}, domain.OutputContract{
ValidationMode: domain.ValidationBasic,
})
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if res.Status != domain.ValidationPassed || !res.IsValid {
t.Fatalf("expected passed/valid, got status=%q valid=%v", res.Status, res.IsValid)
}
})
} }
} }
func TestStandardValidatorBasicFailureEmpty(t *testing.T) { func TestStandardValidatorBasicFailureEmpty(t *testing.T) {
v := NewStandardValidator("") v := NewStandardValidator("")
for _, tc := range []struct {
res, err := v.Validate(context.Background(), &domain.Artifact{Body: []byte(" \n\t ")}, domain.OutputContract{ name string
ValidationMode: domain.ValidationBasic, body []byte
}) }{
if err != nil { {name: "empty bytes", body: []byte{}},
t.Fatalf("expected no error, got %v", err) {name: "ASCII whitespace", body: []byte(" \n\t ")},
} {name: "Unicode whitespace", body: []byte("\u2003\u00a0\u3000")},
if res.Status != domain.ValidationFailed || res.IsValid { } {
t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid) t.Run(tc.name, func(t *testing.T) {
} res, err := v.Validate(context.Background(), &domain.Artifact{Body: tc.body}, domain.OutputContract{
if len(res.Errors) == 0 { ValidationMode: domain.ValidationBasic,
t.Fatal("expected validation errors") })
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if res.Status != domain.ValidationFailed || res.IsValid {
t.Fatalf("expected failed/invalid, got status=%q valid=%v", res.Status, res.IsValid)
}
if len(res.Errors) == 0 {
t.Fatal("expected validation errors")
}
})
} }
} }
@@ -947,7 +966,8 @@ func BenchmarkBasicValidation(b *testing.B) {
} }
b.ReportAllocs() b.ReportAllocs()
b.SetBytes(int64(len(benchmark.body))) // Nonempty input can be classified from its boundary bytes without
// scanning the body, so report latency rather than bytes per second.
b.ResetTimer() b.ResetTimer()
for range b.N { for range b.N {
result, err := validator.Validate(ctx, artifact, contract) result, err := validator.Validate(ctx, artifact, contract)