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
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:]...)