STET

agent_patch

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

38761 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/engine/execution_engine.go b/app/execution/engine/execution_engine.go
index 51b2742..42302aa 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/engine/execution_engine.go
+++ b/app/execution/engine/execution_engine.go
@@ -66,6 +66,7 @@ type ExecutionEngine struct {
 	logger                   abstractlogger.Logger
 	config                   Configuration
 	resolver                 *resolve.Resolver
+	buildFetchReasons        bool
 	executionPlanCache       *lru.Cache
 	apolloCompatibilityFlags apollocompatibility.Flags
 }
@@ -140,6 +141,7 @@ func NewExecutionEngine(ctx context.Context, logger abstractlogger.Logger, engin
 		logger:             logger,
 		config:             engineConfig,
 		resolver:           resolve.New(ctx, resolverOptions),
+		buildFetchReasons:  resolverOptions.PropagateFetchReasons,
 		executionPlanCache: executionPlanCache,
 		apolloCompatibilityFlags: apollocompatibility.Flags{
 			ReplaceInvalidVarError: resolverOptions.ResolvableOptions.ApolloCompatibilityReplaceInvalidVarError,
@@ -255,7 +257,11 @@ func (e *ExecutionEngine) getCachedPlan(ctx *internalExecutionContext, operation
 	}
 
 	planner, _ := plan.NewPlanner(e.config.plannerConfig)
-	planResult := planner.Plan(operation, definition, operationName, report)
+	var planOptions []plan.Opts
+	if e.buildFetchReasons {
+		planOptions = append(planOptions, plan.BuildFetchReasons())
+	}
+	planResult := planner.Plan(operation, definition, operationName, report, planOptions...)
 	if report.HasErrors() {
 		return nil
 	}
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/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..2d369ac 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/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
@@ -3096,7 +3096,33 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 										Input:          `{"method":"POST","url":"http://user.service","body":{"query":"{user {account {address {line1 line2 __typename id}}}}"}}`,
 										DataSource:     &Source{},
 										PostProcessing: DefaultPostProcessingConfiguration,
-										FieldFetchReasons: []resolve.FetchReason{
+									},
+									Info: &resolve.FetchInfo{
+										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",
@@ -3129,8 +3155,36 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 									},
 									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{},
+										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")},
+														},
+													},
+												}),
+											},
+										},
+										SetTemplateOutputToNullOnVariableNull: true,
+									},
+									Info: &resolve.FetchInfo{
 										CoordinateDependencies: []resolve.FetchDependency{
 											{
 												Coordinate: resolve.GraphCoordinate{
@@ -3167,6 +3221,17 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 												},
 											},
 										},
+									},
+								}, "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 +3253,27 @@ 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{
 										CoordinateDependencies: []resolve.FetchDependency{
 											{
 												Coordinate: resolve.GraphCoordinate{
@@ -3260,7 +3328,21 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 												},
 											},
 										},
-										FieldFetchReasons: []resolve.FetchReason{
+										FetchReasons: []resolve.FetchReason{
+											{
+												TypeName:    "Address",
+												FieldName:   "line3",
+												BySubgraphs: []string{"account.service"},
+												IsRequires:  true,
+											},
+											{
+												TypeName:    "Address",
+												FieldName:   "zip",
+												BySubgraphs: []string{"account.service"},
+												IsRequires:  true,
+											},
+										},
+										PropagatedFetchReasons: []resolve.FetchReason{
 											{
 												TypeName:    "Address",
 												FieldName:   "line3",
@@ -3274,6 +3356,19 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 												IsRequires:  true,
 											},
 										},
+									},
+								}, "user.account.address", resolve.ObjectPath("user"), resolve.ObjectPath("account"), resolve.ObjectPath("address")),
+								resolve.SingleWithPath(&resolve.SingleFetch{
+									FetchDependencies: resolve.FetchDependencies{
+										FetchID:           3,
+										DependsOnFetchIDs: []int{0, 2},
+									},
+									DataSourceIdentifier: []byte("graphql_datasource.Source"),
+									FetchConfiguration: resolve.FetchConfiguration{
+										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,
+										RequiresEntityFetch: true,
 										Variables: []resolve.Variable{
 											&resolve.ResolvableObjectVariable{
 												Renderer: resolve.NewGraphQLVariableResolveRenderer(&resolve.Object{
@@ -3287,23 +3382,37 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 															OnTypeNames: [][]byte{[]byte("Address")},
 														},
 														{
-															Name: []byte("id"),
-															Value: &resolve.Scalar{
-																Path: []string{"id"},
+															Name: []byte("line1"),
+															Value: &resolve.String{
+																Path: []string{"line1"},
 															},
 															OnTypeNames: [][]byte{[]byte("Address")},
 														},
 														{
-															Name: []byte("country"),
+															Name: []byte("line2"),
 															Value: &resolve.String{
-																Path: []string{"country"},
+																Path: []string{"line2"},
 															},
 															OnTypeNames: [][]byte{[]byte("Address")},
 														},
 														{
-															Name: []byte("city"),
+															Name: []byte("line3"),
 															Value: &resolve.String{
-																Path: []string{"city"},
+																Path: []string{"line3"},
+															},
+															OnTypeNames: [][]byte{[]byte("Address")},
+														},
+														{
+															Name: []byte("zip"),
+															Value: &resolve.String{
+																Path: []string{"zip"},
+															},
+															OnTypeNames: [][]byte{[]byte("Address")},
+														},
+														{
+															Name: []byte("id"),
+															Value: &resolve.Scalar{
+																Path: []string{"id"},
 															},
 															OnTypeNames: [][]byte{[]byte("Address")},
 														},
@@ -3313,17 +3422,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 										},
 										SetTemplateOutputToNullOnVariableNull: true,
 									},
-								}, "user.account.address", resolve.ObjectPath("user"), resolve.ObjectPath("account"), resolve.ObjectPath("address")),
-								resolve.SingleWithPath(&resolve.SingleFetch{
-									FetchDependencies: resolve.FetchDependencies{
-										FetchID:           3,
-										DependsOnFetchIDs: []int{0, 2},
-									},
-									DataSourceIdentifier: []byte("graphql_datasource.Source"),
-									FetchConfiguration: resolve.FetchConfiguration{
-										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,
+									Info: &resolve.FetchInfo{
 										CoordinateDependencies: []resolve.FetchDependency{
 											{
 												Coordinate: resolve.GraphCoordinate{
@@ -3380,59 +3479,6 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 												},
 											},
 										},
-										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("line1"),
-															Value: &resolve.String{
-																Path: []string{"line1"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("line2"),
-															Value: &resolve.String{
-																Path: []string{"line2"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("line3"),
-															Value: &resolve.String{
-																Path: []string{"line3"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("zip"),
-															Value: &resolve.String{
-																Path: []string{"zip"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-														{
-															Name: []byte("id"),
-															Value: &resolve.Scalar{
-																Path: []string{"id"},
-															},
-															OnTypeNames: [][]byte{[]byte("Address")},
-														},
-													},
-												}),
-											},
-										},
-										SetTemplateOutputToNullOnVariableNull: true,
 									},
 								}, "user.account.address", resolve.ObjectPath("user"), resolve.ObjectPath("account"), resolve.ObjectPath("address")),
 							),
@@ -3521,6 +3567,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 					},
 					WithDefaultPostProcessor(),
 					WithFieldDependencies(),
+					WithFetchReasons(),
 				)
 			})
 
@@ -16067,7 +16114,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 								SelectionSet: "id",
 								Conditions: []plan.KeyCondition{
 									{
-										Coordinates: []plan.KeyConditionCoordinate{
+										Coordinates: []plan.FieldCoordinate{
 											{
 												TypeName:  "User",
 												FieldName: "hostedImageWithProvides",
@@ -17008,7 +17055,7 @@ func TestGraphQLDataSourceFederation(t *testing.T) {
 								SelectionSet: "id",
 								Conditions: []plan.KeyCondition{
 									{
-										Coordinates: []plan.KeyConditionCoordinate{
+										Coordinates: []plan.FieldCoordinate{
 											{
 												TypeName:  "Host",
 												FieldName: "image",
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasourcetesting/datasourcetesting.go b/app/v2/pkg/engine/datasourcetesting/datasourcetesting.go
index 1b1a622..17da5ce 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasourcetesting/datasourcetesting.go
+++ b/app/v2/pkg/engine/datasourcetesting/datasourcetesting.go
@@ -33,6 +33,7 @@ type testOptions struct {
 	withFieldInfo         bool
 	withPrintPlan         bool
 	withFieldDependencies bool
+	withFetchReasons      bool
 }
 
 func WithPostProcessors(postProcessors ...*postprocess.Processor) func(*testOptions) {
@@ -74,6 +75,12 @@ func WithFieldDependencies() func(*testOptions) {
 	}
 }
 
+func WithFetchReasons() func(*testOptions) {
+	return func(o *testOptions) {
+		o.withFetchReasons = true
+	}
+}
+
 func RunWithPermutations(t *testing.T, definition, operation, operationName string, expectedPlan plan.Plan, config plan.Configuration, options ...func(*testOptions)) {
 	t.Helper()
 
@@ -177,6 +184,9 @@ func RunTestWithVariables(definition, operation, operationName, variables string
 		if opts.withPrintPlan {
 			planOpts = append(planOpts, plan.IncludeQueryPlanInResponse())
 		}
+		if opts.withFetchReasons {
+			planOpts = append(planOpts, plan.BuildFetchReasons())
+		}
 
 		actualPlan := p.Plan(&op, &def, operationName, &report, planOpts...)
 		if report.HasErrors() {
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/federation_metadata.go b/app/v2/pkg/engine/plan/federation_metadata.go
index b4479a4..994ea95 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/federation_metadata.go
+++ b/app/v2/pkg/engine/plan/federation_metadata.go
@@ -82,11 +82,11 @@ type FederationFieldConfiguration struct {
 }
 
 type KeyCondition struct {
-	Coordinates []KeyConditionCoordinate `json:"coordinates"`
-	FieldPath   []string                 `json:"field_path"`
+	Coordinates []FieldCoordinate `json:"coordinates"`
+	FieldPath   []string          `json:"field_path"`
 }
 
-type KeyConditionCoordinate struct {
+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-4/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-4/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-4/app/v2/pkg/engine/plan/planner.go b/app/v2/pkg/engine/plan/planner.go
index 25d6e89..68dc0e6 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/planner.go
+++ b/app/v2/pkg/engine/plan/planner.go
@@ -85,6 +85,7 @@ func (p *Planner) SetDebugConfig(config DebugConfiguration) {
 
 type _opts struct {
 	includeQueryPlanInResponse bool
+	buildFetchReasons          bool
 }
 
 type Opts func(*_opts)
@@ -95,6 +96,12 @@ func IncludeQueryPlanInResponse() Opts {
 	}
 }
 
+func BuildFetchReasons() Opts {
+	return func(o *_opts) {
+		o.buildFetchReasons = true
+	}
+}
+
 func (p *Planner) Plan(operation, definition *ast.Document, operationName string, report *operationreport.Report, options ...Opts) (plan Plan) {
 
 	var opts _opts
@@ -103,6 +110,7 @@ func (p *Planner) Plan(operation, definition *ast.Document, operationName string
 	}
 
 	p.planningVisitor.includeQueryPlans = opts.includeQueryPlanInResponse
+	p.planningVisitor.buildFetchReasons = opts.buildFetchReasons
 
 	p.selectOperation(operation, operationName, report)
 	if report.HasErrors() {
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/visitor.go b/app/v2/pkg/engine/plan/visitor.go
index 382be28..9f57521 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/visitor.go
+++ b/app/v2/pkg/engine/plan/visitor.go
@@ -53,6 +53,7 @@ type Visitor struct {
 	skipIncludeOnFragments       map[int]skipIncludeInfo
 	disableResolveFieldPositions bool
 	includeQueryPlans            bool
+	buildFetchReasons            bool
 	indirectInterfaceFields      map[int]indirectInterfaceField
 	pathCache                    map[astvisitor.VisitorKind]map[int]string
 
@@ -205,7 +206,7 @@ func (v *Visitor) AllowVisitor(kind astvisitor.VisitorKind, ref int, visitor any
 			}
 		}
 
-		if !v.Config.DisableIncludeFieldDependencies && kind == astvisitor.LeaveField {
+		if v.shouldTrackFetchMetadata() && kind == astvisitor.LeaveField {
 			// we don't need to do this twice, so we only do it on leave
 
 			// store which fields are planned on which planners
@@ -340,7 +341,7 @@ func (v *Visitor) LeaveSelectionSet(ref int) {
 func (v *Visitor) EnterField(ref int) {
 	v.debugOnEnterNode(ast.NodeKindField, ref)
 
-	if !v.Config.DisableIncludeFieldDependencies {
+	if v.shouldTrackFetchMetadata() {
 		v.fieldEnclosingTypeNames[ref] = strings.Clone(v.Walker.EnclosingTypeDefinition.NameString(v.Definition))
 	}
 	// check if we have to skip the field in the response
@@ -1325,24 +1326,33 @@ func (v *Visitor) configureFetch(internal *objectFetchConfiguration, external re
 		DataSourceIdentifier: []byte(dataSourceType),
 	}
 
+	if !v.Config.DisableIncludeInfo || !v.Config.DisableIncludeFieldDependencies || v.buildFetchReasons {
+		singleFetch.Info = &resolve.FetchInfo{}
+	}
+
 	if !v.Config.DisableIncludeInfo {
-		singleFetch.Info = &resolve.FetchInfo{
-			DataSourceID:   internal.sourceID,
-			DataSourceName: internal.sourceName,
-			RootFields:     internal.rootFields,
-			OperationType:  internal.operationType,
-			QueryPlan:      external.QueryPlan,
-		}
+		singleFetch.Info.DataSourceID = internal.sourceID
+		singleFetch.Info.DataSourceName = internal.sourceName
+		singleFetch.Info.RootFields = internal.rootFields
+		singleFetch.Info.OperationType = internal.operationType
+		singleFetch.Info.QueryPlan = external.QueryPlan
 	}
 
 	if !v.Config.DisableIncludeFieldDependencies {
-		singleFetch.CoordinateDependencies = v.resolveFetchDependencies(internal.fetchID)
-		singleFetch.FieldFetchReasons = v.buildFetchReasons(internal.fetchID)
+		singleFetch.Info.CoordinateDependencies = v.resolveFetchDependencies(internal.fetchID)
+	}
+
+	if v.buildFetchReasons {
+		singleFetch.Info.FetchReasons, singleFetch.Info.PropagatedFetchReasons = v.buildFetchReasonsInfo(internal.fetchID)
 	}
 
 	return singleFetch
 }
 
+func (v *Visitor) shouldTrackFetchMetadata() bool {
+	return !v.Config.DisableIncludeFieldDependencies || v.buildFetchReasons
+}
+
 func (v *Visitor) resolveFetchDependencies(fetchID int) []resolve.FetchDependency {
 	fields, ok := v.plannerFields[fetchID]
 	if !ok {
@@ -1398,10 +1408,10 @@ func (v *Visitor) resolveFetchDependencies(fetchID int) []resolve.FetchDependenc
 	return dependencies
 }
 
-func (v *Visitor) buildFetchReasons(fetchID int) []resolve.FetchReason {
+func (v *Visitor) buildFetchReasonsInfo(fetchID int) ([]resolve.FetchReason, []resolve.FetchReason) {
 	fields, ok := v.plannerFields[fetchID]
 	if !ok {
-		return nil
+		return nil, nil
 	}
 	dsConfig := v.planners[fetchID].DataSourceConfiguration()
 
@@ -1418,9 +1428,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]
@@ -1495,5 +1502,13 @@ func (v *Visitor) buildFetchReasons(fetchID int) []resolve.FetchReason {
 			cmp.Compare(a.FieldName, b.FieldName),
 		)
 	})
-	return reasons
+
+	propagated := make([]resolve.FetchReason, 0, len(reasons))
+	for i := range reasons {
+		if dsConfig.RequiresFetchReason(reasons[i].TypeName, reasons[i].FieldName) {
+			propagated = append(propagated, reasons[i])
+		}
+	}
+
+	return reasons, propagated
 }
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/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..f5d0b2a 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/postprocess/create_concrete_single_fetch_types.go
+++ b/app/v2/pkg/engine/postprocess/create_concrete_single_fetch_types.go
@@ -75,10 +75,8 @@ func (d *createConcreteSingleFetchTypes) createEntityBatchFetch(fetch *resolve.S
 	}
 
 	return &resolve.BatchEntityFetch{
-		FetchDependencies:      fetch.FetchDependencies,
-		CoordinateDependencies: fetch.CoordinateDependencies,
-		FieldFetchReasons:      fetch.FieldFetchReasons,
-		Info:                   fetch.Info,
+		FetchDependencies: fetch.FetchDependencies,
+		Info:              fetch.Info,
 		Input: resolve.BatchInput{
 			Header: resolve.InputTemplate{
 				Segments:                              fetch.InputTemplate.Segments[:representationsVariableIndex],
@@ -122,10 +120,8 @@ func (d *createConcreteSingleFetchTypes) createEntityFetch(fetch *resolve.Single
 	}
 
 	return &resolve.EntityFetch{
-		FetchDependencies:      fetch.FetchDependencies,
-		CoordinateDependencies: fetch.CoordinateDependencies,
-		FieldFetchReasons:      fetch.FieldFetchReasons,
-		Info:                   fetch.Info,
+		FetchDependencies: fetch.FetchDependencies,
+		Info:              fetch.Info,
 		Input: resolve.EntityInput{
 			Header: resolve.InputTemplate{
 				Segments:                              fetch.InputTemplate.Segments[:representationsVariableIndex],
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go b/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go
index 9a0121b..d3da371 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go
+++ b/app/v2/pkg/engine/postprocess/deduplicate_single_fetches_test.go
@@ -99,6 +99,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 							},
 							FetchConfiguration: resolve.FetchConfiguration{
 								Input: "a",
+							},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -123,6 +125,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 							},
 							FetchConfiguration: resolve.FetchConfiguration{
 								Input: "a",
+							},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -147,6 +151,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 							},
 							FetchConfiguration: resolve.FetchConfiguration{
 								Input: "b",
+							},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -174,6 +180,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 							},
 							FetchConfiguration: resolve.FetchConfiguration{
 								Input: "b",
+							},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -219,6 +227,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 							},
 							FetchConfiguration: resolve.FetchConfiguration{
 								Input: "a",
+							},
+							Info: &resolve.FetchInfo{
 								CoordinateDependencies: []resolve.FetchDependency{
 									{
 										DependsOn: []resolve.FetchDependencyOrigin{
@@ -243,6 +253,8 @@ func TestDeduplicateSingleFetches_ProcessFetchTree(t *testing.T) {
 							},
 							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-4/app/v2/pkg/engine/resolve/fetch.go b/app/v2/pkg/engine/resolve/fetch.go
index 137670b..87ade48 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/resolve/fetch.go
+++ b/app/v2/pkg/engine/resolve/fetch.go
@@ -20,6 +20,7 @@ const (
 type Fetch interface {
 	FetchKind() FetchKind
 	Dependencies() *FetchDependencies
+	FetchInfo() *FetchInfo
 	DataSourceInfo() DataSourceInfo
 	DependenciesCoordinates() []FetchDependency
 	FetchReasons() []FetchReason
@@ -101,15 +102,28 @@ func (s *SingleFetch) Dependencies() *FetchDependencies {
 	return &s.FetchDependencies
 }
 
+func (s *SingleFetch) FetchInfo() *FetchInfo {
+	return s.Info
+}
+
 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 {
+	if s.Info == nil {
+		return DataSourceInfo{}
+	}
 	return DataSourceInfo{
 		ID:   s.Info.DataSourceID,
 		Name: s.Info.DataSourceName,
@@ -170,29 +184,40 @@ func (*SingleFetch) FetchKind() FetchKind {
 type BatchEntityFetch struct {
 	FetchDependencies
 
-	Input                  BatchInput
-	DataSource             DataSource
-	PostProcessing         PostProcessingConfiguration
-	DataSourceIdentifier   []byte
-	Trace                  *DataSourceLoadTrace
-	Info                   *FetchInfo
-	CoordinateDependencies []FetchDependency
-	FieldFetchReasons      []FetchReason
+	Input                BatchInput
+	DataSource           DataSource
+	PostProcessing       PostProcessingConfiguration
+	DataSourceIdentifier []byte
+	Trace                *DataSourceLoadTrace
+	Info                 *FetchInfo
 }
 
 func (b *BatchEntityFetch) Dependencies() *FetchDependencies {
 	return &b.FetchDependencies
 }
 
+func (b *BatchEntityFetch) FetchInfo() *FetchInfo {
+	return b.Info
+}
+
 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 {
+	if b.Info == nil {
+		return DataSourceInfo{}
+	}
 	return DataSourceInfo{
 		ID:   b.Info.DataSourceID,
 		Name: b.Info.DataSourceName,
@@ -223,29 +248,40 @@ func (*BatchEntityFetch) FetchKind() FetchKind {
 type EntityFetch struct {
 	FetchDependencies
 
-	Input                  EntityInput
-	DataSource             DataSource
-	PostProcessing         PostProcessingConfiguration
-	DataSourceIdentifier   []byte
-	Trace                  *DataSourceLoadTrace
-	Info                   *FetchInfo
-	CoordinateDependencies []FetchDependency
-	FieldFetchReasons      []FetchReason
+	Input                EntityInput
+	DataSource           DataSource
+	PostProcessing       PostProcessingConfiguration
+	DataSourceIdentifier []byte
+	Trace                *DataSourceLoadTrace
+	Info                 *FetchInfo
 }
 
 func (e *EntityFetch) Dependencies() *FetchDependencies {
 	return &e.FetchDependencies
 }
 
+func (e *EntityFetch) FetchInfo() *FetchInfo {
+	return e.Info
+}
+
 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 {
+	if e.Info == nil {
+		return DataSourceInfo{}
+	}
 	return DataSourceInfo{
 		ID:   e.Info.DataSourceID,
 		Name: e.Info.DataSourceName,
@@ -276,12 +312,25 @@ func (p *ParallelListItemFetch) Dependencies() *FetchDependencies {
 	return &p.Fetch.FetchDependencies
 }
 
+func (p *ParallelListItemFetch) FetchInfo() *FetchInfo {
+	if p.Fetch == nil {
+		return nil
+	}
+	return p.Fetch.Info
+}
+
 func (p *ParallelListItemFetch) DependenciesCoordinates() []FetchDependency {
-	return p.Fetch.CoordinateDependencies
+	if p.Fetch == nil || p.Fetch.Info == nil {
+		return nil
+	}
+	return p.Fetch.Info.CoordinateDependencies
 }
 
 func (p *ParallelListItemFetch) FetchReasons() []FetchReason {
-	return p.Fetch.FieldFetchReasons
+	if p.Fetch == nil || p.Fetch.Info == nil {
+		return nil
+	}
+	return p.Fetch.Info.PropagatedFetchReasons
 }
 
 func (*ParallelListItemFetch) FetchKind() FetchKind {
@@ -341,17 +390,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 +405,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
 	}
@@ -430,11 +463,14 @@ type FetchReason struct {
 }
 
 type FetchInfo struct {
-	DataSourceID   string
-	DataSourceName string
-	RootFields     []GraphCoordinate
-	OperationType  ast.OperationType
-	QueryPlan      *QueryPlan
+	DataSourceID           string
+	DataSourceName         string
+	RootFields             []GraphCoordinate
+	OperationType          ast.OperationType
+	QueryPlan              *QueryPlan
+	CoordinateDependencies []FetchDependency
+	FetchReasons           []FetchReason
+	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-4/app/v2/pkg/engine/resolve/fetchtree.go b/app/v2/pkg/engine/resolve/fetchtree.go
index ad1eb2f..f4fd987 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/resolve/fetchtree.go
+++ b/app/v2/pkg/engine/resolve/fetchtree.go
@@ -216,7 +216,7 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				SubgraphName:      f.Info.DataSourceName,
 				SubgraphID:        f.Info.DataSourceID,
 				Path:              n.Item.ResponsePath,
-				Dependencies:      f.FetchConfiguration.CoordinateDependencies,
+				Dependencies:      f.Info.CoordinateDependencies,
 			}
 
 			if f.Info.QueryPlan != nil {
@@ -231,7 +231,7 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				SubgraphName:      f.Info.DataSourceName,
 				SubgraphID:        f.Info.DataSourceID,
 				Path:              n.Item.ResponsePath,
-				Dependencies:      f.CoordinateDependencies,
+				Dependencies:      f.Info.CoordinateDependencies,
 			}
 
 			if f.Info.QueryPlan != nil {
@@ -246,7 +246,7 @@ func (n *FetchTreeNode) queryPlan() *FetchTreeQueryPlanNode {
 				SubgraphName:      f.Info.DataSourceName,
 				SubgraphID:        f.Info.DataSourceID,
 				Path:              n.Item.ResponsePath,
-				Dependencies:      f.CoordinateDependencies,
+				Dependencies:      f.Info.CoordinateDependencies,
 			}
 
 			if f.Info.QueryPlan != nil {
diff --git a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/resolve/loader.go b/app/v2/pkg/engine/resolve/loader.go
index 685383c..9a3690d 100644
--- a/tmp/agent-patch-flux-pr-1293.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/resolve/loader.go
+++ b/app/v2/pkg/engine/resolve/loader.go
@@ -1599,7 +1599,10 @@ func (l *Loader) executeSourceLoad(ctx context.Context, fetchItem *FetchItem, so
 		}
 	}
 	if l.propagateFetchReasons && !IsIntrospectionDataSource(res.ds.ID) {
-		fetchReasons := fetchItem.Fetch.FetchReasons()
+		var fetchReasons []FetchReason
+		if info := fetchItem.Fetch.FetchInfo(); info != nil {
+			fetchReasons = info.PropagatedFetchReasons
+		}
 		if len(fetchReasons) > 0 {
 			var encoded []byte
 			encoded, res.err = json.Marshal(fetchReasons)