STET

agent_patch

runs/2026-02-28__13-38-10__gpt-5-1-codex-mini/flux-pr-1293/flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/agent-logs/agent.patch

34208 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
index 3acdd07..0c4d72c 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
+++ b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
@@ -1823,6 +1823,7 @@ func (f *Factory[T]) PlanningBehavior() plan.DataSourcePlanningBehavior {
 		OverrideFieldPathFromAlias: true,
 		AllowPlanningTypeName:      true,
 		AlwaysFlattenFragments:     f.grpcClient != nil || f.grpcClientProvider != nil,
+		BuildFetchReasons:          true,
 	}
 	return b
 }
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_federation_test.go b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_federation_test.go
index 2e881ca..3a765cb 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_federation_test.go
+++ b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_federation_test.go
@@ -3092,35 +3092,63 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 										FetchID: 0,
 									},
 									DataSourceIdentifier: []byte("graphql_datasource.Source"),
-									FetchConfiguration: resolve.FetchConfiguration{
-										Input:          `{"method":"POST","url":"http://user.service","body":{"query":"{user {account {address {line1 line2 __typename id}}}}"}}`,
-										DataSource:     &Source{},
-										PostProcessing: DefaultPostProcessingConfiguration,
-										FieldFetchReasons: []resolve.FetchReason{
-											{
-												TypeName:  "Address",
-												FieldName: "id",
-												BySubgraphs: []string{
-													"account.service",
-													"address-enricher.service",
-													"address.service",
-												},
-												IsKey: true,
-											},
-											{
-												TypeName:    "Address",
-												FieldName:   "line1",
-												BySubgraphs: []string{"account.service"},
-												IsRequires:  true,
-											},
-											{
-												TypeName:    "Address",
-												FieldName:   "line2",
-												BySubgraphs: []string{"account.service"},
-												IsRequires:  true,
-											},
+								FetchConfiguration: resolve.FetchConfiguration{
+									Input:          `{"method":"POST","url":"http://user.service","body":{"query":"{user {account {address {line1 line2 __typename id}}}}"}}`,
+									DataSource:     &Source{},
+									PostProcessing: DefaultPostProcessingConfiguration,
+								},
+								Info: &resolve.FetchInfo{
+									DataSourceID:   "user.service",
+									DataSourceName: "user.service",
+									FetchReasons: []resolve.FetchReason{
+										{
+											TypeName:  "Address",
+											FieldName: "id",
+											BySubgraphs: []string{
+												"account.service",
+												"address-enricher.service",
+												"address.service",
+											},
+											IsKey: true,
+										},
+										{
+											TypeName:    "Address",
+											FieldName:   "line1",
+											BySubgraphs: []string{"account.service"},
+											IsRequires:  true,
+										},
+										{
+											TypeName:    "Address",
+											FieldName:   "line2",
+											BySubgraphs: []string{"account.service"},
+											IsRequires:  true,
+										},
+									},
+									PropagatedFetchReasons: []resolve.FetchReason{
+										{
+											TypeName:  "Address",
+											FieldName: "id",
+											BySubgraphs: []string{
+												"account.service",
+												"address-enricher.service",
+												"address.service",
+											},
+											IsKey: true,
+										},
+										{
+											TypeName:    "Address",
+											FieldName:   "line1",
+											BySubgraphs: []string{"account.service"},
+											IsRequires:  true,
+										},
+										{
+											TypeName:    "Address",
+											FieldName:   "line2",
+											BySubgraphs: []string{"account.service"},
+											IsRequires:  true,
 										},
 									},
+								},
 								}),
 								resolve.SingleWithPath(&resolve.SingleFetch{
 									FetchDependencies: resolve.FetchDependencies{
@@ -3128,45 +3156,86 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 										DependsOnFetchIDs: []int{0},
 									},
 									DataSourceIdentifier: []byte("graphql_datasource.Source"),
-									FetchConfiguration: resolve.FetchConfiguration{
-										Input:      `{"method":"POST","url":"http://address-enricher.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Address {__typename country city}}}","variables":{"representations":[$$0$$]}}}`,
-										DataSource: &Source{},
-										CoordinateDependencies: []resolve.FetchDependency{
-											{
-												Coordinate: resolve.GraphCoordinate{
-													TypeName:  "Address",
-													FieldName: "country",
-												},
-												DependsOn: []resolve.FetchDependencyOrigin{
-													{
-														FetchID:  0,
-														Subgraph: "user.service",
-														Coordinate: resolve.GraphCoordinate{
-															TypeName:  "Address",
-															FieldName: "id",
+										FetchConfiguration: resolve.FetchConfiguration{
+											Input:      `{"method":"POST","url":"http://address-enricher.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Address {__typename country city}}}","variables":{"representations":[$$0$$]}}}`,
+											DataSource: &Source{},
+											PostProcessing:      SingleEntityPostProcessingConfiguration,
+											RequiresEntityFetch: true,
+											Variables: []resolve.Variable{
+												&resolve.ResolvableObjectVariable{
+													Renderer: resolve.NewGraphQLVariableResolveRenderer(&resolve.Object{
+														Nullable: true,
+														Fields: []*resolve.Field{
+															{
+																Name: []byte("__typename"),
+																Value: &resolve.String{
+																	Path: []string{"__typename"},
+																},
+																OnTypeNames: [][]byte{[]byte("Address")},
+															},
+															{
+																Name: []byte("id"),
+																Value: &resolve.Scalar{
+																	Path: []string{"id"},
+																},
+																OnTypeNames: [][]byte{[]byte("Address")},
+															},
 														},
-														IsKey: true,
-													},
+													}),
 												},
 											},
-											{
-												Coordinate: resolve.GraphCoordinate{
-													TypeName:  "Address",
-													FieldName: "city",
+											SetTemplateOutputToNullOnVariableNull: true,
+										},
+										Info: &resolve.FetchInfo{
+											DataSourceID:   "address-enricher.service",
+											DataSourceName: "address-enricher.service",
+											CoordinateDependencies: []resolve.FetchDependency{
+												{
+													Coordinate: resolve.GraphCoordinate{
+														TypeName:  "Address",
+														FieldName: "country",
+													},
+													DependsOn: []resolve.FetchDependencyOrigin{
+														{
+															FetchID:  0,
+															Subgraph: "user.service",
+															Coordinate: resolve.GraphCoordinate{
+																TypeName:  "Address",
+																FieldName: "id",
+															},
+															IsKey: true,
+														},
+													},
 												},
-												DependsOn: []resolve.FetchDependencyOrigin{
-													{
-														FetchID:  0,
-														Subgraph: "user.service",
-														Coordinate: resolve.GraphCoordinate{
-															TypeName:  "Address",
-															FieldName: "id",
+												{
+													Coordinate: resolve.GraphCoordinate{
+														TypeName:  "Address",
+														FieldName: "city",
+													},
+													DependsOn: []resolve.FetchDependencyOrigin{
+														{
+															FetchID:  0,
+															Subgraph: "user.service",
+															Coordinate: resolve.GraphCoordinate{
+																TypeName:  "Address",
+																FieldName: "id",
+															},
+															IsKey: true,
 														},
-														IsKey: true,
 													},
 												},
 											},
 										},
+								}, "user.account.address", resolve.ObjectPath("user"), resolve.ObjectPath("account"), resolve.ObjectPath("address")),
+								resolve.SingleWithPath(&resolve.SingleFetch{
+									FetchDependencies: resolve.FetchDependencies{
+										FetchID:           2,
+										DependsOnFetchIDs: []int{0, 1},
+									},
+									DataSourceIdentifier: []byte("graphql_datasource.Source"),
+									FetchConfiguration: resolve.FetchConfiguration{
+										Input:               `{"method":"POST","url":"http://address.service","body":{"query":"query($representations: [_Any!]!, $a: String!){_entities(representations: $representations){... on Address {__typename line3(test: $a) zip}}}","variables":{"a":"BOOM","representations":[$$0$$]}}}`,
+										DataSource:          &Source{},
 										PostProcessing:      SingleEntityPostProcessingConfiguration,
 										RequiresEntityFetch: true,
 										Variables: []resolve.Variable{
@@ -3188,24 +3257,29 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 															},
 															OnTypeNames: [][]byte{[]byte("Address")},
 														},
+														{
+															Name: []byte("country"),
+															Value: &resolve.String{
+																Path: []string{"country"},
+															},
+															OnTypeNames: [][]byte{[]byte("Address")},
+														},
+														{
+															Name: []byte("city"),
+															Value: &resolve.String{
+																Path: []string{"city"},
+															},
+															OnTypeNames: [][]byte{[]byte("Address")},
+														},
 													},
 												}),
 											},
 										},
 										SetTemplateOutputToNullOnVariableNull: true,
 									},
-								}, "user.account.address", resolve.ObjectPath("user"), resolve.ObjectPath("account"), resolve.ObjectPath("address")),
-								resolve.SingleWithPath(&resolve.SingleFetch{
-									FetchDependencies: resolve.FetchDependencies{
-										FetchID:           2,
-										DependsOnFetchIDs: []int{0, 1},
-									},
-									DataSourceIdentifier: []byte("graphql_datasource.Source"),
-									FetchConfiguration: resolve.FetchConfiguration{
-										Input:               `{"method":"POST","url":"http://address.service","body":{"query":"query($representations: [_Any!]!, $a: String!){_entities(representations: $representations){... on Address {__typename line3(test: $a) zip}}}","variables":{"a":"BOOM","representations":[$$0$$]}}}`,
-										DataSource:          &Source{},
-										PostProcessing:      SingleEntityPostProcessingConfiguration,
-										RequiresEntityFetch: true,
+									Info: &resolve.FetchInfo{
+										DataSourceID:   "address.service",
+										DataSourceName: "address.service",
 										CoordinateDependencies: []resolve.FetchDependency{
 											{
 												Coordinate: resolve.GraphCoordinate{
@@ -3260,7 +3334,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 												},
 											},
 										},
-										FieldFetchReasons: []resolve.FetchReason{
+										FetchReasons: []resolve.FetchReason{
 											{
 												TypeName:    "Address",
 												FieldName:   "line3",
@@ -3274,44 +3348,20 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 												IsRequires:  true,
 											},
 										},
-										Variables: []resolve.Variable{
-											&resolve.ResolvableObjectVariable{
-												Renderer: resolve.NewGraphQLVariableResolveRenderer(&resolve.Object{
-													Nullable: true,
-													Fields: []*resolve.Field{
-														{
-															Name: []byte("__typename"),
-															Value: &resolve.String{
-																Path: []string{"__typename"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("id"),
-															Value: &resolve.Scalar{
-																Path: []string{"id"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("country"),
-															Value: &resolve.String{
-																Path: []string{"country"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("city"),
-															Value: &resolve.String{
-																Path: []string{"city"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-													},
-												}),
+										PropagatedFetchReasons: []resolve.FetchReason{
+											{
+												TypeName:    "Address",
+												FieldName:   "line3",
+												BySubgraphs: []string{"account.service"},
+												IsRequires:  true,
+											},
+											{
+												TypeName:    "Address",
+												FieldName:   "zip",
+												BySubgraphs: []string{"account.service"},
+												IsRequires:  true,
 											},
 										},
-										SetTemplateOutputToNullOnVariableNull: true,
 									},
 								}, "user.account.address", resolve.ObjectPath("user"), resolve.ObjectPath("account"), resolve.ObjectPath("address")),
 								resolve.SingleWithPath(&resolve.SingleFetch{
@@ -3324,7 +3374,6 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 										Input:          `{"method":"POST","url":"http://account.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Address {__typename fullAddress}}}","variables":{"representations":[$$0$$]}}}`,
 										DataSource:     &Source{},
 										PostProcessing: SingleEntityPostProcessingConfiguration,
-										CoordinateDependencies: []resolve.FetchDependency{
 											{
 												Coordinate: resolve.GraphCoordinate{
 													TypeName:  "Address",
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/datasource_configuration.go b/app/v2/pkg/engine/plan/datasource_configuration.go
index 2601a43..af5e545 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/datasource_configuration.go
+++ b/app/v2/pkg/engine/plan/datasource_configuration.go
@@ -444,6 +444,9 @@ type DataSourcePlanningBehavior struct {
 	// If true then planner will rewrite the operation
 	// to flatten inline fragments to only the concrete types.
 	AlwaysFlattenFragments bool
+
+	// BuildFetchReasons controls whether the planner should compute fetch reason metadata for this datasource.
+	BuildFetchReasons bool
 }
 
 type DataSourceFetchPlanner interface {
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/federation_metadata.go b/app/v2/pkg/engine/plan/federation_metadata.go
index b4479a4..ed260f9 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/federation_metadata.go
+++ b/app/v2/pkg/engine/plan/federation_metadata.go
@@ -82,15 +82,10 @@ type FederationFieldConfiguration struct {
 }
 
 type KeyCondition struct {
-	Coordinates []KeyConditionCoordinate `json:"coordinates"`
+	Coordinates []FieldCoordinate `json:"coordinates"`
 	FieldPath   []string                 `json:"field_path"`
 }
 
-type KeyConditionCoordinate struct {
-	TypeName  string `json:"type_name"`
-	FieldName string `json:"field_name"`
-}
-
 func (f *FederationFieldConfiguration) parseSelectionSet() error {
 	if f.parsedSelectionSet != nil {
 		return nil
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/node_selection_visitor.go b/app/v2/pkg/engine/plan/node_selection_visitor.go
index 6a1259a..2273710 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/node_selection_visitor.go
+++ b/app/v2/pkg/engine/plan/node_selection_visitor.go
@@ -45,7 +45,7 @@ type nodeSelectionVisitor struct {
 	hasNewFields        bool // hasNewFields is used to determine if we need to run the planner again. It will be true in case required fields were added
 	hasUnresolvedFields bool // hasUnresolvedFields is used to determine if we need to run the planner again. We should set it to true in case we have unresolved fields
 
-	fieldPathCoordinates []KeyConditionCoordinate // currentFieldPathCoordinates is a stack of field path coordinates // TODO: remove me
+	fieldPathCoordinates []FieldCoordinate // currentFieldPathCoordinates is a stack of field path coordinates // TODO: remove me
 	rewrittenFieldRefs   []int
 }
 
@@ -128,7 +128,7 @@ func (c *nodeSelectionVisitor) EnterDocument(operation, definition *ast.Document
 	}
 
 	if c.fieldPathCoordinates == nil {
-		c.fieldPathCoordinates = make([]KeyConditionCoordinate, 0, 8)
+		c.fieldPathCoordinates = make([]FieldCoordinate, 0, 8)
 	} else {
 		c.fieldPathCoordinates = c.fieldPathCoordinates[:0]
 	}
@@ -219,7 +219,7 @@ func (c *nodeSelectionVisitor) EnterField(fieldRef int) {
 		c.rewriteSelectionSetHavingAbstractFragments(fieldRef, ds)
 	}
 
-	c.fieldPathCoordinates = append(c.fieldPathCoordinates, KeyConditionCoordinate{
+	c.fieldPathCoordinates = append(c.fieldPathCoordinates, FieldCoordinate{
 		FieldName: fieldName,
 		TypeName:  typeName,
 	})
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/type_field.go b/app/v2/pkg/engine/plan/type_field.go
index e3dfa26..521a62a 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/type_field.go
+++ b/app/v2/pkg/engine/plan/type_field.go
@@ -8,3 +8,8 @@ type TypeField struct {
 }
 
 type TypeFields []TypeField
+
+type FieldCoordinate struct {
+	TypeName  string `json:"type_name"`
+	FieldName string `json:"field_name"`
+}
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/visitor.go b/app/v2/pkg/engine/plan/visitor.go
index 382be28..5c0b878 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/visitor.go
+++ b/app/v2/pkg/engine/plan/visitor.go
@@ -1326,18 +1326,20 @@ func (v *Visitor) configureFetch(internal *objectFetchConfiguration, external re
 	}
 
 	if !v.Config.DisableIncludeInfo {
-		singleFetch.Info = &resolve.FetchInfo{
+		info := &resolve.FetchInfo{
 			DataSourceID:   internal.sourceID,
 			DataSourceName: internal.sourceName,
 			RootFields:     internal.rootFields,
 			OperationType:  internal.operationType,
 			QueryPlan:      external.QueryPlan,
 		}
-	}
-
-	if !v.Config.DisableIncludeFieldDependencies {
-		singleFetch.CoordinateDependencies = v.resolveFetchDependencies(internal.fetchID)
-		singleFetch.FieldFetchReasons = v.buildFetchReasons(internal.fetchID)
+		if !v.Config.DisableIncludeFieldDependencies {
+			info.CoordinateDependencies = v.resolveFetchDependencies(internal.fetchID)
+			if dsConfig := v.planners[internal.fetchID].DataSourceConfiguration(); dsConfig != nil && dsConfig.PlanningBehavior().BuildFetchReasons {
+				info.FetchReasons, info.PropagatedFetchReasons = v.buildFetchReasons(internal.fetchID, dsConfig)
+			}
+		}
+		singleFetch.Info = info
 	}
 
 	return singleFetch
@@ -1398,12 +1400,11 @@ func (v *Visitor) resolveFetchDependencies(fetchID int) []resolve.FetchDependenc
 	return dependencies
 }
 
-func (v *Visitor) buildFetchReasons(fetchID int) []resolve.FetchReason {
+func (v *Visitor) buildFetchReasons(fetchID int, dsConfig DataSource) ([]resolve.FetchReason, []resolve.FetchReason) {
 	fields, ok := v.plannerFields[fetchID]
 	if !ok {
-		return nil
+		return nil, nil
 	}
-	dsConfig := v.planners[fetchID].DataSourceConfiguration()
 
 	type typedField struct {
 		typeName string
@@ -1418,9 +1419,6 @@ func (v *Visitor) buildFetchReasons(fetchID int) []resolve.FetchReason {
 			continue
 		}
 		typeName := v.fieldEnclosingTypeNames[fieldRef]
-		if !dsConfig.RequiresFetchReason(typeName, fieldName) {
-			continue
-		}
 
 		byUser := !v.skipField(fieldRef)
 		dependants, ok := v.fieldRefDependants[fieldRef]
@@ -1471,14 +1469,14 @@ func (v *Visitor) buildFetchReasons(fetchID int) []resolve.FetchReason {
 					reasons[i].IsRequires = reasons[i].IsRequires || isRequires
 				}
 			} else {
-				reasons = append(reasons, resolve.FetchReason{
-					TypeName:    typeName,
-					FieldName:   fieldName,
-					BySubgraphs: subgraphs,
-					ByUser:      byUser,
-					IsKey:       isKey,
-					IsRequires:  isRequires,
-				})
+			reasons = append(reasons, resolve.FetchReason{
+				TypeName:    typeName,
+				FieldName:   fieldName,
+				BySubgraphs: subgraphs,
+				ByUser:      byUser,
+				IsKey:       isKey,
+				IsRequires:  isRequires,
+			})
 				i = len(reasons) - 1
 				index[key] = i
 			}
@@ -1495,5 +1493,15 @@ func (v *Visitor) buildFetchReasons(fetchID int) []resolve.FetchReason {
 			cmp.Compare(a.FieldName, b.FieldName),
 		)
 	})
-	return reasons
+	if dsConfig == nil {
+		return reasons, nil
+	}
+
+	var propagated []resolve.FetchReason
+	for _, reason := range reasons {
+		if dsConfig.RequiresFetchReason(reason.TypeName, reason.FieldName) {
+			propagated = append(propagated, reason)
+		}
+	}
+	return reasons, propagated
 }
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/postprocess/create_concrete_single_fetch_types.go b/app/v2/pkg/engine/postprocess/create_concrete_single_fetch_types.go
index 3d6a00b..89f3b08 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/postprocess/create_concrete_single_fetch_types.go
+++ b/app/v2/pkg/engine/postprocess/create_concrete_single_fetch_types.go
@@ -76,8 +76,6 @@ func (d *createConcreteSingleFetchTypes) createEntityBatchFetch(fetch *resolve.S
 
 	return &resolve.BatchEntityFetch{
 		FetchDependencies:      fetch.FetchDependencies,
-		CoordinateDependencies: fetch.CoordinateDependencies,
-		FieldFetchReasons:      fetch.FieldFetchReasons,
 		Info:                   fetch.Info,
 		Input: resolve.BatchInput{
 			Header: resolve.InputTemplate{
@@ -123,8 +121,6 @@ func (d *createConcreteSingleFetchTypes) createEntityFetch(fetch *resolve.Single
 
 	return &resolve.EntityFetch{
 		FetchDependencies:      fetch.FetchDependencies,
-		CoordinateDependencies: fetch.CoordinateDependencies,
-		FieldFetchReasons:      fetch.FieldFetchReasons,
 		Info:                   fetch.Info,
 		Input: resolve.EntityInput{
 			Header: resolve.InputTemplate{
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go b/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go
index 9a0121b..3256351 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go
+++ b/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go
@@ -97,8 +97,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 								FetchID:           1,
 								DependsOnFetchIDs: []int{0},
 							},
-							FetchConfiguration: resolve.FetchConfiguration{
-								Input: "a",
+							FetchConfiguration: resolve.FetchConfiguration{Input: "a"},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -121,8 +121,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 								FetchID:           2,
 								DependsOnFetchIDs: []int{0},
 							},
-							FetchConfiguration: resolve.FetchConfiguration{
-								Input: "a",
+							FetchConfiguration: resolve.FetchConfiguration{Input: "a"},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -145,8 +145,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 								FetchID:           4,
 								DependsOnFetchIDs: []int{0, 2},
 							},
-							FetchConfiguration: resolve.FetchConfiguration{
-								Input: "b",
+							FetchConfiguration: resolve.FetchConfiguration{Input: "b"},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -172,8 +172,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 								FetchID:           3,
 								DependsOnFetchIDs: []int{0, 1},
 							},
-							FetchConfiguration: resolve.FetchConfiguration{
-								Input: "b",
+							FetchConfiguration: resolve.FetchConfiguration{Input: "b"},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -217,8 +217,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 								FetchID:           1,
 								DependsOnFetchIDs: []int{0},
 							},
-							FetchConfiguration: resolve.FetchConfiguration{
-								Input: "a",
+							FetchConfiguration: resolve.FetchConfiguration{Input: "a"},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -241,8 +241,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 								FetchID:           4,
 								DependsOnFetchIDs: []int{0, 1},
 							},
-							FetchConfiguration: resolve.FetchConfiguration{
-								Input: "b",
+							FetchConfiguration: resolve.FetchConfiguration{Input: "b"},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/fetch.go b/app/v2/pkg/engine/resolve/fetch.go
index 137670b..69430b4 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/fetch.go
+++ b/app/v2/pkg/engine/resolve/fetch.go
@@ -102,11 +102,17 @@ func (s *SingleFetch) Dependencies() *FetchDependencies {
 }
 
 func (s *SingleFetch) DependenciesCoordinates() []FetchDependency {
-	return s.CoordinateDependencies
+	if s.Info == nil {
+		return nil
+	}
+	return s.Info.CoordinateDependencies
 }
 
 func (s *SingleFetch) FetchReasons() []FetchReason {
-	return s.FieldFetchReasons
+	if s.Info == nil {
+		return nil
+	}
+	return s.Info.PropagatedFetchReasons
 }
 
 func (s *SingleFetch) DataSourceInfo() DataSourceInfo {
@@ -176,8 +182,6 @@ type BatchEntityFetch struct {
 	DataSourceIdentifier   []byte
 	Trace                  *DataSourceLoadTrace
 	Info                   *FetchInfo
-	CoordinateDependencies []FetchDependency
-	FieldFetchReasons      []FetchReason
 }
 
 func (b *BatchEntityFetch) Dependencies() *FetchDependencies {
@@ -185,11 +189,17 @@ func (b *BatchEntityFetch) Dependencies() *FetchDependencies {
 }
 
 func (b *BatchEntityFetch) DependenciesCoordinates() []FetchDependency {
-	return b.CoordinateDependencies
+	if b.Info == nil {
+		return nil
+	}
+	return b.Info.CoordinateDependencies
 }
 
 func (b *BatchEntityFetch) FetchReasons() []FetchReason {
-	return b.FieldFetchReasons
+	if b.Info == nil {
+		return nil
+	}
+	return b.Info.PropagatedFetchReasons
 }
 
 func (b *BatchEntityFetch) DataSourceInfo() DataSourceInfo {
@@ -229,8 +239,6 @@ type EntityFetch struct {
 	DataSourceIdentifier   []byte
 	Trace                  *DataSourceLoadTrace
 	Info                   *FetchInfo
-	CoordinateDependencies []FetchDependency
-	FieldFetchReasons      []FetchReason
 }
 
 func (e *EntityFetch) Dependencies() *FetchDependencies {
@@ -238,11 +246,17 @@ func (e *EntityFetch) Dependencies() *FetchDependencies {
 }
 
 func (e *EntityFetch) DependenciesCoordinates() []FetchDependency {
-	return e.CoordinateDependencies
+	if e.Info == nil {
+		return nil
+	}
+	return e.Info.CoordinateDependencies
 }
 
 func (e *EntityFetch) FetchReasons() []FetchReason {
-	return e.FieldFetchReasons
+	if e.Info == nil {
+		return nil
+	}
+	return e.Info.PropagatedFetchReasons
 }
 
 func (e *EntityFetch) DataSourceInfo() DataSourceInfo {
@@ -277,11 +291,11 @@ func (p *ParallelListItemFetch) Dependencies() *FetchDependencies {
 }
 
 func (p *ParallelListItemFetch) DependenciesCoordinates() []FetchDependency {
-	return p.Fetch.CoordinateDependencies
+	return p.Fetch.DependenciesCoordinates()
 }
 
 func (p *ParallelListItemFetch) FetchReasons() []FetchReason {
-	return p.Fetch.FieldFetchReasons
+	return p.Fetch.FetchReasons()
 }
 
 func (*ParallelListItemFetch) FetchKind() FetchKind {
@@ -341,17 +355,6 @@ type FetchConfiguration struct {
 
 	QueryPlan *QueryPlan
 
-	// CoordinateDependencies contain a list of GraphCoordinates (typeName+fieldName)
-	// and which fields from other fetches they depend on.
-	// This information is useful to understand why a fetch depends on other fetches,
-	// and how multiple dependencies lead to a chain of fetches
-	CoordinateDependencies []FetchDependency
-
-	// FieldFetchReasons contains provenance for fields that require fetch reason to be propagated
-	// to their subgraph. It is optional propagation via request extensions;
-	// it does not affect execution.
-	FieldFetchReasons []FetchReason
-
 	// OperationName is non-empty when the operation name is propagated to the upstream subgraph fetch.
 	OperationName string
 }
@@ -367,11 +370,6 @@ func (fc *FetchConfiguration) Equals(other *FetchConfiguration) bool {
 	}
 
 	// Note: we do not compare datasources, as they will always be a different instance.
-	// Note: we do not compare CoordinateDependencies, as they contain more detailed
-	// dependencies information that is already present in the FetchDependencies on the fetch itself.
-	// Note: we do not compare FieldFetchReasons, as it is derived data for an extension
-	// and does not affect fetch execution semantics.
-
 	if fc.RequiresParallelListItemFetch != other.RequiresParallelListItemFetch {
 		return false
 	}
@@ -435,6 +433,13 @@ type FetchInfo struct {
 	RootFields     []GraphCoordinate
 	OperationType  ast.OperationType
 	QueryPlan      *QueryPlan
+	// CoordinateDependencies contain a list of GraphCoordinates (typeName+fieldName)
+	// and which fields from other fetches they depend on.
+	CoordinateDependencies []FetchDependency
+	// FetchReasons contains all computed reasons for the fields planned on this fetch.
+	FetchReasons []FetchReason
+	// PropagatedFetchReasons lists the subset of reasons that should be sent to the upstream subgraph.
+	PropagatedFetchReasons []FetchReason
 }
 
 type GraphCoordinate struct {
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/fetchtree.go b/app/v2/pkg/engine/resolve/fetchtree.go
index ad1eb2f..5088938 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/fetchtree.go
+++ b/app/v2/pkg/engine/resolve/fetchtree.go
@@ -209,6 +209,10 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 	case FetchTreeNodeKindSingle:
 		switch f := n.Item.Fetch.(type) {
 		case *SingleFetch:
+			var dependencies []FetchDependency
+			if f.Info != nil {
+				dependencies = f.Info.CoordinateDependencies
+			}
 			queryPlan.Fetch = &FetchTreeQueryPlan{
 				Kind:              "Single",
 				FetchID:           f.FetchDependencies.FetchID,
@@ -216,7 +220,7 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				SubgraphName:      f.Info.DataSourceName,
 				SubgraphID:        f.Info.DataSourceID,
 				Path:              n.Item.ResponsePath,
-				Dependencies:      f.FetchConfiguration.CoordinateDependencies,
+				Dependencies:      dependencies,
 			}
 
 			if f.Info.QueryPlan != nil {
@@ -224,6 +228,10 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				queryPlan.Fetch.Representations = f.Info.QueryPlan.DependsOnFields
 			}
 		case *EntityFetch:
+			var dependencies []FetchDependency
+			if f.Info != nil {
+				dependencies = f.Info.CoordinateDependencies
+			}
 			queryPlan.Fetch = &FetchTreeQueryPlan{
 				Kind:              "Entity",
 				FetchID:           f.FetchDependencies.FetchID,
@@ -231,7 +239,7 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				SubgraphName:      f.Info.DataSourceName,
 				SubgraphID:        f.Info.DataSourceID,
 				Path:              n.Item.ResponsePath,
-				Dependencies:      f.CoordinateDependencies,
+				Dependencies:      dependencies,
 			}
 
 			if f.Info.QueryPlan != nil {
@@ -239,6 +247,10 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				queryPlan.Fetch.Representations = f.Info.QueryPlan.DependsOnFields
 			}
 		case *BatchEntityFetch:
+			var dependencies []FetchDependency
+			if f.Info != nil {
+				dependencies = f.Info.CoordinateDependencies
+			}
 			queryPlan.Fetch = &FetchTreeQueryPlan{
 				Kind:              "BatchEntity",
 				FetchID:           f.FetchDependencies.FetchID,
@@ -246,7 +258,7 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				SubgraphName:      f.Info.DataSourceName,
 				SubgraphID:        f.Info.DataSourceID,
 				Path:              n.Item.ResponsePath,
-				Dependencies:      f.CoordinateDependencies,
+				Dependencies:      dependencies,
 			}
 
 			if f.Info.QueryPlan != nil {