Implement generated artifact handoff and provenance

This commit is contained in:
2026-07-21 21:39:23 +00:00
parent afb7ed3cf1
commit 22d4f29670
12 changed files with 749 additions and 85 deletions

View File

@@ -119,23 +119,38 @@ func (a *countingInputAdapter) Parse(ctx context.Context, request contracts.Pars
return a.InputAdapter.Parse(ctx, request)
}
func TestRunnerRejectsGeneratedBindingsBeforeSourceParsing(t *testing.T) {
func TestRunnerFailsGeneratedHandoffBeforeConsumerExtraction(t *testing.T) {
prepared := preparedConcurrentPipeline(t, 1)
input := &countingInputAdapter{InputAdapter: prepared.input}
prepared.input = input
prepared.resolved.Steps[0].ArtifactLanes[0].ExtractReferences.Bindings = []ReferenceBinding{{
preparedLane := &prepared.Steps[0].lanes[0]
lane := &preparedLane.resolved
binding := ReferenceBinding{
Stage: StageExtract,
LaneID: prepared.resolved.Steps[0].ArtifactLanes[0].ID,
LaneID: lane.ID,
SlotName: "generated",
Artifact: &ArtifactReference{Step: "producer", Lane: "source"},
}
lane.ExtractReferences.Bindings = []ReferenceBinding{binding}
lane.ExtractReferences.ReferenceSet = contracts.ReferenceSet{Slots: map[string]contracts.ResolvedReferenceSlot{
"generated": {Slot: contracts.ReferenceSlot{Name: "generated", AcceptedArtifactKinds: []contracts.ArtifactKind{"test/notes"}}},
}}
prepared.resolved.Steps[0].ArtifactLanes[0].ExtractReferences = CloneReferenceTarget(lane.ExtractReferences)
var extractCalls atomic.Int32
preparedLane.typed.extract = func(context.Context, any, contracts.TypedExtractionRequest) (erasedTypedResult, error) {
extractCalls.Add(1)
return erasedTypedResult{Value: codecNotes{}}, nil
}
_, err := New().Run(context.Background(), RunInput{Prepared: prepared, RawInput: []byte("input")})
if err == nil || !strings.Contains(err.Error(), "generated reference execution is not supported yet") {
t.Fatalf("Run() error = %v, want generated binding rejection", err)
if err == nil || !strings.Contains(err.Error(), "generated dependency") {
t.Fatalf("Run() error = %v, want generated dependency failure", err)
}
if got := input.calls.Load(); got != 0 {
t.Fatalf("input Parse calls = %d, want zero", got)
if got := input.calls.Load(); got != 1 {
t.Fatalf("input Parse calls = %d, want one before handoff", got)
}
if got := extractCalls.Load(); got != 0 {
t.Fatalf("consumer extract calls = %d, want zero", got)
}
}