agent_patch
runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-828/flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch
15339 bytes
diff --git a/app/v2/pkg/astminifier/astminifier.go b/app/v2/pkg/astminifier/astminifier.go
new file mode 100644
index 0000000..7e4c520
--- /dev/null
+++ b/app/v2/pkg/astminifier/astminifier.go
@@ -0,0 +1,282 @@
+package astminifier
+
+import (
+ "fmt"
+ "sort"
+
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/astparser"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/astprinter"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/operationreport"
+)
+
+// MinifySubgraphOperationIfSmaller deduplicates repeated inline-fragment selection sets by
+// extracting them into named fragments. It returns the minified operation only when it is smaller.
+func MinifySubgraphOperationIfSmaller(operation []byte) (out []byte, applied bool, err error) {
+ minified, changed, err := MinifySubgraphOperation(operation)
+ if err != nil {
+ return nil, false, err
+ }
+ if !changed || len(minified) >= len(operation) {
+ return operation, false, nil
+ }
+ return minified, true, nil
+}
+
+// MinifySubgraphOperation deduplicates repeated inline-fragment selection sets by extracting
+// them into named fragments.
+func MinifySubgraphOperation(operation []byte) (out []byte, changed bool, err error) {
+ doc := ast.NewSmallDocument()
+ report := &operationreport.Report{}
+ parser := astparser.NewParser()
+ doc.Input.ResetInputBytes(operation)
+ parser.Parse(doc, report)
+ if report.HasErrors() {
+ return nil, false, fmt.Errorf("astminifier: parse operation failed: %w", report)
+ }
+
+ changed = dedupeInlineFragmentSelectionSets(doc)
+
+ minified, err := astprinter.PrintString(doc, nil)
+ if err != nil {
+ return nil, false, fmt.Errorf("astminifier: print operation failed: %w", err)
+ }
+
+ return []byte(minified), changed, nil
+}
+
+func dedupeInlineFragmentSelectionSets(doc *ast.Document) bool {
+ inlineFragmentRefsByType := make(map[string][]int)
+ for inlineFragmentRef := range doc.InlineFragments {
+ inlineFragment := doc.InlineFragments[inlineFragmentRef]
+ if !inlineFragment.HasSelections || inlineFragment.SelectionSet == ast.InvalidRef {
+ continue
+ }
+ if inlineFragment.TypeCondition.Type == ast.InvalidRef {
+ continue
+ }
+ typeName := doc.InlineFragmentTypeConditionNameString(inlineFragmentRef)
+ inlineFragmentRefsByType[typeName] = append(
+ inlineFragmentRefsByType[typeName],
+ inlineFragmentRef,
+ )
+ }
+
+ if len(inlineFragmentRefsByType) == 0 {
+ return false
+ }
+
+ usedFragmentNames := make(map[string]struct{}, len(doc.FragmentDefinitions))
+ for i := range doc.FragmentDefinitions {
+ usedFragmentNames[doc.FragmentDefinitionNameString(i)] = struct{}{}
+ }
+ for i := range doc.FragmentSpreads {
+ usedFragmentNames[doc.FragmentSpreadNameString(i)] = struct{}{}
+ }
+
+ fragmentSequence := 0
+ changed := false
+
+ typeNames := make([]string, 0, len(inlineFragmentRefsByType))
+ for typeName := range inlineFragmentRefsByType {
+ typeNames = append(typeNames, typeName)
+ }
+ sort.Strings(typeNames)
+
+ for _, typeName := range typeNames {
+ inlineFragmentRefs := inlineFragmentRefsByType[typeName]
+ groups := findEqualSelectionSetGroups(doc, inlineFragmentRefs)
+ for _, group := range groups {
+ if len(group) < 2 {
+ continue
+ }
+
+ fragmentName := nextFragmentName(usedFragmentNames, &fragmentSequence)
+ addFragmentDefinitionForGroup(doc, group, fragmentName)
+ replaceGroupSelectionsWithSpread(doc, group, fragmentName)
+ changed = true
+ }
+ }
+
+ return changed
+}
+
+func findEqualSelectionSetGroups(doc *ast.Document, inlineFragmentRefs []int) [][]int {
+ visited := make([]bool, len(inlineFragmentRefs))
+ groups := make([][]int, 0, len(inlineFragmentRefs)/2)
+
+ for i := range inlineFragmentRefs {
+ if visited[i] {
+ continue
+ }
+ visited[i] = true
+
+ baseRef := inlineFragmentRefs[i]
+ baseSetRef := doc.InlineFragments[baseRef].SelectionSet
+
+ group := []int{baseRef}
+ for j := i + 1; j < len(inlineFragmentRefs); j++ {
+ if visited[j] {
+ continue
+ }
+
+ candidateRef := inlineFragmentRefs[j]
+ candidateSetRef := doc.InlineFragments[candidateRef].SelectionSet
+ if !selectionSetsEqual(doc, baseSetRef, candidateSetRef) {
+ continue
+ }
+
+ visited[j] = true
+ group = append(group, candidateRef)
+ }
+
+ if len(group) > 1 {
+ groups = append(groups, group)
+ }
+ }
+
+ return groups
+}
+
+func selectionSetsEqual(doc *ast.Document, leftSetRef, rightSetRef int) bool {
+ if leftSetRef == rightSetRef {
+ return true
+ }
+
+ leftSelections := doc.SelectionSets[leftSetRef].SelectionRefs
+ rightSelections := doc.SelectionSets[rightSetRef].SelectionRefs
+ if len(leftSelections) != len(rightSelections) {
+ return false
+ }
+
+ for i := range leftSelections {
+ if !selectionsEqual(doc, leftSelections[i], rightSelections[i]) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func selectionsEqual(doc *ast.Document, leftSelectionRef, rightSelectionRef int) bool {
+ leftSelection := doc.Selections[leftSelectionRef]
+ rightSelection := doc.Selections[rightSelectionRef]
+ if leftSelection.Kind != rightSelection.Kind {
+ return false
+ }
+
+ switch leftSelection.Kind {
+ case ast.SelectionKindField:
+ return fieldsEqual(doc, leftSelection.Ref, rightSelection.Ref)
+ case ast.SelectionKindInlineFragment:
+ return inlineFragmentsEqual(doc, leftSelection.Ref, rightSelection.Ref)
+ case ast.SelectionKindFragmentSpread:
+ return fragmentSpreadsEqual(doc, leftSelection.Ref, rightSelection.Ref)
+ default:
+ return false
+ }
+}
+
+func fieldsEqual(doc *ast.Document, leftFieldRef, rightFieldRef int) bool {
+ leftField := doc.Fields[leftFieldRef]
+ rightField := doc.Fields[rightFieldRef]
+
+ if !doc.FieldNameBytes(leftFieldRef).Equals(doc.FieldNameBytes(rightFieldRef)) {
+ return false
+ }
+ if !doc.FieldAliasBytes(leftFieldRef).Equals(doc.FieldAliasBytes(rightFieldRef)) {
+ return false
+ }
+ if !doc.ArgumentSetsAreEquals(leftField.Arguments.Refs, rightField.Arguments.Refs) {
+ return false
+ }
+ if !doc.DirectiveSetsAreEqual(leftField.Directives.Refs, rightField.Directives.Refs) {
+ return false
+ }
+ if leftField.HasSelections != rightField.HasSelections {
+ return false
+ }
+ if !leftField.HasSelections {
+ return true
+ }
+
+ return selectionSetsEqual(doc, leftField.SelectionSet, rightField.SelectionSet)
+}
+
+func inlineFragmentsEqual(doc *ast.Document, leftInlineFragmentRef, rightInlineFragmentRef int) bool {
+ leftInlineFragment := doc.InlineFragments[leftInlineFragmentRef]
+ rightInlineFragment := doc.InlineFragments[rightInlineFragmentRef]
+
+ if leftInlineFragment.TypeCondition.Type != rightInlineFragment.TypeCondition.Type {
+ return false
+ }
+ if !doc.DirectiveSetsAreEqual(leftInlineFragment.Directives.Refs, rightInlineFragment.Directives.Refs) {
+ return false
+ }
+ if leftInlineFragment.HasSelections != rightInlineFragment.HasSelections {
+ return false
+ }
+ if !leftInlineFragment.HasSelections {
+ return true
+ }
+
+ return selectionSetsEqual(doc, leftInlineFragment.SelectionSet, rightInlineFragment.SelectionSet)
+}
+
+func fragmentSpreadsEqual(doc *ast.Document, leftFragmentSpreadRef, rightFragmentSpreadRef int) bool {
+ if !doc.FragmentSpreadNameBytes(leftFragmentSpreadRef).Equals(doc.FragmentSpreadNameBytes(rightFragmentSpreadRef)) {
+ return false
+ }
+ return doc.DirectiveSetsAreEqual(
+ doc.FragmentSpreads[leftFragmentSpreadRef].Directives.Refs,
+ doc.FragmentSpreads[rightFragmentSpreadRef].Directives.Refs,
+ )
+}
+
+func nextFragmentName(usedNames map[string]struct{}, sequence *int) string {
+ for {
+ name := fmt.Sprintf("_wgf%d", *sequence)
+ *sequence = *sequence + 1
+ if _, exists := usedNames[name]; exists {
+ continue
+ }
+ usedNames[name] = struct{}{}
+ return name
+ }
+}
+
+func addFragmentDefinitionForGroup(doc *ast.Document, inlineFragmentRefs []int, fragmentName string) {
+ firstInlineFragment := doc.InlineFragments[inlineFragmentRefs[0]]
+ selectionSetRef := doc.CopySelectionSet(firstInlineFragment.SelectionSet)
+
+ fragmentDefinitionRef := len(doc.FragmentDefinitions)
+ doc.FragmentDefinitions = append(doc.FragmentDefinitions, ast.FragmentDefinition{
+ Name: doc.Input.AppendInputString(fragmentName),
+ TypeCondition: ast.TypeCondition{
+ Type: firstInlineFragment.TypeCondition.Type,
+ },
+ SelectionSet: selectionSetRef,
+ HasSelections: !doc.SelectionSetIsEmpty(selectionSetRef),
+ })
+ doc.RootNodes = append(doc.RootNodes, ast.Node{
+ Kind: ast.NodeKindFragmentDefinition,
+ Ref: fragmentDefinitionRef,
+ })
+}
+
+func replaceGroupSelectionsWithSpread(doc *ast.Document, inlineFragmentRefs []int, fragmentName string) {
+ for _, inlineFragmentRef := range inlineFragmentRefs {
+ selectionSetRef := doc.InlineFragments[inlineFragmentRef].SelectionSet
+ doc.EmptySelectionSet(selectionSetRef)
+
+ fragmentSpreadRef := doc.AddFragmentSpread(ast.FragmentSpread{
+ FragmentName: doc.Input.AppendInputString(fragmentName),
+ })
+ doc.AddSelection(selectionSetRef, ast.Selection{
+ Kind: ast.SelectionKindFragmentSpread,
+ Ref: fragmentSpreadRef,
+ })
+
+ doc.InlineFragments[inlineFragmentRef].HasSelections = true
+ }
+}
diff --git a/app/v2/pkg/astminifier/astminifier_test.go b/app/v2/pkg/astminifier/astminifier_test.go
new file mode 100644
index 0000000..9194229
--- /dev/null
+++ b/app/v2/pkg/astminifier/astminifier_test.go
@@ -0,0 +1,46 @@
+package astminifier
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestMinifySubgraphOperationIfSmaller(t *testing.T) {
+ t.Run("extracts duplicate inline-fragment selection sets", func(t *testing.T) {
+ sharedSelectionSet := `id name username email phone profilePic(size:50){url width height} bestFriend{firstName lastName} friends{count edges{node{id name}}}`
+
+ var builder strings.Builder
+ builder.WriteString("query{")
+ for i := 0; i < 20; i++ {
+ builder.WriteString(fmt.Sprintf("f%d:user{... on User{%s}}", i, sharedSelectionSet))
+ }
+ builder.WriteString("}")
+ operation := []byte(builder.String())
+
+ candidate, changed, err := MinifySubgraphOperation(operation)
+ require.NoError(t, err)
+ require.True(t, changed)
+
+ minified, applied, err := MinifySubgraphOperationIfSmaller(operation)
+ require.NoError(t, err)
+ require.True(t, applied)
+ require.Less(t, len(minified), len(operation))
+ require.Less(t, len(candidate), len(operation))
+
+ minifiedString := string(minified)
+ require.Contains(t, minifiedString, "fragment _wgf0 on User")
+ require.Equal(t, 20, strings.Count(minifiedString, "..._wgf0"))
+ })
+
+ t.Run("keeps original operation when result is not smaller", func(t *testing.T) {
+ operation := []byte(`query{a{... on User{id}}b{... on User{id}}}`)
+
+ minified, applied, err := MinifySubgraphOperationIfSmaller(operation)
+ require.NoError(t, err)
+ require.False(t, applied)
+ require.Equal(t, operation, minified)
+ })
+}
diff --git a/tmp/agent-patch-flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
index d9ea5f5..a9c350c 100644
--- a/tmp/agent-patch-flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
+++ b/app/v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
@@ -16,6 +16,7 @@ import (
"github.com/tidwall/sjson"
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/astminifier"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astnormalization"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astparser"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astprinter"
@@ -1353,7 +1354,17 @@ func (p *Planner[T]) printOperation() []byte {
return nil
}
- return buf.Bytes()
+ printedQuery := bytes.Clone(buf.Bytes())
+ if !p.dataSourcePlannerConfig.EnableOperationMinifier {
+ return printedQuery
+ }
+
+ minified, applied, err := astminifier.MinifySubgraphOperationIfSmaller(printedQuery)
+ if err != nil || !applied {
+ return printedQuery
+ }
+
+ return minified
}
func (p *Planner[T]) stopWithError(msg string, args ...interface{}) {
diff --git a/tmp/agent-patch-flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/configuration.go b/app/v2/pkg/engine/plan/configuration.go
index 6bb384b..bc7df64 100644
--- a/tmp/agent-patch-flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/configuration.go
+++ b/app/v2/pkg/engine/plan/configuration.go
@@ -12,6 +12,9 @@ type Configuration struct {
DataSources []DataSource
Fields FieldConfigurations
Types TypeConfigurations
+ // EnableOperationMinifier enables optional subgraph operation minification.
+ // The minified operation will only be used when it is smaller than the original operation.
+ EnableOperationMinifier bool
// DisableResolveFieldPositions should be set to true for testing purposes
// This setting removes position information from all fields
// In production, this should be set to false so that error messages are easier to understand
diff --git a/tmp/agent-patch-flux-pr-828.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 05b0b5b..1cc741e 100644
--- a/tmp/agent-patch-flux-pr-828.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
@@ -159,11 +159,12 @@ func (d *dataSourceConfiguration[T]) Hash() DSHash {
}
type DataSourcePlannerConfiguration struct {
- RequiredFields FederationFieldConfigurations
- ProvidedFields *NodeSuggestions
- ParentPath string
- PathType PlannerPathType
- IsNested bool
+ RequiredFields FederationFieldConfigurations
+ ProvidedFields *NodeSuggestions
+ ParentPath string
+ PathType PlannerPathType
+ IsNested bool
+ EnableOperationMinifier bool
}
type PlannerPathType int
diff --git a/tmp/agent-patch-flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/planner_configuration.go b/app/v2/pkg/engine/plan/planner_configuration.go
index 0485948..414c3ee 100644
--- a/tmp/agent-patch-flux-pr-828.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/planner_configuration.go
+++ b/app/v2/pkg/engine/plan/planner_configuration.go
@@ -36,11 +36,12 @@ type PlannerConfiguration interface {
func (p *plannerConfiguration[T]) Register(visitor *Visitor) error {
dataSourcePlannerConfig := DataSourcePlannerConfiguration{
- RequiredFields: p.requiredFields,
- ProvidedFields: p.providedFields,
- ParentPath: p.parentPath,
- PathType: p.parentPathType,
- IsNested: p.IsNestedPlanner(),
+ RequiredFields: p.requiredFields,
+ ProvidedFields: p.providedFields,
+ ParentPath: p.parentPath,
+ PathType: p.parentPathType,
+ IsNested: p.IsNestedPlanner(),
+ EnableOperationMinifier: visitor.Config.EnableOperationMinifier,
}
return p.planner.Register(visitor, p.dataSourceConfiguration, dataSourcePlannerConfig)