STET

agent_patch

runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-1184/flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch

17482 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
index 3484ce9..2a460a1 100644
--- a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
@@ -177,6 +177,10 @@ func (r *fieldSelectionRewriter) unionFieldSelectionNeedsRewrite(selectionSetInf
 		return true
 	}
 
+	if r.unionFragmentsRequiresCleanup(selectionSetInfo.inlineFragmentsOnUnions, unionTypeNames) {
+		return true
+	}
+
 	// when we do not have fragments on objects, but only on interfaces
 	// we need to check that all entities implementing each interface have a root node with the requested fields
 	// e.g. { ... on Interface { a } }
@@ -221,6 +225,10 @@ func (r *fieldSelectionRewriter) rewriteUnionSelection(fieldRef int, fieldInfo s
 		// we need to recursively flatten nested fragments on interfaces
 		r.flattenFragmentOnInterface(inlineFragmentOnInterface.selectionSetInfo, inlineFragmentOnInterface.typeNamesImplementingInterface, unionTypeNames, &newSelectionRefs)
 	}
+	for _, inlineFragmentOnUnion := range fieldInfo.inlineFragmentsOnUnions {
+		// flatten nested fragments on unions into concrete type fragments
+		r.flattenFragmentOnUnion(inlineFragmentOnUnion.selectionSetInfo, inlineFragmentOnUnion.unionMemberTypeNamesInCurrentDS, unionTypeNames, &newSelectionRefs)
+	}
 
 	// filter existing fragments by type names exists in the current datasource
 	// TODO: do not need to iterate 2 times in filter and here
@@ -360,6 +368,12 @@ func (r *fieldSelectionRewriter) interfaceFieldSelectionNeedsRewrite(selectionSe
 		}
 	}
 
+	if selectionSetInfo.hasInlineFragmentsOnUnions {
+		if r.unionFragmentsRequiresCleanup(selectionSetInfo.inlineFragmentsOnUnions, interfaceTypeNames) {
+			return true
+		}
+	}
+
 	if selectionSetInfo.hasInlineFragmentsOnInterfaces && selectionSetInfo.hasInlineFragmentsOnObjects {
 		if len(entitiesWithoutFragment) > 0 {
 			if !r.allEntitiesImplementsInterfaces(selectionSetInfo.inlineFragmentsOnInterfaces, entitiesWithoutFragment) {
@@ -438,7 +452,71 @@ func (r *fieldSelectionRewriter) flattenFragmentOnInterface(selectionSetInfo sel
 		// in case of interfaces the only thing which is matter is an interception of implementing types
 		// and parent allowed types
 
-		r.flattenFragmentOnInterface(inlineFragmentInfo.selectionSetInfo, inlineFragmentInfo.typeNamesImplementingInterface, filteredImplementingTypes, selectionRefs)
+		typeNamesImplementingInterfaceInCurrentDS := inlineFragmentInfo.typeNamesImplementingInterfaceInCurrentDS
+		if len(typeNamesImplementingInterfaceInCurrentDS) == 0 {
+			typeNamesImplementingInterfaceInCurrentDS = inlineFragmentInfo.typeNamesImplementingInterface
+		}
+
+		r.flattenFragmentOnInterface(inlineFragmentInfo.selectionSetInfo, typeNamesImplementingInterfaceInCurrentDS, filteredImplementingTypes, selectionRefs)
+	}
+
+	for _, inlineFragmentInfo := range selectionSetInfo.inlineFragmentsOnUnions {
+		unionMemberTypeNamesInCurrentDS := inlineFragmentInfo.unionMemberTypeNamesInCurrentDS
+		if len(unionMemberTypeNamesInCurrentDS) == 0 {
+			unionMemberTypeNamesInCurrentDS = inlineFragmentInfo.unionMemberTypeNames
+		}
+
+		r.flattenFragmentOnUnion(inlineFragmentInfo.selectionSetInfo, unionMemberTypeNamesInCurrentDS, filteredImplementingTypes, selectionRefs)
+	}
+}
+
+func (r *fieldSelectionRewriter) flattenFragmentOnUnion(selectionSetInfo selectionSetInfo, unionMemberTypeNamesInCurrentDS []string, allowedTypeNames []string, selectionRefs *[]int) {
+	if len(unionMemberTypeNamesInCurrentDS) == 0 {
+		return
+	}
+
+	filteredUnionMemberTypes := make([]string, 0, len(unionMemberTypeNamesInCurrentDS))
+	for _, typeName := range unionMemberTypeNamesInCurrentDS {
+		if slices.Contains(allowedTypeNames, typeName) {
+			filteredUnionMemberTypes = append(filteredUnionMemberTypes, typeName)
+		}
+	}
+
+	if len(filteredUnionMemberTypes) == 0 {
+		return
+	}
+
+	if selectionSetInfo.hasFields {
+		for _, typeName := range filteredUnionMemberTypes {
+			*selectionRefs = append(*selectionRefs, r.createFragmentSelection(typeName, selectionSetInfo.fields))
+		}
+	}
+
+	for _, inlineFragmentInfo := range selectionSetInfo.inlineFragmentsOnObjects {
+		if !slices.Contains(filteredUnionMemberTypes, inlineFragmentInfo.typeName) {
+			continue
+		}
+
+		fragmentSelectionRef := r.operation.CopySelection(inlineFragmentInfo.selectionRef)
+		*selectionRefs = append(*selectionRefs, fragmentSelectionRef)
+	}
+
+	for _, inlineFragmentInfo := range selectionSetInfo.inlineFragmentsOnInterfaces {
+		typeNamesImplementingInterfaceInCurrentDS := inlineFragmentInfo.typeNamesImplementingInterfaceInCurrentDS
+		if len(typeNamesImplementingInterfaceInCurrentDS) == 0 {
+			typeNamesImplementingInterfaceInCurrentDS = inlineFragmentInfo.typeNamesImplementingInterface
+		}
+
+		r.flattenFragmentOnInterface(inlineFragmentInfo.selectionSetInfo, typeNamesImplementingInterfaceInCurrentDS, filteredUnionMemberTypes, selectionRefs)
+	}
+
+	for _, inlineFragmentInfo := range selectionSetInfo.inlineFragmentsOnUnions {
+		nestedUnionMemberTypeNamesInCurrentDS := inlineFragmentInfo.unionMemberTypeNamesInCurrentDS
+		if len(nestedUnionMemberTypeNamesInCurrentDS) == 0 {
+			nestedUnionMemberTypeNamesInCurrentDS = inlineFragmentInfo.unionMemberTypeNames
+		}
+
+		r.flattenFragmentOnUnion(inlineFragmentInfo.selectionSetInfo, nestedUnionMemberTypeNamesInCurrentDS, filteredUnionMemberTypes, selectionRefs)
 	}
 }
 
diff --git a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter_helpers.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter_helpers.go
index 17a53e1..1c191c0 100644
--- a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter_helpers.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter_helpers.go
@@ -39,13 +39,13 @@ func (r *fieldSelectionRewriter) entitiesImplementingInterface(typesImplementing
 		return nil
 	}
 
-	for _, typeName := range typesImplementingInterface {
-		if slices.Contains(entityNames, typeName) {
+	for _, typeName := range entityNames {
+		if slices.Contains(typesImplementingInterface, typeName) {
 			out = append(out, typeName) //nolint:staticcheck
 		}
 	}
 
-	return entityNames
+	return out
 }
 
 func (r *fieldSelectionRewriter) entityNamesWithoutFragments(inlineFragments []inlineFragmentSelection, entityNames []string) []string {
@@ -168,7 +168,21 @@ func (r *fieldSelectionRewriter) interfaceFragmentsRequiresCleanup(inlineFragmen
 	return false
 }
 
-func (r *fieldSelectionRewriter) objectFragmentNeedCleanup(inlineFragment inlineFragmentSelection) bool {
+func (r *fieldSelectionRewriter) unionFragmentsRequiresCleanup(inlineFragments []inlineFragmentSelectionOnUnion, parentSelectionValidTypes []string) bool {
+	for _, fragment := range inlineFragments {
+		if r.unionFragmentNeedCleanup(fragment, parentSelectionValidTypes) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (r *fieldSelectionRewriter) objectFragmentNeedCleanup(inlineFragment inlineFragmentSelection, parentSelectionValidTypes []string) bool {
+	if !slices.Contains(parentSelectionValidTypes, inlineFragment.typeName) {
+		return true
+	}
+
 	if !r.hasTypeOnDataSource(inlineFragment.typeName) {
 		return true
 	}
@@ -179,6 +193,66 @@ func (r *fieldSelectionRewriter) objectFragmentNeedCleanup(inlineFragment inline
 		}
 	}
 
+	for _, fragmentOnUnion := range inlineFragment.selectionSetInfo.inlineFragmentsOnUnions {
+		if r.unionFragmentNeedCleanup(fragmentOnUnion, []string{inlineFragment.typeName}) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (r *fieldSelectionRewriter) unionFragmentNeedCleanup(inlineFragment inlineFragmentSelectionOnUnion, parentSelectionValidTypes []string) bool {
+	if !r.hasTypeOnDataSource(inlineFragment.typeName) {
+		return true
+	}
+
+	unionMemberTypeNamesInCurrentDS := inlineFragment.unionMemberTypeNamesInCurrentDS
+	if len(unionMemberTypeNamesInCurrentDS) == 0 {
+		unionMemberTypeNamesInCurrentDS = inlineFragment.unionMemberTypeNames
+	}
+
+	filteredUnionMemberTypeNames := make([]string, 0, len(unionMemberTypeNamesInCurrentDS))
+	for _, typeName := range unionMemberTypeNamesInCurrentDS {
+		if slices.Contains(parentSelectionValidTypes, typeName) {
+			filteredUnionMemberTypeNames = append(filteredUnionMemberTypeNames, typeName)
+		}
+	}
+
+	if len(filteredUnionMemberTypeNames) == 0 {
+		return true
+	}
+
+	for _, fragmentOnObject := range inlineFragment.selectionSetInfo.inlineFragmentsOnObjects {
+		if r.objectFragmentNeedCleanup(fragmentOnObject, filteredUnionMemberTypeNames) {
+			return true
+		}
+	}
+
+	for _, fragmentOnInterface := range inlineFragment.selectionSetInfo.inlineFragmentsOnInterfaces {
+		if r.interfaceFragmentNeedCleanup(fragmentOnInterface, filteredUnionMemberTypeNames) {
+			return true
+		}
+	}
+
+	for _, fragmentOnUnion := range inlineFragment.selectionSetInfo.inlineFragmentsOnUnions {
+		if r.unionFragmentNeedCleanup(fragmentOnUnion, filteredUnionMemberTypeNames) {
+			return true
+		}
+	}
+
+	if inlineFragment.selectionSetInfo.hasFields {
+		for _, typeName := range filteredUnionMemberTypeNames {
+			if !r.typeHasAllFieldLocal(typeName, inlineFragment.selectionSetInfo.fields) {
+				return true
+			}
+
+			if r.hasRequiresConfigurationForField(typeName, inlineFragment.selectionSetInfo.fields) {
+				return true
+			}
+		}
+	}
+
 	return false
 }
 
@@ -202,11 +276,7 @@ func (r *fieldSelectionRewriter) interfaceFragmentNeedCleanup(inlineFragment inl
 	// check each fragment for the presence of other interface fragments
 	if inlineFragment.selectionSetInfo.hasInlineFragmentsOnObjects {
 		for _, fragmentOnObject := range inlineFragment.selectionSetInfo.inlineFragmentsOnObjects {
-			if !slices.Contains(parentSelectionValidTypes, fragmentOnObject.typeName) {
-				return true
-			}
-
-			if r.objectFragmentNeedCleanup(fragmentOnObject) {
+			if r.objectFragmentNeedCleanup(fragmentOnObject, parentSelectionValidTypes) {
 				return true
 			}
 		}
@@ -222,6 +292,14 @@ func (r *fieldSelectionRewriter) interfaceFragmentNeedCleanup(inlineFragment inl
 		}
 	}
 
+	if inlineFragment.selectionSetInfo.hasInlineFragmentsOnUnions {
+		for _, fragmentOnUnion := range inlineFragment.selectionSetInfo.inlineFragmentsOnUnions {
+			if r.unionFragmentNeedCleanup(fragmentOnUnion, parentSelectionValidTypes) {
+				return true
+			}
+		}
+	}
+
 	if inlineFragment.selectionSetInfo.hasFields {
 		// NOTE: maybe we need to filter this typenames by parentSelectionValidTypes?
 		for _, typeName := range inlineFragment.typeNamesImplementingInterfaceInCurrentDS {
diff --git a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
index 950ccb0..ed92045 100644
--- a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
@@ -146,6 +146,7 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 		if hasUpstreamNode {
 			if upstreamNode.Kind == ast.NodeKindInterfaceTypeDefinition {
 				typeNamesImplementingInterface, _ := r.upstreamDefinition.InterfaceTypeDefinitionImplementedByObjectWithNames(upstreamNode.Ref)
+				sort.Strings(typeNamesImplementingInterface)
 				entityNames, _ := r.datasourceHasEntitiesWithName(typeNamesImplementingInterface)
 
 				inlineFragmentSelectionOnInterface.typeNamesImplementingInterfaceInCurrentDS = typeNamesImplementingInterface
@@ -159,8 +160,9 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 		sort.Strings(unionMemberTypeNames)
 
 		inlineFragmentSelectionOnUnion := inlineFragmentSelectionOnUnion{
-			inlineFragmentSelection: inlineFragmentSelection,
-			unionMemberTypeNames:    unionMemberTypeNames,
+			inlineFragmentSelection:         inlineFragmentSelection,
+			unionMemberTypeNames:            unionMemberTypeNames,
+			unionMemberTypeNamesInCurrentDS: unionMemberTypeNames,
 		}
 
 		// NOTE: We are getting type names of union members from the current SUBGRAPH definion
@@ -169,9 +171,10 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 		if hasUpstreamNode {
 			if upstreamNode.Kind == ast.NodeKindUnionTypeDefinition {
 				unionMemberTypeNamesFromCurrentDS, _ := r.upstreamDefinition.UnionTypeDefinitionMemberTypeNames(upstreamNode.Ref)
+				sort.Strings(unionMemberTypeNamesFromCurrentDS)
 				entityNames, _ := r.datasourceHasEntitiesWithName(unionMemberTypeNamesFromCurrentDS)
 
-				inlineFragmentSelectionOnUnion.unionMemberTypeNames = unionMemberTypeNamesFromCurrentDS
+				inlineFragmentSelectionOnUnion.unionMemberTypeNamesInCurrentDS = unionMemberTypeNamesFromCurrentDS
 				inlineFragmentSelectionOnUnion.unionMemberEntityNames = entityNames
 			}
 		}
diff --git a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go
index c58465a..962bb01 100644
--- a/tmp/agent-patch-flux-pr-1184.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter_test.go
@@ -2437,6 +2437,199 @@ func TestInterfaceSelectionRewriter_RewriteOperation(t *testing.T) {
 				}`,
 			shouldRewrite: true,
 		},
+		{
+			name: "interface rewrite keeps nested union fragments and filters impossible nested concrete types",
+			definition: `
+				interface HasName {
+					name: String!
+				}
+
+				type User implements HasName {
+					id: ID!
+					name: String!
+					isUser: Boolean!
+				}
+
+				type Admin implements HasName {
+					id: ID!
+					name: String!
+				}
+
+				type Moderator {
+					id: ID!
+					name: String!
+					isModerator: Boolean!
+				}
+
+				union Account = User | Admin | Moderator
+
+				type Query {
+					iface: HasName!
+				}`,
+			upstreamDefinition: `
+				interface HasName {
+					name: String!
+				}
+
+				type User implements HasName {
+					id: ID!
+					name: String!
+					isUser: Boolean!
+				}
+
+				type Admin implements HasName {
+					id: ID!
+				}
+
+				type Moderator {
+					id: ID!
+					name: String!
+					isModerator: Boolean!
+				}
+
+				union Account = User | Admin | Moderator
+
+				type Query {
+					iface: HasName!
+				}`,
+			dsConfiguration: dsb().
+				RootNode("Query", "iface").
+				RootNode("User", "id", "name", "isUser").
+				RootNode("Admin", "id").
+				RootNode("Moderator", "id", "name", "isModerator").
+				RootNode("HasName", "name").
+				RootNode("Account", "__typename").
+				KeysMetadata(FederationFieldConfigurations{
+					{
+						TypeName:     "User",
+						SelectionSet: "id",
+					},
+					{
+						TypeName:     "Admin",
+						SelectionSet: "id",
+					},
+					{
+						TypeName:     "Moderator",
+						SelectionSet: "id",
+					},
+				}).
+				DS(),
+			operation: `
+				query {
+					iface {
+						name
+						... on Account {
+							... on User {
+								isUser
+							}
+							... on Moderator {
+								isModerator
+							}
+						}
+					}
+				}`,
+			expectedOperation: `
+				query {
+					iface {
+						... on Admin {
+							name
+						}
+						... on User {
+							name
+							isUser
+						}
+					}
+				}`,
+			shouldRewrite: true,
+		},
+		{
+			name:      "union rewrite keeps nested union fragments inside interface fragments",
+			fieldName: "returnsUnion",
+			definition: `
+				interface HasName {
+					name: String!
+				}
+
+				type User implements HasName {
+					id: ID!
+					name: String!
+					isUser: Boolean!
+				}
+
+				type Admin implements HasName {
+					id: ID!
+					name: String!
+				}
+
+				union Account = User | Admin
+
+				type Query {
+					returnsUnion: Account!
+				}`,
+			upstreamDefinition: `
+				interface HasName {
+					name: String!
+				}
+
+				type User implements HasName {
+					id: ID!
+					name: String!
+					isUser: Boolean!
+				}
+
+				type Admin implements HasName {
+					id: ID!
+				}
+
+				union Account = User | Admin
+
+				type Query {
+					returnsUnion: Account!
+				}`,
+			dsConfiguration: dsb().
+				RootNode("Query", "returnsUnion").
+				RootNode("User", "id", "name", "isUser").
+				RootNode("Admin", "id").
+				RootNode("HasName", "name").
+				RootNode("Account", "__typename").
+				KeysMetadata(FederationFieldConfigurations{
+					{
+						TypeName:     "User",
+						SelectionSet: "id",
+					},
+					{
+						TypeName:     "Admin",
+						SelectionSet: "id",
+					},
+				}).
+				DS(),
+			operation: `
+				query {
+					returnsUnion {
+						... on HasName {
+							name
+							... on Account {
+								... on User {
+									isUser
+								}
+							}
+						}
+					}
+				}`,
+			expectedOperation: `
+				query {
+					returnsUnion {
+						... on Admin {
+							name
+						}
+						... on User {
+							name
+							isUser
+						}
+					}
+				}`,
+			shouldRewrite: true,
+		},
 		{
 			name: "everything is local, nested interface selections with typename, first interface is matching field return type",
 			definition: `