Deep-clone source metadata during chunk materialization

This commit is contained in:
2026-07-18 02:10:05 +00:00
parent 205e2a9908
commit 561d65a505
6 changed files with 279 additions and 77 deletions

View File

@@ -679,41 +679,11 @@ func validateOutputFileName(name string) error {
}
func cloneMetadata(metadata map[string]any) map[string]any {
if len(metadata) == 0 {
return nil
}
out := make(map[string]any, len(metadata))
for key, value := range metadata {
out[key] = cloneMetadataValue(value)
}
return out
}
func cloneMetadataValue(value any) any {
switch typed := value.(type) {
case map[string]any:
return cloneMetadata(typed)
case []any:
out := make([]any, len(typed))
for i := range typed {
out[i] = cloneMetadataValue(typed[i])
}
return out
case json.RawMessage:
return append(json.RawMessage(nil), typed...)
case []byte:
return append([]byte(nil), typed...)
case []string:
return append([]string(nil), typed...)
case map[string]string:
out := make(map[string]string, len(typed))
for key, item := range typed {
out[key] = item
}
return out
default:
return value
cloned, err := source.CloneMetadata(metadata)
if err != nil {
return metadata
}
return cloned
}
func cloneLLMProfiles(profiles []artifacts.LLMProfileManifest) []artifacts.LLMProfileManifest {

View File

@@ -16,6 +16,24 @@ type extractCaptureRecorder struct {
checkpoint ExtractCheckpoint
}
type pipelineTypedMetadata map[string]any
type mutatingMetadataValidator struct {
seen string
}
func (*mutatingMetadataValidator) Name() string { return "test/mutating-metadata" }
func (*mutatingMetadataValidator) ExecutionClass() contracts.ExecutionClass {
return contracts.ExecutionClassDeterministic
}
func (v *mutatingMetadataValidator) Validate(_ context.Context, request contracts.ChunkValidationRequest) (contracts.ValidationResult, error) {
nested := request.Chunks[0].Units[0].Metadata["typed"].(pipelineTypedMetadata)
v.seen = string(nested["raw"].(json.RawMessage))
nested["raw"].(json.RawMessage)[0] = '['
nested["changed"] = true
return contracts.ValidationResult{Approved: true}, nil
}
func (r *extractCaptureRecorder) ExtractSucceeded(_ string, _ string, _ []CheckpointFingerprint, outputs []CheckpointArtifact, rejected []contracts.RejectedOutput, warnings []contracts.Warning) error {
r.checkpoint = ExtractCheckpoint{
Outputs: cloneCheckpointArtifacts(outputs),
@@ -77,6 +95,46 @@ func TestRunnerPassesIndependentAnnotationScopesToExtractors(t *testing.T) {
}
}
func TestRunnerPassesIndependentConcreteMetadataToValidatorsAndExtractors(t *testing.T) {
prepared := preparedAttemptDebugPipeline(t)
input := prepared.input.(*typedTestInput)
input.doc.Units[0].Metadata = map[string]any{
"typed": pipelineTypedMetadata{"raw": json.RawMessage(`{"value":true}`)},
}
var err error
input.doc.Digest, err = source.DigestDocument(input.doc)
if err != nil {
t.Fatal(err)
}
chunker := prepared.chunker.(*typedTestChunker)
chunker.plan = typedTestPlan(input.doc)
validator := &mutatingMetadataValidator{}
prepared.chunkValidators.validators = []preparedValidator{{
resolved: ResolvedValidator{Binding: Binding(validator.Name()), Target: ValidatorTargetChunk},
chunk: validator,
}}
var extractorSeen string
installExtractOperation(prepared, 0, func(_ context.Context, request contracts.TypedExtractionRequest) (erasedTypedResult, error) {
nested := request.Chunk.Units[0].Metadata["typed"].(pipelineTypedMetadata)
extractorSeen = string(nested["raw"].(json.RawMessage))
nested["raw"].(json.RawMessage)[0] = '['
nested["changed"] = true
return erasedTypedResult{Value: typedValueForLane(0, request.Chunk.Index)}, nil
})
if _, err := New().Run(context.Background(), RunInput{Prepared: prepared, RawInput: []byte("input")}); err != nil {
t.Fatalf("Run() error = %v", err)
}
if validator.seen != `{"value":true}` || extractorSeen != `{"value":true}` {
t.Fatalf("validator/extractor metadata = %q / %q", validator.seen, extractorSeen)
}
original := input.doc.Units[0].Metadata["typed"].(pipelineTypedMetadata)
if _, changed := original["changed"]; changed || string(original["raw"].(json.RawMessage)) != `{"value":true}` {
t.Fatalf("source metadata changed through runner handoff: %#v", original)
}
}
func TestRunnerContinuesFromFreshAndReusedExtractResults(t *testing.T) {
prepared := preparedAttemptDebugPipeline(t)
extractCalls := 0