agent_patch
runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-859/flux-pr-859.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch
17820 bytes
diff --git a/tmp/agent-patch-flux-pr-859.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 c5794ce..cc1e876 100644
--- a/tmp/agent-patch-flux-pr-859.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
@@ -60,12 +60,19 @@ type fieldSelectionRewriter struct {
upstreamDefinition *ast.Document
dsConfiguration DataSource
+
+ definitionInterfaceImplementors map[int][]string
+ upstreamInterfaceImplementors map[int][]string
+ upstreamInterfaceEntities map[int][]string
}
func newFieldSelectionRewriter(operation *ast.Document, definition *ast.Document) *fieldSelectionRewriter {
return &fieldSelectionRewriter{
- operation: operation,
- definition: definition,
+ operation: operation,
+ definition: definition,
+ definitionInterfaceImplementors: make(map[int][]string),
+ upstreamInterfaceImplementors: make(map[int][]string),
+ upstreamInterfaceEntities: make(map[int][]string),
}
}
diff --git a/tmp/agent-patch-flux-pr-859.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 ad5ea1d..7652d7c 100644
--- a/tmp/agent-patch-flux-pr-859.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
@@ -127,12 +127,9 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
return nil
}
- typeNamesImplementingInterface, _ := r.definition.InterfaceTypeDefinitionImplementedByObjectWithNames(definitionNode.Ref)
- sort.Strings(typeNamesImplementingInterface)
-
inlineFragmentSelectionOnInterface := inlineFragmentSelectionOnInterface{
inlineFragmentSelection: inlineFragmentSelection,
- typeNamesImplementingInterface: typeNamesImplementingInterface,
+ typeNamesImplementingInterface: r.typeNamesImplementingDefinitionInterface(definitionNode.Ref),
}
// NOTE: We are getting type names implementing interface from the current SUBGRAPH definion
@@ -140,11 +137,8 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
upstreamNode, hasUpstreamNode := r.upstreamDefinition.NodeByNameStr(typeCondition)
if hasUpstreamNode {
if upstreamNode.Kind == ast.NodeKindInterfaceTypeDefinition {
- typeNamesImplementingInterface, _ := r.upstreamDefinition.InterfaceTypeDefinitionImplementedByObjectWithNames(upstreamNode.Ref)
- entityNames, _ := r.datasourceHasEntitiesWithName(typeNamesImplementingInterface)
-
- inlineFragmentSelectionOnInterface.typeNamesImplementingInterfaceInCurrentDS = typeNamesImplementingInterface
- inlineFragmentSelectionOnInterface.entityNamesImplementingInterface = entityNames
+ inlineFragmentSelectionOnInterface.typeNamesImplementingInterfaceInCurrentDS = r.typeNamesImplementingUpstreamInterface(upstreamNode.Ref)
+ inlineFragmentSelectionOnInterface.entityNamesImplementingInterface = r.entityNamesImplementingUpstreamInterface(upstreamNode.Ref)
}
}
@@ -153,6 +147,39 @@ func (r *fieldSelectionRewriter) collectInlineFragmentInformation(
return nil
}
+func (r *fieldSelectionRewriter) typeNamesImplementingDefinitionInterface(interfaceRef int) []string {
+ if implementors, ok := r.definitionInterfaceImplementors[interfaceRef]; ok {
+ return implementors
+ }
+
+ implementors, _ := r.definition.InterfaceTypeDefinitionImplementedByObjectWithNames(interfaceRef)
+ sort.Strings(implementors)
+ r.definitionInterfaceImplementors[interfaceRef] = implementors
+ return implementors
+}
+
+func (r *fieldSelectionRewriter) typeNamesImplementingUpstreamInterface(interfaceRef int) []string {
+ if implementors, ok := r.upstreamInterfaceImplementors[interfaceRef]; ok {
+ return implementors
+ }
+
+ implementors, _ := r.upstreamDefinition.InterfaceTypeDefinitionImplementedByObjectWithNames(interfaceRef)
+ sort.Strings(implementors)
+ r.upstreamInterfaceImplementors[interfaceRef] = implementors
+ return implementors
+}
+
+func (r *fieldSelectionRewriter) entityNamesImplementingUpstreamInterface(interfaceRef int) []string {
+ if entities, ok := r.upstreamInterfaceEntities[interfaceRef]; ok {
+ return entities
+ }
+
+ implementors := r.typeNamesImplementingUpstreamInterface(interfaceRef)
+ entities, _ := r.datasourceHasEntitiesWithName(implementors)
+ r.upstreamInterfaceEntities[interfaceRef] = entities
+ return entities
+}
+
func (r *fieldSelectionRewriter) collectSelectionSetInformation(selectionSetRef int, skipTypeName bool) (selectionSetInfo, error) {
fieldSelections, hasSharedTypename := r.selectionSetFieldSelections(selectionSetRef, skipTypeName)
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/configuration_visitor.go b/app/v2/pkg/engine/plan/configuration_visitor.go
index 505795a..3da9298 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/configuration_visitor.go
+++ b/app/v2/pkg/engine/plan/configuration_visitor.go
@@ -44,6 +44,8 @@ type configurationVisitor struct {
skipFieldsRefs []int // skipFieldsRefs holds required field refs added by planner and should not be added to user response
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[pathDSKey]struct{} // addedPathIndex provides O(1) lookups for path+datasource pairs
+ addedPathDSIndex map[string]DSHash // addedPathDSIndex stores the first datasource hash seen for a path
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
@@ -57,6 +59,8 @@ type configurationVisitor struct {
secondaryRun bool // secondaryRun is a flag to indicate that we're running the configurationVisitor not the first time
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
fieldRef int // fieldRef is the reference for the current field; it is required by subscription filter to retrieve any variables
+
+ processedFieldRefs map[int]struct{} // processedFieldRefs tracks fields that already went through expensive planning checks
}
func (c *configurationVisitor) shouldRevisit() bool {
@@ -92,6 +96,11 @@ type missingPath struct {
precedingRootNodePath string
}
+type pathDSKey struct {
+ path string
+ dsHash DSHash
+}
+
func (p *missingPath) String() string {
return fmt.Sprintf(`{"path":"%s","precedingRootNodePath":"%s"}`, p.path, p.precedingRootNodePath)
}
@@ -184,28 +193,25 @@ func (c *configurationVisitor) saveAddedPath(configuration pathConfiguration) {
}
c.addedPathTracker = append(c.addedPathTracker, configuration)
+ c.addedPathIndex[pathDSKey{
+ path: configuration.path,
+ dsHash: configuration.dsHash,
+ }] = struct{}{}
+ if _, ok := c.addedPathDSIndex[configuration.path]; !ok {
+ c.addedPathDSIndex[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.addedPathDSIndex[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
- }
- }
- return false
+ _, ok := c.addedPathIndex[pathDSKey{path: path, dsHash: hash}]
+ return ok
}
func (c *configurationVisitor) findPreviousRootPath(currentPath string) (previousRootPath string, found bool) {
@@ -300,6 +306,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[pathDSKey]struct{}, 16)
+ c.addedPathDSIndex = make(map[string]DSHash, 16)
c.pendingRequiredFields = make(map[int]selectionSetPendingRequirements)
c.fieldDependenciesForPlanners = make(map[int][]int)
@@ -310,6 +318,7 @@ func (c *configurationVisitor) EnterDocument(operation, definition *ast.Document
c.processedFieldNotHavingRequires = make(map[int]struct{})
c.fieldsWithProcessedProvides = make(map[int]struct{})
c.visitedFieldsAbstractChecks = make(map[int]struct{})
+ c.processedFieldRefs = make(map[int]struct{})
}
func (c *configurationVisitor) LeaveDocument(operation, definition *ast.Document) {
@@ -381,6 +390,7 @@ func (c *configurationVisitor) EnterField(ref int) {
typeName := c.walker.EnclosingTypeDefinition.NameString(c.definition)
c.debugPrint("EnterField ref:", ref, "fieldName:", fieldName, "typeName:", typeName)
+ defer c.markFieldProcessed(ref)
parentPath := c.walker.Path.DotDelimitedString()
// we need to also check preceding path for inline fragments
@@ -395,6 +405,10 @@ func (c *configurationVisitor) EnterField(ref int) {
currentPath := parentPath + "." + fieldAliasOrName
c.addArrayField(ref, currentPath)
+ if c.secondaryRun && c.shouldSkipSecondaryRunField(ref, currentPath) {
+ return
+ }
+
c.handleProvidesSuggestions(ref, typeName, fieldName, currentPath)
root := c.walker.Ancestors[0]
@@ -432,6 +446,34 @@ func (c *configurationVisitor) EnterField(ref int) {
c.handleMissingPath(typeName, fieldName, currentPath)
}
+func (c *configurationVisitor) markFieldProcessed(fieldRef int) {
+ c.processedFieldRefs[fieldRef] = struct{}{}
+}
+
+func (c *configurationVisitor) shouldSkipSecondaryRunField(fieldRef int, currentPath string) bool {
+ if _, processed := c.processedFieldRefs[fieldRef]; !processed {
+ return false
+ }
+
+ if _, waitingForDependency := c.fieldWaitingForRequiresDependency[fieldRef]; waitingForDependency {
+ return false
+ }
+
+ if _, hasMissingPath := c.missingPathTracker[currentPath]; hasMissingPath {
+ return false
+ }
+
+ if c.hasMissingPathWithParentPath(currentPath) {
+ return false
+ }
+
+ if _, planned := c.fieldsPlannedOn[fieldRef]; !planned {
+ return false
+ }
+
+ return true
+}
+
func (c *configurationVisitor) addRootField(fieldRef, plannerIdx int) {
if c.fieldIsChildNode(plannerIdx) {
diff --git a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/datasource_configuration.go b/app/v2/pkg/engine/plan/datasource_configuration.go
index f078113..695c5b6 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/datasource_configuration.go
+++ b/app/v2/pkg/engine/plan/datasource_configuration.go
@@ -3,6 +3,7 @@ package plan
import (
"context"
"errors"
+ "sync"
"github.com/cespare/xxhash/v2"
"github.com/jensneuse/abstractlogger"
@@ -40,6 +41,16 @@ type DataSourceMetadata struct {
// Note: Unions are not present in the child or root nodes
ChildNodes TypeFields
Directives *DirectiveConfigurations
+
+ rootNodesIndex typeFieldsIndex
+ childNodesIndex typeFieldsIndex
+ indexesMu sync.Mutex
+ indexesReady bool
+}
+
+type typeFieldsIndex struct {
+ byType map[string]map[string]struct{}
+ typeOnly map[string]struct{}
}
type DirectivesConfigurations interface {
@@ -63,19 +74,35 @@ func (d *DataSourceMetadata) DirectiveConfigurations() *DirectiveConfigurations
}
func (d *DataSourceMetadata) HasRootNode(typeName, fieldName string) bool {
- return d.RootNodes.HasNode(typeName, fieldName)
+ d.prepareIndexes()
+ fieldsByType, ok := d.rootNodesIndex.byType[typeName]
+ if !ok {
+ return false
+ }
+ _, ok = fieldsByType[fieldName]
+ return ok
}
func (d *DataSourceMetadata) HasRootNodeWithTypename(typeName string) bool {
- return d.RootNodes.HasNodeWithTypename(typeName)
+ d.prepareIndexes()
+ _, ok := d.rootNodesIndex.typeOnly[typeName]
+ return ok
}
func (d *DataSourceMetadata) HasChildNode(typeName, fieldName string) bool {
- return d.ChildNodes.HasNode(typeName, fieldName)
+ d.prepareIndexes()
+ fieldsByType, ok := d.childNodesIndex.byType[typeName]
+ if !ok {
+ return false
+ }
+ _, ok = fieldsByType[fieldName]
+ return ok
}
func (d *DataSourceMetadata) HasChildNodeWithTypename(typeName string) bool {
- return d.ChildNodes.HasNodeWithTypename(typeName)
+ d.prepareIndexes()
+ _, ok := d.childNodesIndex.typeOnly[typeName]
+ return ok
}
func (d *DataSourceMetadata) ListRootNodes() TypeFields {
@@ -87,6 +114,43 @@ func (d *DataSourceMetadata) ListChildNodes() TypeFields {
}
+func (d *DataSourceMetadata) prepareIndexes() {
+ if d.indexesReady {
+ return
+ }
+
+ d.indexesMu.Lock()
+ defer d.indexesMu.Unlock()
+ if d.indexesReady {
+ return
+ }
+
+ d.rootNodesIndex = buildTypeFieldsIndex(d.RootNodes)
+ d.childNodesIndex = buildTypeFieldsIndex(d.ChildNodes)
+ d.indexesReady = true
+}
+
+func buildTypeFieldsIndex(nodes TypeFields) typeFieldsIndex {
+ index := typeFieldsIndex{
+ byType: make(map[string]map[string]struct{}, len(nodes)),
+ typeOnly: make(map[string]struct{}, len(nodes)),
+ }
+
+ for i := range nodes {
+ typeName := nodes[i].TypeName
+ index.typeOnly[typeName] = struct{}{}
+
+ if _, ok := index.byType[typeName]; !ok {
+ index.byType[typeName] = make(map[string]struct{}, len(nodes[i].FieldNames))
+ }
+ for j := range nodes[i].FieldNames {
+ index.byType[typeName][nodes[i].FieldNames[j]] = struct{}{}
+ }
+ }
+
+ return index
+}
+
// 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-28__13-38-10__gpt-5-3-codex/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..da32829 100644
--- a/tmp/agent-patch-flux-pr-859.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go
+++ b/app/v2/pkg/engine/plan/datasource_filter_collect_nodes_visitor.go
@@ -1,8 +1,6 @@
package plan
import (
- "slices"
-
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor"
)
@@ -19,10 +17,18 @@ type collectNodesVisitor struct {
parentNodeIds []uint
saveSelectionReason bool
+
+ dsIndexes []collectNodesDataSourceIndex
+}
+
+type collectNodesDataSourceIndex struct {
+ blockedTypeName map[string]struct{}
+ lessPreferableRootTypes map[string]struct{}
}
func (f *collectNodesVisitor) EnterDocument(_, _ *ast.Document) {
f.parentNodeIds = []uint{treeRootID}
+ f.buildDataSourceIndexes()
if !f.secondaryRun {
f.nodes = NewNodeSuggestions()
@@ -34,6 +40,33 @@ func (f *collectNodesVisitor) EnterDocument(_, _ *ast.Document) {
}
}
+func (f *collectNodesVisitor) buildDataSourceIndexes() {
+ f.dsIndexes = make([]collectNodesDataSourceIndex, len(f.dataSources))
+
+ for i := range f.dataSources {
+ index := collectNodesDataSourceIndex{
+ blockedTypeName: make(map[string]struct{}),
+ lessPreferableRootTypes: make(map[string]struct{}),
+ }
+
+ federationCfg := f.dataSources[i].FederationConfiguration()
+ for _, interfaceObject := range federationCfg.InterfaceObjects {
+ index.blockedTypeName[interfaceObject.InterfaceTypeName] = struct{}{}
+ for _, concreteType := range interfaceObject.ConcreteTypeNames {
+ index.blockedTypeName[concreteType] = struct{}{}
+ }
+ }
+
+ for _, key := range federationCfg.Keys {
+ if key.DisableEntityResolver {
+ index.lessPreferableRootTypes[key.TypeName] = struct{}{}
+ }
+ }
+
+ f.dsIndexes[i] = index
+ }
+}
+
func (f *collectNodesVisitor) EnterField(ref int) {
if f.nodes.IsFieldSeen(ref) {
currentNodeId := TreeNodeID(ref)
@@ -59,27 +92,16 @@ func (f *collectNodesVisitor) EnterField(ref int) {
itemIds := make([]int, 0, 1)
- for _, v := range f.dataSources {
+ for i, v := range f.dataSources {
hasRootNode := v.HasRootNode(typeName, fieldName) || (isTypeName && v.HasRootNodeWithTypename(typeName))
hasChildNode := v.HasChildNode(typeName, fieldName) || (isTypeName && v.HasChildNodeWithTypename(typeName))
- allowTypeName := true
- // we should not select a typename on the interface object
- for _, k := range v.FederationConfiguration().InterfaceObjects {
- if k.InterfaceTypeName == typeName || slices.Contains(k.ConcreteTypeNames, typeName) {
- allowTypeName = false
- break
- }
- }
+ _, blockedTypeName := f.dsIndexes[i].blockedTypeName[typeName]
+ allowTypeName := !blockedTypeName
lessPreferable := false
if hasRootNode {
- for _, k := range v.FederationConfiguration().Keys {
- if k.TypeName == typeName && k.DisableEntityResolver {
- lessPreferable = true
- break
- }
- }
+ _, lessPreferable = f.dsIndexes[i].lessPreferableRootTypes[typeName]
}
if !allowTypeName && isTypeName {