Preserve structured repair settings across pipeline boundaries

This commit is contained in:
2026-08-25 23:46:52 +00:00
parent 3d3f16db4a
commit 916d9210fd
7 changed files with 166 additions and 16 deletions

View File

@@ -41,6 +41,10 @@ type observingChunkValidator struct {
request contracts.ChunkValidationRequest
}
type observingSerializedValidator struct {
request contracts.SerializedValidationRequest
}
func (*observingChunkValidator) Name() string { return "observing/chunk-validator" }
func (*observingChunkValidator) ExecutionClass() contracts.ExecutionClass {
return contracts.ExecutionClassDeterministic
@@ -50,6 +54,15 @@ func (v *observingChunkValidator) Validate(_ context.Context, request contracts.
return contracts.ValidationResult{Approved: true}, nil
}
func (*observingSerializedValidator) Name() string { return "observing/serialized-validator" }
func (*observingSerializedValidator) ExecutionClass() contracts.ExecutionClass {
return contracts.ExecutionClassDeterministic
}
func (v *observingSerializedValidator) Validate(_ context.Context, request contracts.SerializedValidationRequest) (contracts.ValidationResult, error) {
v.request = request
return contracts.ValidationResult{Approved: true}, nil
}
func (terminalChunkValidator) Name() string { return "terminal/chunk-validator" }
func (terminalChunkValidator) ExecutionClass() contracts.ExecutionClass {
@@ -168,6 +181,33 @@ func TestRunnerMaterializesAnnotatedPlanBeforeChunkValidation(t *testing.T) {
}
}
func TestRunnerForwardsDetachedRepairAttemptsToChunkValidators(t *testing.T) {
prepared, plan := preparedTerminalDebugPipeline(t)
prepared.chunker = terminalChunker{key: prepared.resolved.Chunk.Module, plan: plan}
chunkValidator := &observingChunkValidator{}
serializedValidator := &observingSerializedValidator{}
chunkAttempts := 2
serializedAttempts := 3
chunkBinding := Binding(chunkValidator.Name())
chunkBinding.StructuredOutputRepairAttempts = &chunkAttempts
serializedBinding := Binding(serializedValidator.Name())
serializedBinding.StructuredOutputRepairAttempts = &serializedAttempts
prepared.chunkValidators.validators = []preparedValidator{
{resolved: ResolvedValidator{Binding: chunkBinding, Target: ValidatorTargetChunk}, chunk: chunkValidator},
{resolved: ResolvedValidator{Binding: serializedBinding, Target: ValidatorTargetSerialized}, serialized: serializedValidator},
}
if _, err := New().Run(context.Background(), RunInput{Prepared: prepared, RawInput: []byte("input")}); err != nil {
t.Fatalf("Run() error = %v, want nil", err)
}
if got := chunkValidator.request.StructuredOutputRepairAttempts; got == nil || *got != chunkAttempts || got == chunkBinding.StructuredOutputRepairAttempts {
t.Fatalf("chunk validator repair attempts = %v, want detached value %d", got, chunkAttempts)
}
if got := serializedValidator.request.StructuredOutputRepairAttempts; got == nil || *got != serializedAttempts || got == serializedBinding.StructuredOutputRepairAttempts {
t.Fatalf("serialized validator repair attempts = %v, want detached value %d", got, serializedAttempts)
}
}
func TestRunnerRetriesMalformedPlanWithDebugEnabled(t *testing.T) {
prepared, plan := preparedTerminalDebugPipeline(t)
plan.Ranges[0].Annotations = source.ChunkAnnotations{"broken": []byte(`{"value":`)}