STET

agent_patch

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

25921 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
index 316e2fc..f347100 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
+++ b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
@@ -269,14 +269,6 @@ func (p *Planner[T]) DownstreamResponseFieldAlias(downstreamFieldRef int) (alias
 	return "", false
 }
 
-func (p *Planner[T]) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior {
-	return plan.DataSourcePlanningBehavior{
-		MergeAliasedRootNodes:      true,
-		OverrideFieldPathFromAlias: true,
-		IncludeTypeNameFields:      true,
-	}
-}
-
 func (p *Planner[T]) Register(visitor *plan.Visitor, configuration plan.DataSourceConfiguration[T], dataSourcePlannerConfiguration plan.DataSourcePlannerConfiguration) error {
 
 	p.visitor = visitor
@@ -1825,6 +1817,15 @@ func (f *Factory[T]) UpstreamSchema(dataSourceConfig plan.DataSourceConfiguratio
 	return schema, true
 }
 
+func (f *Factory[T]) PlanningBehavior() plan.DataSourcePlanningBehavior {
+	return plan.DataSourcePlanningBehavior{
+		MergeAliasedRootNodes:      true,
+		OverrideFieldPathFromAlias: true,
+		AllowPlanningTypeName:      true,
+		AlwaysFlattenFragments:     f.grpcClient != nil || f.grpcClientProvider != nil,
+	}
+}
+
 type Source struct {
 	httpClient *http.Client
 }
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/introspection_datasource/factory.go b/app/v2/pkg/engine/datasource/introspection_datasource/factory.go
index a251521..5f97576 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/introspection_datasource/factory.go
+++ b/app/v2/pkg/engine/datasource/introspection_datasource/factory.go
@@ -29,3 +29,11 @@ func (f *Factory[T]) Context() context.Context {
 func (f *Factory[T]) UpstreamSchema(dataSourceConfig plan.DataSourceConfiguration[T]) (*ast.Document, bool) {
 	return nil, false
 }
+
+func (f *Factory[T]) PlanningBehavior() plan.DataSourcePlanningBehavior {
+	return plan.DataSourcePlanningBehavior{
+		MergeAliasedRootNodes:      false,
+		OverrideFieldPathFromAlias: true,
+		AllowPlanningTypeName:      true,
+	}
+}
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/introspection_datasource/planner.go b/app/v2/pkg/engine/datasource/introspection_datasource/planner.go
index 2b05800..481dc3c 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/introspection_datasource/planner.go
+++ b/app/v2/pkg/engine/datasource/introspection_datasource/planner.go
@@ -45,14 +45,6 @@ func (p *Planner[T]) DownstreamResponseFieldAlias(_ int) (alias string, exists b
 	return
 }
 
-func (p *Planner[T]) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior {
-	return plan.DataSourcePlanningBehavior{
-		MergeAliasedRootNodes:      false,
-		OverrideFieldPathFromAlias: true,
-		IncludeTypeNameFields:      true,
-	}
-}
-
 func (p *Planner[T]) EnterField(ref int) {
 	fieldName := p.v.Operation.FieldNameString(ref)
 	fieldAliasOrName := p.v.Operation.FieldAliasOrNameString(ref)
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go b/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go
index 60faa27..9e14ba1 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go
+++ b/app/v2/pkg/engine/datasource/pubsub_datasource/pubsub_datasource.go
@@ -275,14 +275,6 @@ func (p *Planner[T]) ConfigureSubscription() plan.SubscriptionConfiguration {
 	return plan.SubscriptionConfiguration{}
 }
 
-func (p *Planner[T]) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior {
-	return plan.DataSourcePlanningBehavior{
-		MergeAliasedRootNodes:      false,
-		OverrideFieldPathFromAlias: false,
-		IncludeTypeNameFields:      true,
-	}
-}
-
 func (p *Planner[T]) DownstreamResponseFieldAlias(_ int) (alias string, exists bool) {
 	return "", false
 }
@@ -316,6 +308,14 @@ func (f *Factory[T]) UpstreamSchema(dataSourceConfig plan.DataSourceConfiguratio
 	return nil, false
 }
 
+func (f *Factory[T]) PlanningBehavior() plan.DataSourcePlanningBehavior {
+	return plan.DataSourcePlanningBehavior{
+		MergeAliasedRootNodes:      false,
+		OverrideFieldPathFromAlias: false,
+		AllowPlanningTypeName:      true,
+	}
+}
+
 func buildEventDataBytes(ref int, visitor *plan.Visitor, variables *resolve.Variables) ([]byte, error) {
 	// Collect the field arguments for fetch based operations
 	fieldArgs := visitor.Operation.FieldArguments(ref)
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/staticdatasource/static_datasource.go b/app/v2/pkg/engine/datasource/staticdatasource/static_datasource.go
index 3449afb..c05efc7 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/datasource/staticdatasource/static_datasource.go
+++ b/app/v2/pkg/engine/datasource/staticdatasource/static_datasource.go
@@ -18,7 +18,7 @@ type Configuration struct {
 
 type Factory[T Configuration] struct{}
 
-func (f *Factory[T]) Planner(logger abstractlogger.Logger) plan.DataSourcePlanner[T] {
+func (f *Factory[T]) Planner(_ abstractlogger.Logger) plan.DataSourcePlanner[T] {
 	return &Planner[T]{}
 }
 
@@ -26,10 +26,14 @@ func (f *Factory[T]) Context() context.Context {
 	return context.TODO()
 }
 
-func (f *Factory[T]) UpstreamSchema(dataSourceConfig plan.DataSourceConfiguration[T]) (*ast.Document, bool) {
+func (f *Factory[T]) UpstreamSchema(_ plan.DataSourceConfiguration[T]) (*ast.Document, bool) {
 	return nil, false
 }
 
+func (f *Factory[T]) PlanningBehavior() plan.DataSourcePlanningBehavior {
+	return plan.DataSourcePlanningBehavior{}
+}
+
 type Planner[T Configuration] struct {
 	id     int
 	config Configuration
@@ -48,13 +52,6 @@ func (p *Planner[T]) DownstreamResponseFieldAlias(downstreamFieldRef int) (alias
 	return
 }
 
-func (p *Planner[T]) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior {
-	return plan.DataSourcePlanningBehavior{
-		MergeAliasedRootNodes:      false,
-		OverrideFieldPathFromAlias: false,
-	}
-}
-
 func (p *Planner[T]) Register(_ *plan.Visitor, configuration plan.DataSourceConfiguration[T], _ plan.DataSourcePlannerConfiguration) error {
 	p.config = Configuration(configuration.CustomConfiguration())
 	return nil
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/abstract_selection_rewriter.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
index 284ad42..2bfffcf 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
@@ -13,9 +13,10 @@ import (
 )
 
 var (
-	FieldDoesntHaveSelectionSetErr          = errors.New("unexpected error: field does not have a selection set")
-	InlineFragmentDoesntHaveSelectionSetErr = errors.New("unexpected error: inline fragment does not have a selection set")
-	InlineFragmentTypeIsNotExistsErr        = errors.New("unexpected error: inline fragment type condition does not exists")
+	ErrFieldHasNoSelectionSet          = errors.New("unexpected error: field does not have a selection set")
+	ErrInlineFragmentHasNoSelectionSet = errors.New("unexpected error: inline fragment does not have a selection set")
+	ErrInlineFragmentHasNoCondition    = errors.New("unexpected error: inline fragment type condition does not exists")
+	ErrNoUpstreamSchema                = errors.New("unexpected error: upstream schema is not defined in DataSource")
 )
 
 /*
@@ -65,6 +66,7 @@ type fieldSelectionRewriter struct {
 	dsConfiguration    DataSource
 
 	skipFieldRefs []int
+	alwaysRewrite bool
 }
 
 type RewriteResult struct {
@@ -74,19 +76,19 @@ type RewriteResult struct {
 
 var resultNotRewritten = RewriteResult{}
 
-func newFieldSelectionRewriter(operation *ast.Document, definition *ast.Document) *fieldSelectionRewriter {
-	return &fieldSelectionRewriter{
-		operation:  operation,
-		definition: definition,
+func newFieldSelectionRewriter(operation *ast.Document, definition *ast.Document, dsConfiguration DataSource) (*fieldSelectionRewriter, error) {
+	upstreamDefinition, ok := dsConfiguration.UpstreamSchema()
+	if !ok {
+		return nil, ErrNoUpstreamSchema
 	}
-}
-
-func (r *fieldSelectionRewriter) SetUpstreamDefinition(upstreamDefinition *ast.Document) {
-	r.upstreamDefinition = upstreamDefinition
-}
 
-func (r *fieldSelectionRewriter) SetDatasourceConfiguration(dsConfiguration DataSource) {
-	r.dsConfiguration = dsConfiguration
+	return &fieldSelectionRewriter{
+		operation:          operation,
+		definition:         definition,
+		upstreamDefinition: upstreamDefinition,
+		dsConfiguration:    dsConfiguration,
+		alwaysRewrite:      dsConfiguration.PlanningBehavior().AlwaysFlattenFragments,
+	}, nil
 }
 
 func (r *fieldSelectionRewriter) RewriteFieldSelection(fieldRef int, enclosingNode ast.Node) (res RewriteResult, err error) {
@@ -168,7 +170,18 @@ func (r *fieldSelectionRewriter) processUnionSelection(fieldRef int, unionDefRef
 	}, nil
 }
 
+func (r *fieldSelectionRewriter) mustRewrite(selectionSetInfo selectionSetInfo) bool {
+	return r.alwaysRewrite &&
+		(selectionSetInfo.hasInlineFragmentsOnInterfaces ||
+			selectionSetInfo.hasInlineFragmentsOnUnions ||
+			selectionSetInfo.hasInlineFragmentsOnObjects)
+}
+
 func (r *fieldSelectionRewriter) unionFieldSelectionNeedsRewrite(selectionSetInfo selectionSetInfo, unionTypeNames, entityNames []string) (needRewrite bool) {
+	if r.mustRewrite(selectionSetInfo) {
+		return true
+	}
+
 	if selectionSetInfo.hasInlineFragmentsOnObjects {
 		// when we have types not exists in the current datasource - we need to rewrite
 		if r.objectFragmentsRequiresCleanup(selectionSetInfo.inlineFragmentsOnObjects, unionTypeNames) {
@@ -263,7 +276,7 @@ func (r *fieldSelectionRewriter) replaceFieldSelections(fieldRef int, newSelecti
 func (r *fieldSelectionRewriter) processObjectSelection(fieldRef int, objectDefRef int) (res RewriteResult, err error) {
 	selectionSetRef, ok := r.operation.FieldSelectionSet(fieldRef)
 	if !ok {
-		return resultNotRewritten, FieldDoesntHaveSelectionSetErr
+		return resultNotRewritten, ErrFieldHasNoSelectionSet
 	}
 
 	fieldTypeName := r.definition.ObjectTypeDefinitionNameBytes(objectDefRef)
@@ -346,6 +359,10 @@ func (r *fieldSelectionRewriter) rewriteObjectSelection(fieldRef int, fieldInfo
 }
 
 func (r *fieldSelectionRewriter) objectFieldSelectionNeedsRewrite(selectionSetInfo selectionSetInfo, objectTypeName string) (needRewrite bool) {
+	if r.mustRewrite(selectionSetInfo) {
+		return true
+	}
+
 	if selectionSetInfo.hasInlineFragmentsOnObjects {
 		if r.objectFragmentsRequiresCleanup(selectionSetInfo.inlineFragmentsOnObjects, []string{objectTypeName}) {
 			return true
@@ -412,6 +429,10 @@ func (r *fieldSelectionRewriter) processInterfaceSelection(fieldRef int, interfa
 }
 
 func (r *fieldSelectionRewriter) interfaceFieldSelectionNeedsRewrite(selectionSetInfo selectionSetInfo, interfaceTypeNames []string, entityNames []string) (needRewrite bool) {
+	if r.mustRewrite(selectionSetInfo) {
+		return true
+	}
+
 	// when we do not have fragments
 	if !selectionSetInfo.hasInlineFragmentsOnInterfaces &&
 		!selectionSetInfo.hasInlineFragmentsOnUnions &&
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
index 950ccb0..61a76ab 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
@@ -83,7 +83,7 @@ func (r *fieldSelectionRewriter) selectionSetFieldSelections(selectionSetRef int
 func (r *fieldSelectionRewriter) collectFieldInformation(fieldRef int) (selectionSetInfo, error) {
 	fieldSelectionSetRef, ok := r.operation.FieldSelectionSet(fieldRef)
 	if !ok {
-		return selectionSetInfo{}, FieldDoesntHaveSelectionSetErr
+		return selectionSetInfo{}, ErrFieldHasNoSelectionSet
 	}
 
 	return r.collectSelectionSetInformation(fieldSelectionSetRef)
@@ -101,7 +101,7 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 	typeCondition := r.operation.InlineFragmentTypeConditionNameString(inlineFragmentRef)
 	inlineFragmentSelectionSetRef, ok := r.operation.InlineFragmentSelectionSet(inlineFragmentRef)
 	if !ok {
-		return InlineFragmentDoesntHaveSelectionSetErr
+		return ErrInlineFragmentHasNoSelectionSet
 	}
 
 	hasDirectives := r.operation.InlineFragmentHasDirectives(inlineFragmentRef)
@@ -110,7 +110,7 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 	// because it could be absent in the current SUBGRAPH document
 	definitionNode, hasNode := r.definition.NodeByNameStr(typeCondition)
 	if !hasNode {
-		return InlineFragmentTypeIsNotExistsErr
+		return ErrInlineFragmentHasNoCondition
 	}
 
 	selectionSetInfo, err := r.collectSelectionSetInformation(inlineFragmentSelectionSetRef)
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go
index 11b5fc8..df18217 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go
@@ -46,12 +46,27 @@ func TestInterfaceSelectionRewriter_RewriteOperation(t *testing.T) {
 				break
 			}
 		}
+		require.NotEqual(t, ast.InvalidRef, fieldRef)
+
+		if cfg, ok := testCase.dsConfiguration.(*dataSourceConfiguration[any]); ok {
+			behavior := cfg.PlanningBehavior()
+			if cfg.factory == nil {
+				cfg.factory = &FakeFactory[any]{
+					upstreamSchema: &upstreamDef,
+					behavior:       &behavior,
+				}
+			} else if _, hasSchema := cfg.UpstreamSchema(); !hasSchema {
+				cfg.factory = &FakeFactory[any]{
+					upstreamSchema: &upstreamDef,
+					behavior:       &behavior,
+				}
+			}
+		}
 
 		node, _ := def.Index.FirstNodeByNameStr(testCase.enclosingTypeName)
 
-		rewriter := newFieldSelectionRewriter(&op, &def)
-		rewriter.SetUpstreamDefinition(&upstreamDef)
-		rewriter.SetDatasourceConfiguration(testCase.dsConfiguration)
+		rewriter, err := newFieldSelectionRewriter(&op, &def, testCase.dsConfiguration)
+		require.NoError(t, err)
 
 		result, err := rewriter.RewriteFieldSelection(fieldRef, node)
 		require.NoError(t, err)
@@ -179,7 +194,113 @@ func TestInterfaceSelectionRewriter_RewriteOperation(t *testing.T) {
 		}).
 		DS()
 
+	definitionB := `
+		type Query {
+			named: Named
+			union: U
+		}
+
+		union U = User
+
+		interface Named {
+			name: String
+		}
+
+		interface Numbered {
+			number: Int
+		}
+
+		type User implements Named & Numbered {
+			id: ID
+			name: String
+			number: Int
+		}`
+
 	testCases := []testCase{
+		{
+			name:               "should flatten interfaces for gRPC",
+			fieldName:          "named",
+			definition:         definitionB,
+			upstreamDefinition: definitionB,
+			dsConfiguration: dsb().
+				WithBehavior(DataSourcePlanningBehavior{AlwaysFlattenFragments: true}).
+				RootNode("Query", "named", "union").
+				RootNode("User", "id", "name", "number").
+				ChildNode("Named", "name").
+				ChildNode("Numbered", "number").
+				KeysMetadata(FederationFieldConfigurations{
+					{
+						TypeName:     "User",
+						SelectionSet: "id",
+					},
+				}).
+				DS(),
+			operation: `
+				query {
+					named {
+						... on Numbered {
+							... on User {
+								name
+							}
+						}
+						... on User {
+							id
+						}
+					}
+				}`,
+			expectedOperation: `
+				query {
+					named {
+						... on User {
+							id
+							name
+						}
+					}
+				}`,
+			shouldRewrite: true,
+		},
+		{
+			name:               "should flatten union for gRPC",
+			fieldName:          "union",
+			definition:         definitionB,
+			upstreamDefinition: definitionB,
+			dsConfiguration: dsb().
+				WithBehavior(DataSourcePlanningBehavior{AlwaysFlattenFragments: true}).
+				RootNode("Query", "named", "union").
+				RootNode("User", "id", "name", "number").
+				ChildNode("Named", "name").
+				ChildNode("Numbered", "number").
+				KeysMetadata(FederationFieldConfigurations{
+					{
+						TypeName:     "User",
+						SelectionSet: "id",
+					},
+				}).
+				DS(),
+			operation: `
+				query {
+					union {
+						... on Numbered {
+							... on User {
+								name
+							}
+						}
+						... on User {
+							id
+						}
+					}
+				}`,
+			expectedOperation: `
+				query {
+					union {
+						... on User {
+							id
+							name
+						}
+					}
+				}`,
+			shouldRewrite: true,
+		},
 		{
 			name:       "one field is external. query without fragments",
 			definition: definition,
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_configuration.go b/app/v2/pkg/engine/plan/datasource_configuration.go
index 07ec63e..62b0b00 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_configuration.go
+++ b/app/v2/pkg/engine/plan/datasource_configuration.go
@@ -25,6 +25,7 @@ type PlannerFactory[DataSourceSpecificConfiguration any] interface {
 	// This method serves as a flag that factory should have a context
 	Context() context.Context
 	UpstreamSchema(dataSourceConfig DataSourceConfiguration[DataSourceSpecificConfiguration]) (*ast.Document, bool)
+	PlanningBehavior() DataSourcePlanningBehavior
 }
 
 type DataSourceMetadata struct {
@@ -245,15 +246,12 @@ type DataSourceConfiguration[T any] interface {
 	CustomConfiguration() T
 }
 
-type DataSourceUpstreamSchema interface {
-	UpstreamSchema() (*ast.Document, bool)
-}
-
 type DataSource interface {
 	FederationInfo
 	NodesInfo
 	DirectivesConfigurations
-	DataSourceUpstreamSchema
+	UpstreamSchema() (*ast.Document, bool)
+	PlanningBehavior() DataSourcePlanningBehavior
 	Id() string
 	Name() string
 	Hash() DSHash
@@ -287,6 +285,10 @@ func (d *dataSourceConfiguration[T]) UpstreamSchema() (*ast.Document, bool) {
 	return d.factory.UpstreamSchema(d)
 }
 
+func (d *dataSourceConfiguration[T]) PlanningBehavior() DataSourcePlanningBehavior {
+	return d.factory.PlanningBehavior()
+}
+
 func (d *dataSourceConfiguration[T]) Id() string {
 	return d.id
 }
@@ -383,8 +385,10 @@ type DataSourcePlanningBehavior struct {
 	// When true expected response will be { "rootField": ..., "alias": ... }
 	// When false expected response will be { "rootField": ..., "original": ... }
 	OverrideFieldPathFromAlias bool
-	// IncludeTypeNameFields should be set to true if the planner allows to plan __typename fields
-	IncludeTypeNameFields bool
+	// AllowPlanningTypeName set to true will allow the planner to plan __typename fields.
+	AllowPlanningTypeName bool
+	// AlwaysFlattenFragments rewrites inline fragments to concrete types unconditionally.
+	AlwaysFlattenFragments bool
 }
 
 type DataSourceFetchPlanner interface {
@@ -393,7 +397,6 @@ type DataSourceFetchPlanner interface {
 }
 
 type DataSourceBehavior interface {
-	DataSourcePlanningBehavior() DataSourcePlanningBehavior
 	// DownstreamResponseFieldAlias allows the DataSourcePlanner to overwrite the response path with an alias
 	// It's required to set OverrideFieldPathFromAlias to true
 	// This function is useful in the following scenario
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go b/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go
index acf02a9..9a3584c 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go
+++ b/app/v2/pkg/engine/plan/datasource_filter_visitor_test.go
@@ -64,6 +64,16 @@ func (b *dsBuilder) Schema(schema string) *dsBuilder {
 	return b
 }
 
+func (b *dsBuilder) SchemaMergedWithBase(schema string) *dsBuilder {
+	def := unsafeparser.ParseGraphqlDocumentStringWithBaseSchema(schema)
+	b.ds.factory = &FakeFactory[any]{
+		upstreamSchema: &def,
+		behavior:       b.behavior,
+	}
+
+	return b
+}
+
 func (b *dsBuilder) KeysMetadata(keys FederationFieldConfigurations) *dsBuilder {
 	b.ds.FederationMetaData.Keys = keys
 	return b
@@ -85,6 +95,11 @@ func (b *dsBuilder) Id(id string) *dsBuilder {
 }
 
 func (b *dsBuilder) DS() DataSource {
+	if b.ds.factory == nil {
+		b.ds.factory = &FakeFactory[any]{
+			behavior: b.behavior,
+		}
+	}
 	if err := b.ds.DataSourceMetadata.Init(); err != nil {
 		panic(err)
 	}
diff --git a/tmp/agent-patch-flux-pr-1268.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 95c4f01..fa2d045 100644
--- a/tmp/agent-patch-flux-pr-1268.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
@@ -644,14 +644,15 @@ func (c *nodeSelectionVisitor) rewriteSelectionSetHavingAbstractFragments(fieldR
 	}
 	c.visitedFieldsAbstractChecks[fieldRef] = struct{}{}
 
-	upstreamSchema, ok := ds.UpstreamSchema()
-	if !ok {
+	if _, ok := ds.UpstreamSchema(); !ok {
 		return
 	}
 
-	rewriter := newFieldSelectionRewriter(c.operation, c.definition)
-	rewriter.SetUpstreamDefinition(upstreamSchema)
-	rewriter.SetDatasourceConfiguration(ds)
+	rewriter, err := newFieldSelectionRewriter(c.operation, c.definition, ds)
+	if err != nil {
+		c.walker.StopWithInternalErr(err)
+		return
+	}
 
 	result, err := rewriter.RewriteFieldSelection(fieldRef, c.walker.EnclosingTypeDefinition)
 	if err != nil {
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/path_builder_visitor.go b/app/v2/pkg/engine/plan/path_builder_visitor.go
index bd4d6b2..a551826 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/path_builder_visitor.go
+++ b/app/v2/pkg/engine/plan/path_builder_visitor.go
@@ -719,8 +719,8 @@ func (c *pathBuilderVisitor) isAllFieldDependenciesOnSameDataSource(fieldRef int
 
 func (c *pathBuilderVisitor) planWithExistingPlanners(fieldRef int, typeName, fieldName, currentPath, parentPath, precedingParentPath string, suggestion *NodeSuggestion) (plannerIdx int, planned bool) {
 	for plannerIdx, plannerConfig := range c.planners {
-		planningBehaviour := plannerConfig.DataSourcePlanningBehavior()
 		dsConfiguration := plannerConfig.DataSourceConfiguration()
+		planningBehaviour := dsConfiguration.PlanningBehavior()
 		currentPlannerDSHash := dsConfiguration.Hash()
 
 		hasSuggestion := suggestion != nil
@@ -1247,7 +1247,7 @@ func (c *pathBuilderVisitor) addPlannerPathForTypename(
 	if fieldName != typeNameField {
 		return false
 	}
-	if !planningBehaviour.IncludeTypeNameFields {
+	if !planningBehaviour.AllowPlanningTypeName {
 		return false
 	}
 
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/planner_configuration.go b/app/v2/pkg/engine/plan/planner_configuration.go
index 69e23e8..7bc5614 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/planner_configuration.go
+++ b/app/v2/pkg/engine/plan/planner_configuration.go
@@ -62,10 +62,6 @@ func (p *plannerConfiguration[T]) ObjectFetchConfiguration() *objectFetchConfigu
 	return p.objectFetchConfiguration
 }
 
-func (p *plannerConfiguration[T]) DataSourcePlanningBehavior() DataSourcePlanningBehavior {
-	return p.planner.DataSourcePlanningBehavior()
-}
-
 func (p *plannerConfiguration[T]) DownstreamResponseFieldAlias(downstreamFieldRef int) (alias string, exists bool) {
 	return p.planner.DownstreamResponseFieldAlias(downstreamFieldRef)
 }
diff --git a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/planner_test.go b/app/v2/pkg/engine/plan/planner_test.go
index 0a498ad..c377dae 100644
--- a/tmp/agent-patch-flux-pr-1268.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/engine/plan/planner_test.go
+++ b/app/v2/pkg/engine/plan/planner_test.go
@@ -997,7 +997,14 @@ type FakeFactory[T any] struct {
 }
 
 func (f *FakeFactory[T]) UpstreamSchema(dataSourceConfig DataSourceConfiguration[T]) (*ast.Document, bool) {
-	return f.upstreamSchema, true
+	return f.upstreamSchema, f.upstreamSchema != nil
+}
+
+func (f *FakeFactory[T]) PlanningBehavior() DataSourcePlanningBehavior {
+	if f.behavior == nil {
+		return DataSourcePlanningBehavior{}
+	}
+	return *f.behavior
 }
 
 func (f *FakeFactory[T]) Planner(logger abstractlogger.Logger) DataSourcePlanner[T] {
diff --git a/tmp/agent-patch-flux-pr-1268.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 848c5cc..a49955f 100644
--- a/tmp/agent-patch-flux-pr-1268.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
@@ -1021,7 +1021,7 @@ func (v *Visitor) resolveFieldPath(ref int) []string {
 
 	aliasOverride := false
 	if plannerConfig != nil && plannerConfig.Planner() != nil {
-		aliasOverride = plannerConfig.DataSourcePlanningBehavior().OverrideFieldPathFromAlias
+		aliasOverride = plannerConfig.DataSourceConfiguration().PlanningBehavior().OverrideFieldPathFromAlias
 	}
 
 	for i := range v.Config.Fields {