agent_patch
runs/2026-02-28__13-38-10__gpt-5-4/flux-pr-1380/flux-pr-1380.1-of-1.2026-02-28__13-38-10__gpt-5-4/agent-logs/agent.patch
9187 bytes
diff --git a/tmp/agent-patch-flux-pr-1380.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 bbcffd3..e053afa 100644
--- a/tmp/agent-patch-flux-pr-1380.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
@@ -4,9 +4,11 @@ import (
"errors"
"fmt"
"slices"
+ "strings"
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/operationreport"
)
// nodeSelectionVisitor walks through the operation multiple times to rewrite it
@@ -290,6 +292,10 @@ func (c *nodeSelectionVisitor) handleFieldRequiredByRequires(fieldRef int, paren
return
}
+ if c.areRequiresFieldsSatisfiedBySelections(parentPath, requiresConfiguration) {
+ return
+ }
+
// we should plan adding required fields for the field
// they will be added in the on LeaveSelectionSet callback for the current selection set
// and current field ref will be added to fieldDependsOn map
@@ -770,3 +776,57 @@ func (c *nodeSelectionVisitor) updateSkipFieldRefs(changedFieldRefs map[int][]in
}
}
}
+
+func (c *nodeSelectionVisitor) areRequiresFieldsSatisfiedBySelections(parentPath string, requiresConfiguration FederationFieldConfiguration) bool {
+ if c.nodeSuggestions == nil {
+ return false
+ }
+
+ if err := requiresConfiguration.parseSelectionSet(); err != nil {
+ return false
+ }
+
+ report := &operationreport.Report{}
+ walker := astvisitor.NewWalkerWithID(48, "RequiresSelectionSatisfactionVisitor")
+ visitor := &requiresSelectionSatisfactionVisitor{
+ walker: &walker,
+ operation: requiresConfiguration.parsedSelectionSet,
+ definition: c.definition,
+ parentPath: parentPath,
+ rootTypeName: requiresConfiguration.TypeName,
+ suggestions: c.nodeSuggestions,
+ satisfied: true,
+ }
+
+ walker.RegisterEnterFieldVisitor(visitor)
+ walker.Walk(requiresConfiguration.parsedSelectionSet, c.definition, report)
+
+ return !report.HasErrors() && visitor.satisfied
+}
+
+type requiresSelectionSatisfactionVisitor struct {
+ walker *astvisitor.Walker
+ operation *ast.Document
+ definition *ast.Document
+ parentPath string
+ rootTypeName string
+ suggestions *NodeSuggestions
+ satisfied bool
+}
+
+func (v *requiresSelectionSatisfactionVisitor) EnterField(ref int) {
+ if !v.satisfied {
+ return
+ }
+
+ fieldName := v.operation.FieldNameUnsafeString(ref)
+ typeName := v.walker.EnclosingTypeDefinition.NameString(v.definition)
+ currentPathWithoutFragments := v.walker.Path.WithoutInlineFragmentNames().DotDelimitedString()
+ parentPath := v.parentPath + strings.TrimPrefix(currentPathWithoutFragments, v.rootTypeName)
+ currentPath := parentPath + "." + fieldName
+
+ _, ok := v.suggestions.HasSuggestionForPath(typeName, fieldName, currentPath)
+ if !ok {
+ v.satisfied = false
+ }
+}
diff --git a/app/v2/pkg/engine/plan/node_selection_visitor_test.go b/app/v2/pkg/engine/plan/node_selection_visitor_test.go
new file mode 100644
index 0000000..5ba886a
--- /dev/null
+++ b/app/v2/pkg/engine/plan/node_selection_visitor_test.go
@@ -0,0 +1,163 @@
+package plan
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/internal/unsafeparser"
+)
+
+func TestNodeSelectionVisitor_HandleFieldRequiredByRequires(t *testing.T) {
+ definition := unsafeparser.ParseGraphqlDocumentStringWithBaseSchema(`
+ type Query {
+ me: User!
+ }
+
+ type User {
+ address: Address!
+ }
+
+ type Address {
+ street: String!
+ zip: String!
+ }
+ `)
+
+ operation := unsafeparser.ParseGraphqlDocumentString(`
+ query {
+ me {
+ address {
+ street
+ }
+ }
+ }
+ `)
+
+ addressSelectionSetRef := findFieldSelectionSetRefByPath(t, &operation, operation.OperationDefinitions[0].SelectionSet, "me", "address")
+ streetFieldRef := findFieldRefByPath(t, &operation, operation.OperationDefinitions[0].SelectionSet, "me", "address", "street")
+
+ ds := &dataSourceConfiguration[any]{
+ hash: 1,
+ DataSourceMetadata: &DataSourceMetadata{
+ FederationMetaData: FederationMetaData{
+ Requires: FederationFieldConfigurations{
+ {
+ TypeName: "Address",
+ FieldName: "street",
+ SelectionSet: "zip",
+ },
+ },
+ },
+ },
+ }
+
+ t.Run("skips pending requirements when selected suggestions already satisfy requires", func(t *testing.T) {
+ visitor := &nodeSelectionVisitor{
+ operation: &operation,
+ definition: &definition,
+ nodeSuggestions: selectedSuggestions(newSuggestion("Address", "zip", "query.me.address.zip")),
+ selectionSetRefs: []int{addressSelectionSetRef},
+ pendingFieldRequirements: make(map[int]pendingFieldRequirements),
+ visitedFieldsRequiresChecks: make(map[fieldIndexKey]struct{}),
+ visitedFieldsKeyChecks: make(map[fieldIndexKey]struct{}),
+ visitedFieldsAbstractChecks: make(map[int]struct{}),
+ fieldDependencyKind: make(map[fieldDependencyKey]fieldDependencyKind),
+ fieldDependsOn: make(map[fieldIndexKey][]int),
+ fieldRefDependsOn: make(map[int][]int),
+ fieldRequirementsConfigs: make(map[fieldIndexKey][]FederationFieldConfiguration),
+ fieldLandedTo: make(map[int]DSHash),
+ newFieldRefs: make(map[int]struct{}),
+ }
+
+ visitor.handleFieldRequiredByRequires(streetFieldRef, "query.me.address", "Address", "street", "query.me.address.street", ds)
+
+ assert.Empty(t, visitor.pendingFieldRequirements)
+ })
+
+ t.Run("adds pending requirements when selections do not satisfy requires", func(t *testing.T) {
+ visitor := &nodeSelectionVisitor{
+ operation: &operation,
+ definition: &definition,
+ nodeSuggestions: NewNodeSuggestions(),
+ selectionSetRefs: []int{addressSelectionSetRef},
+ pendingFieldRequirements: make(map[int]pendingFieldRequirements),
+ visitedFieldsRequiresChecks: make(map[fieldIndexKey]struct{}),
+ visitedFieldsKeyChecks: make(map[fieldIndexKey]struct{}),
+ visitedFieldsAbstractChecks: make(map[int]struct{}),
+ fieldDependencyKind: make(map[fieldDependencyKey]fieldDependencyKind),
+ fieldDependsOn: make(map[fieldIndexKey][]int),
+ fieldRefDependsOn: make(map[int][]int),
+ fieldRequirementsConfigs: make(map[fieldIndexKey][]FederationFieldConfiguration),
+ fieldLandedTo: make(map[int]DSHash),
+ newFieldRefs: make(map[int]struct{}),
+ }
+
+ visitor.handleFieldRequiredByRequires(streetFieldRef, "query.me.address", "Address", "street", "query.me.address.street", ds)
+
+ require.Len(t, visitor.pendingFieldRequirements, 1)
+ require.Contains(t, visitor.pendingFieldRequirements, addressSelectionSetRef)
+ assert.Len(t, visitor.pendingFieldRequirements[addressSelectionSetRef].requirementConfigs, 1)
+ assert.Equal(t, "zip", visitor.pendingFieldRequirements[addressSelectionSetRef].requirementConfigs[0].selectionSet)
+ })
+}
+
+func selectedSuggestions(suggestions ...*NodeSuggestion) *NodeSuggestions {
+ nodes := NewNodeSuggestionsWithSize(len(suggestions))
+ nodes.AddItems(suggestions...)
+ return nodes
+}
+
+func newSuggestion(typeName, fieldName, path string) *NodeSuggestion {
+ return &NodeSuggestion{
+ TypeName: typeName,
+ FieldName: fieldName,
+ Path: path,
+ DataSourceHash: 1,
+ Selected: true,
+ }
+}
+
+func findFieldRefByPath(t *testing.T, operation *ast.Document, selectionSetRef int, path ...string) int {
+ t.Helper()
+
+ currentSelectionSetRef := selectionSetRef
+ for i, segment := range path {
+ fieldRef := findFieldRefInSelectionSet(t, operation, currentSelectionSetRef, segment)
+ if i == len(path)-1 {
+ return fieldRef
+ }
+
+ nextSelectionSetRef, ok := operation.FieldSelectionSet(fieldRef)
+ require.True(t, ok, "field %s has no selection set", segment)
+ currentSelectionSetRef = nextSelectionSetRef
+ }
+
+ t.Fatalf("path %v not found", path)
+ return ast.InvalidRef
+}
+
+func findFieldSelectionSetRefByPath(t *testing.T, operation *ast.Document, selectionSetRef int, path ...string) int {
+ t.Helper()
+
+ fieldRef := findFieldRefByPath(t, operation, selectionSetRef, path...)
+ nextSelectionSetRef, ok := operation.FieldSelectionSet(fieldRef)
+ require.True(t, ok, "field %v has no selection set", path)
+ return nextSelectionSetRef
+}
+
+func findFieldRefInSelectionSet(t *testing.T, operation *ast.Document, selectionSetRef int, fieldName string) int {
+ t.Helper()
+
+ for _, selectionRef := range operation.SelectionSetFieldSelections(selectionSetRef) {
+ fieldRef := operation.Selections[selectionRef].Ref
+ if operation.FieldNameString(fieldRef) == fieldName {
+ return fieldRef
+ }
+ }
+
+ t.Fatalf("field %s not found in selection set %d", fieldName, selectionSetRef)
+ return ast.InvalidRef
+}