STET

agent_patch

runs/2026-02-21__03-36-16__gpt-5-1-codex-mini/flux-pr-859/flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/agent-logs/agent.patch

15438 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/abstract_selection_rewriter.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
index c5794ce..64226d2 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter.go
@@ -60,23 +60,44 @@ type fieldSelectionRewriter struct {
 
 	upstreamDefinition *ast.Document
 	dsConfiguration    DataSource
+
+	definitionImplementors *interfaceImplementorCache
+	upstreamImplementors   *interfaceImplementorCache
 }
 
 func newFieldSelectionRewriter(operation *ast.Document, definition *ast.Document) *fieldSelectionRewriter {
 	return &fieldSelectionRewriter{
-		operation:  operation,
-		definition: definition,
+		operation:              operation,
+		definition:             definition,
+		definitionImplementors: newInterfaceImplementorCache(definition),
 	}
 }
 
 func (r *fieldSelectionRewriter) SetUpstreamDefinition(upstreamDefinition *ast.Document) {
 	r.upstreamDefinition = upstreamDefinition
+	if upstreamDefinition != nil {
+		r.upstreamImplementors = newInterfaceImplementorCache(upstreamDefinition)
+	} else {
+		r.upstreamImplementors = nil
+	}
 }
 
 func (r *fieldSelectionRewriter) SetDatasourceConfiguration(dsConfiguration DataSource) {
 	r.dsConfiguration = dsConfiguration
 }
 
+func (r *fieldSelectionRewriter) definitionInterfaceImplementors(ref int) ([]string, bool) {
+	return r.definitionImplementors.typeNames(ref)
+}
+
+func (r *fieldSelectionRewriter) upstreamInterfaceImplementors(ref int) ([]string, bool) {
+	if r.upstreamImplementors == nil {
+		return nil, false
+	}
+
+	return r.upstreamImplementors.typeNames(ref)
+}
+
 func (r *fieldSelectionRewriter) RewriteFieldSelection(fieldRef int, enclosingNode ast.Node) (rewritten bool, err error) {
 	fieldTypeNode, ok := r.definition.FieldTypeNode(r.operation.FieldNameBytes(fieldRef), enclosingNode)
 	if !ok {
@@ -266,7 +287,7 @@ func (r *fieldSelectionRewriter) processInterfaceSelection(fieldRef int, interfa
 
 	if !isInterfaceObject {
 		var ok bool
-		interfaceTypeNames, ok = r.upstreamDefinition.InterfaceTypeDefinitionImplementedByObjectWithNames(node.Ref)
+		interfaceTypeNames, ok = r.upstreamInterfaceImplementors(node.Ref)
 		if !ok {
 			return false, nil
 		}
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go b/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
index ad5ea1d..f9dfebd 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
+++ b/app/v2/pkg/engine/plan/abstract_selection_rewriter_info.go
@@ -127,7 +127,7 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 		return nil
 	}
 
-	typeNamesImplementingInterface, _ := r.definition.InterfaceTypeDefinitionImplementedByObjectWithNames(definitionNode.Ref)
+	typeNamesImplementingInterface, _ := r.definitionInterfaceImplementors(definitionNode.Ref)
 	sort.Strings(typeNamesImplementingInterface)
 
 	inlineFragmentSelectionOnInterface := inlineFragmentSelectionOnInterface{
@@ -140,7 +140,7 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
 	upstreamNode, hasUpstreamNode := r.upstreamDefinition.NodeByNameStr(typeCondition)
 	if hasUpstreamNode {
 		if upstreamNode.Kind == ast.NodeKindInterfaceTypeDefinition {
-			typeNamesImplementingInterface, _ := r.upstreamDefinition.InterfaceTypeDefinitionImplementedByObjectWithNames(upstreamNode.Ref)
+			typeNamesImplementingInterface, _ := r.upstreamInterfaceImplementors(upstreamNode.Ref)
 			entityNames, _ := r.datasourceHasEntitiesWithName(typeNamesImplementingInterface)
 
 			inlineFragmentSelectionOnInterface.typeNamesImplementingInterfaceInCurrentDS = typeNamesImplementingInterface
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/configuration_visitor.go b/app/v2/pkg/engine/plan/configuration_visitor.go
index 505795a..b59a7a9 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/configuration_visitor.go
+++ b/app/v2/pkg/engine/plan/configuration_visitor.go
@@ -45,6 +45,9 @@ type configurationVisitor struct {
 	missingPathTracker map[string]missingPath // missingPathTracker is a map of paths which will be added on secondary runs
 	addedPathTracker   []pathConfiguration    // addedPathTracker is a list of paths which were added
 
+	addedPathIndex map[string]map[DSHash]struct{}
+	addedPathHash  map[string]DSHash
+
 	pendingRequiredFields             map[int]selectionSetPendingRequirements // pendingRequiredFields is a map[selectionSetRef][]fieldsRequirementConfig
 	processedFieldNotHavingRequires   map[int]struct{}                        // processedFieldNotHavingRequires is a map[FieldRef] of already processed fields which do not have @requires directive
 	fieldsWithProcessedProvides       map[int]struct{}                        // fieldsWithProcessedProvides is a map[FieldRef] of already processed fields which we check for @provides directive
@@ -184,28 +187,30 @@ func (c *configurationVisitor) saveAddedPath(configuration pathConfiguration) {
 	}
 
 	c.addedPathTracker = append(c.addedPathTracker, configuration)
+	if _, exists := c.addedPathIndex[configuration.path]; !exists {
+		c.addedPathIndex[configuration.path] = make(map[DSHash]struct{})
+	}
+	c.addedPathIndex[configuration.path][configuration.dsHash] = struct{}{}
+	if _, exists := c.addedPathHash[configuration.path]; !exists {
+		c.addedPathHash[configuration.path] = configuration.dsHash
+	}
 
 	c.removeMissingPath(configuration.path)
 }
 
 func (c *configurationVisitor) addedPathDSHash(path string) (hash DSHash, ok bool) {
-	// NOTE: it will found first occurence of such path
-	for i := range c.addedPathTracker {
-		if c.addedPathTracker[i].path == path {
-			return c.addedPathTracker[i].dsHash, true
-		}
-	}
-	return 0, false
+	hash, ok = c.addedPathHash[path]
+	return hash, ok
 }
 
 func (c *configurationVisitor) isPathAddedFor(path string, hash DSHash) bool {
-	// TODO: could be optimized by using map[struct{path,hash}]
-	for i := range c.addedPathTracker {
-		if c.addedPathTracker[i].path == path && c.addedPathTracker[i].dsHash == hash {
-			return true
-		}
+	dsHashes, exists := c.addedPathIndex[path]
+	if !exists {
+		return false
 	}
-	return false
+
+	_, exists = dsHashes[hash]
+	return exists
 }
 
 func (c *configurationVisitor) findPreviousRootPath(currentPath string) (previousRootPath string, found bool) {
@@ -300,6 +305,8 @@ func (c *configurationVisitor) EnterDocument(operation, definition *ast.Document
 
 	c.missingPathTracker = make(map[string]missingPath)
 	c.addedPathTracker = make([]pathConfiguration, 0, 8)
+	c.addedPathIndex = make(map[string]map[DSHash]struct{}, 8)
+	c.addedPathHash = make(map[string]DSHash, 8)
 
 	c.pendingRequiredFields = make(map[int]selectionSetPendingRequirements)
 	c.fieldDependenciesForPlanners = make(map[int][]int)
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/datasource_configuration.go b/app/v2/pkg/engine/plan/datasource_configuration.go
index f078113..8e7efd4 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/datasource_configuration.go
+++ b/app/v2/pkg/engine/plan/datasource_configuration.go
@@ -38,8 +38,10 @@ type DataSourceMetadata struct {
 	// For any flat datasource like HTTP/REST or GRPC we could not request fewer fields, as we always get a full response
 	// Note: for federation child nodes are non-entity type fields and interface type fields
 	// Note: Unions are not present in the child or root nodes
-	ChildNodes TypeFields
-	Directives *DirectiveConfigurations
+	ChildNodes     TypeFields
+	rootNodeIndex  *typeNodeIndex
+	childNodeIndex *typeNodeIndex
+	Directives     *DirectiveConfigurations
 }
 
 type DirectivesConfigurations interface {
@@ -63,19 +65,19 @@ func (d *DataSourceMetadata) DirectiveConfigurations() *DirectiveConfigurations
 }
 
 func (d *DataSourceMetadata) HasRootNode(typeName, fieldName string) bool {
-	return d.RootNodes.HasNode(typeName, fieldName)
+	return d.ensureRootNodeIndex().hasNode(typeName, fieldName)
 }
 
 func (d *DataSourceMetadata) HasRootNodeWithTypename(typeName string) bool {
-	return d.RootNodes.HasNodeWithTypename(typeName)
+	return d.ensureRootNodeIndex().hasTypename(typeName)
 }
 
 func (d *DataSourceMetadata) HasChildNode(typeName, fieldName string) bool {
-	return d.ChildNodes.HasNode(typeName, fieldName)
+	return d.ensureChildNodeIndex().hasNode(typeName, fieldName)
 }
 
 func (d *DataSourceMetadata) HasChildNodeWithTypename(typeName string) bool {
-	return d.ChildNodes.HasNodeWithTypename(typeName)
+	return d.ensureChildNodeIndex().hasTypename(typeName)
 }
 
 func (d *DataSourceMetadata) ListRootNodes() TypeFields {
@@ -87,6 +89,20 @@ func (d *DataSourceMetadata) ListChildNodes() TypeFields {
 
 }
 
+func (d *DataSourceMetadata) ensureRootNodeIndex() *typeNodeIndex {
+	if d.rootNodeIndex == nil {
+		d.rootNodeIndex = newTypeNodeIndex(d.RootNodes)
+	}
+	return d.rootNodeIndex
+}
+
+func (d *DataSourceMetadata) ensureChildNodeIndex() *typeNodeIndex {
+	if d.childNodeIndex == nil {
+		d.childNodeIndex = newTypeNodeIndex(d.ChildNodes)
+	}
+	return d.childNodeIndex
+}
+
 // dataSourceConfiguration is the configuration for a DataSource
 type dataSourceConfiguration[T any] struct {
 	*DataSourceMetadata                   // DataSourceMetadata is the information about root and child nodes and federation metadata if applicable
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go b/app/v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go
index 3852ed6..693a0fa 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go
+++ b/app/v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go
@@ -38,6 +38,7 @@ func (f *collectNodesVisitor) EnterField(ref int) {
 	if f.nodes.IsFieldSeen(ref) {
 		currentNodeId := TreeNodeID(ref)
 		f.parentNodeIds = append(f.parentNodeIds, currentNodeId)
+		f.walker.SkipNode()
 		return
 	}
 	f.nodes.AddSeenField(ref)
diff --git a/app/v2/pkg/engine/plan/interface_implementor_cache.go b/app/v2/pkg/engine/plan/interface_implementor_cache.go
new file mode 100644
index 0000000..d6ab1d9
--- /dev/null
+++ b/app/v2/pkg/engine/plan/interface_implementor_cache.go
@@ -0,0 +1,38 @@
+package plan
+
+import "github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+
+type interfaceImplementorCache struct {
+	doc   *ast.Document
+	cache map[int][]string
+}
+
+func newInterfaceImplementorCache(doc *ast.Document) *interfaceImplementorCache {
+	if doc == nil {
+		return nil
+	}
+	return &interfaceImplementorCache{
+		doc:   doc,
+		cache: make(map[int][]string),
+	}
+}
+
+func (c *interfaceImplementorCache) typeNames(ref int) ([]string, bool) {
+	if c == nil || ref == ast.InvalidRef {
+		return nil, false
+	}
+	if cached, ok := c.cache[ref]; ok {
+		if cached == nil {
+			return nil, false
+		}
+		return append([]string(nil), cached...), true
+	}
+	typeNames, ok := c.doc.InterfaceTypeDefinitionImplementedByObjectWithNames(ref)
+	if !ok {
+		c.cache[ref] = nil
+		return nil, false
+	}
+	copied := append([]string(nil), typeNames...)
+	c.cache[ref] = copied
+	return copied, true
+}
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/type_field.go b/app/v2/pkg/engine/plan/type_field.go
index 80f7125..eb95033 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/type_field.go
+++ b/app/v2/pkg/engine/plan/type_field.go
@@ -30,3 +30,58 @@ func (f TypeFields) HasNodeWithTypename(typeName string) bool {
 	}
 	return false
 }
+
+type typeNodeIndex struct {
+	nodes     map[string]map[string]struct{}
+	typeNames map[string]struct{}
+}
+
+func newTypeNodeIndex(fields TypeFields) *typeNodeIndex {
+	idx := &typeNodeIndex{
+		nodes:     make(map[string]map[string]struct{}, len(fields)),
+		typeNames: make(map[string]struct{}, len(fields)),
+	}
+
+	for _, typeField := range fields {
+		idx.typeNames[typeField.TypeName] = struct{}{}
+
+		if len(typeField.FieldNames) == 0 {
+			continue
+		}
+
+		fieldsMap, ok := idx.nodes[typeField.TypeName]
+		if !ok {
+			fieldsMap = make(map[string]struct{}, len(typeField.FieldNames))
+			idx.nodes[typeField.TypeName] = fieldsMap
+		}
+
+		for _, fieldName := range typeField.FieldNames {
+			fieldsMap[fieldName] = struct{}{}
+		}
+	}
+
+	return idx
+}
+
+func (i *typeNodeIndex) hasNode(typeName, fieldName string) bool {
+	if i == nil {
+		return false
+	}
+
+	fields, ok := i.nodes[typeName]
+	if !ok {
+		return false
+	}
+
+	_, ok = fields[fieldName]
+	return ok
+}
+
+func (i *typeNodeIndex) hasTypename(typeName string) bool {
+	if i == nil {
+		return false
+	}
+
+	_, ok := i.typeNames[typeName]
+	return ok
+}
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/visitor.go b/app/v2/pkg/engine/plan/visitor.go
index 9fa8e45..7aad195 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-21__03-36-16__gpt-5-1-codex-mini/app/v2/pkg/engine/plan/visitor.go
+++ b/app/v2/pkg/engine/plan/visitor.go
@@ -38,6 +38,7 @@ type Visitor struct {
 	fieldConfigs                 map[int]*FieldConfiguration
 	exportedVariables            map[string]struct{}
 	skipIncludeOnFragments       map[int]skipIncludeInfo
+	interfaceImplementorsCache   map[int][]string
 	disableResolveFieldPositions bool
 }
 
@@ -428,6 +429,29 @@ func (v *Visitor) resolveSkipIncludeForField(fieldRef int) skipIncludeInfo {
 	return skipIncludeInfo{}
 }
 
+func (v *Visitor) interfaceImplementors(ref int) ([]string, bool) {
+	if v.interfaceImplementorsCache == nil {
+		v.interfaceImplementorsCache = make(map[int][]string)
+	}
+	if names, ok := v.interfaceImplementorsCache[ref]; ok {
+		if names == nil {
+			return nil, false
+		}
+		return append([]string(nil), names...), true
+	}
+	if v.Definition == nil {
+		return nil, false
+	}
+	names, ok := v.Definition.InterfaceTypeDefinitionImplementedByObjectWithNames(ref)
+	if !ok {
+		v.interfaceImplementorsCache[ref] = nil
+		return nil, false
+	}
+	copied := append([]string(nil), names...)
+	v.interfaceImplementorsCache[ref] = copied
+	return copied, true
+}
+
 func (v *Visitor) resolveOnTypeNames(fieldRef int) [][]byte {
 	if len(v.Walker.Ancestors) < 2 {
 		return nil
@@ -474,7 +498,7 @@ func (v *Visitor) resolveOnTypeNames(fieldRef int) [][]byte {
 			}
 		}
 		if grandParent.Kind == ast.NodeKindInterfaceTypeDefinition {
-			objectTypesImplementingGrandParent, _ := v.Definition.InterfaceTypeDefinitionImplementedByObjectWithNames(grandParent.Ref)
+			objectTypesImplementingGrandParent, _ := v.interfaceImplementors(grandParent.Ref)
 			for i := 0; i < len(onTypeNames); i++ {
 				if !slices.Contains(objectTypesImplementingGrandParent, string(onTypeNames[i])) {
 					onTypeNames = append(onTypeNames[:i], onTypeNames[i+1:]...)