agent_patch
runs/2026-02-21__03-36-16__gpt-5-1-codex-mini/flux-pr-1034/flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/agent-logs/agent.patch
15239 bytes
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/execution/graphql/normalization.go b/app/execution/graphql/normalization.go
index 62253b0..ff20a18 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/execution/graphql/normalization.go
+++ b/app/execution/graphql/normalization.go
@@ -33,16 +33,19 @@ func (r *Request) Normalize(schema *Schema, options ...astnormalization.Option)
}
}
+ options = append(options, astnormalization.WithCanonicalVariableNames())
+
+ var normalizer *astnormalization.OperationNormalizer
if r.OperationName != "" {
- options = append(options, astnormalization.WithRemoveNotMatchingOperationDefinitions())
- normalizer := astnormalization.NewWithOpts(options...)
+ normalizer = astnormalization.NewWithOpts(options...)
normalizer.NormalizeNamedOperation(&r.document, &schema.document, []byte(r.OperationName), &report)
} else {
// TODO: we should validate count of operations - to throw an error
// and do full normalization for the single anonymous operation
- normalizer := astnormalization.NewWithOpts(options...)
+ normalizer = astnormalization.NewWithOpts(options...)
normalizer.NormalizeOperation(&r.document, &schema.document, &report)
}
+ r.variableNameMapping = normalizer.VariableNameMapping()
if report.HasErrors() {
return NormalizationResultFromReport(report)
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/execution/graphql/request.go b/app/execution/graphql/request.go
index 1e10748..594bbce 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/execution/graphql/request.go
+++ b/app/execution/graphql/request.go
@@ -42,7 +42,8 @@ type Request struct {
isNormalized bool
request resolve.Request
- validForSchema map[uint64]ValidationResult
+ validForSchema map[uint64]ValidationResult
+ variableNameMapping map[string]string
}
func UnmarshalRequest(reader io.Reader, request *Request) error {
@@ -105,6 +106,17 @@ func (r *Request) IsNormalized() bool {
return r.isNormalized
}
+func (r *Request) VariableNameMapping() map[string]string {
+ if len(r.variableNameMapping) == 0 {
+ return nil
+ }
+ mapping := make(map[string]string, len(r.variableNameMapping))
+ for canonical, original := range r.variableNameMapping {
+ mapping[canonical] = original
+ }
+ return mapping
+}
+
func (r *Request) parseQueryOnce() (report operationreport.Report) {
if r.isParsed {
return report
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/astnormalization/astnormalization.go b/app/pkg/astnormalization/astnormalization.go
index 7cb6e18..288f753 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/astnormalization/astnormalization.go
+++ b/app/pkg/astnormalization/astnormalization.go
@@ -91,6 +91,7 @@ func NormalizeNamedOperation(operation, definition *ast.Document, operationName
type OperationNormalizer struct {
operationWalkers []*astvisitor.Walker
variablesExtraction *variablesExtractionVisitor
+ variableMapper *variableMapperVisitor
options options
definitionNormalizer *DefinitionNormalizer
}
@@ -130,6 +131,7 @@ type options struct {
extractVariables bool
removeUnusedVariables bool
normalizeDefinition bool
+ canonicalizeVariables bool
}
type Option func(options *options)
@@ -158,6 +160,12 @@ func WithNormalizeDefinition() Option {
}
}
+func WithCanonicalVariableNames() Option {
+ return func(options *options) {
+ options.canonicalizeVariables = true
+ }
+}
+
func (o *OperationNormalizer) setupOperationWalkers() {
o.operationWalkers = make([]*astvisitor.Walker, 0, 4)
@@ -194,6 +202,12 @@ func (o *OperationNormalizer) setupOperationWalkers() {
o.operationWalkers = append(o.operationWalkers, &variablesProcessing)
}
+
+ if o.options.canonicalizeVariables {
+ canonicalWalker := astvisitor.NewWalker(48)
+ o.variableMapper = canonicalizeVariables(&canonicalWalker)
+ o.operationWalkers = append(o.operationWalkers, &canonicalWalker)
+ }
}
func (o *OperationNormalizer) prepareDefinition(definition *ast.Document, report *operationreport.Report) {
@@ -231,6 +245,9 @@ func (o *OperationNormalizer) NormalizeNamedOperation(operation, definition *ast
if o.variablesExtraction != nil {
o.variablesExtraction.operationName = operationName
}
+ if o.variableMapper != nil {
+ o.variableMapper.operationName = operationName
+ }
for i := range o.operationWalkers {
o.operationWalkers[i].Walk(operation, definition, report)
if report.HasErrors() {
@@ -238,3 +255,10 @@ func (o *OperationNormalizer) NormalizeNamedOperation(operation, definition *ast
}
}
}
+
+func (o *OperationNormalizer) VariableNameMapping() map[string]string {
+ if o.variableMapper == nil {
+ return nil
+ }
+ return o.variableMapper.Mapping()
+}
diff --git a/app/pkg/astnormalization/variable_mapper.go b/app/pkg/astnormalization/variable_mapper.go
new file mode 100644
index 0000000..c6e017c
--- /dev/null
+++ b/app/pkg/astnormalization/variable_mapper.go
@@ -0,0 +1,192 @@
+package astnormalization
+
+import (
+ "bytes"
+ "encoding/json"
+ "sort"
+ "strconv"
+
+ "github.com/wundergraph/graphql-go-tools/pkg/ast"
+ "github.com/wundergraph/graphql-go-tools/pkg/astvisitor"
+)
+
+func canonicalizeVariables(walker *astvisitor.Walker) *variableMapperVisitor {
+ visitor := &variableMapperVisitor{
+ Walker: walker,
+ }
+ walker.RegisterEnterDocumentVisitor(visitor)
+ walker.RegisterLeaveDocumentVisitor(visitor)
+ walker.RegisterOperationDefinitionVisitor(visitor)
+ walker.RegisterEnterArgumentVisitor(visitor)
+ return visitor
+}
+
+type variableMapperVisitor struct {
+ *astvisitor.Walker
+ operation *ast.Document
+ definition *ast.Document
+ operationName []byte
+ skip bool
+ seen map[int]struct{}
+ canonicalCounter int
+ canonicalOrder []string
+ canonicalToOriginal map[string]string
+ mapping map[string]string
+}
+
+func (v *variableMapperVisitor) EnterDocument(operation, definition *ast.Document) {
+ v.operation = operation
+ v.definition = definition
+ v.seen = map[int]struct{}{}
+ v.canonicalCounter = 0
+ v.canonicalOrder = v.canonicalOrder[:0]
+ v.canonicalToOriginal = map[string]string{}
+ v.mapping = nil
+ v.skip = false
+}
+
+func (v *variableMapperVisitor) LeaveDocument(operation, definition *ast.Document) {
+ if len(v.canonicalOrder) == 0 {
+ v.mapping = nil
+ return
+ }
+
+ v.rebuildVariablesJSON()
+
+ v.mapping = make(map[string]string, len(v.canonicalToOriginal))
+ for canonical, original := range v.canonicalToOriginal {
+ v.mapping[canonical] = original
+ }
+}
+
+func (v *variableMapperVisitor) EnterOperationDefinition(ref int) {
+ if len(v.operationName) == 0 {
+ v.skip = false
+ return
+ }
+ name := v.operation.OperationDefinitionNameBytes(ref)
+ v.skip = !bytes.Equal(name, v.operationName)
+}
+
+func (v *variableMapperVisitor) LeaveOperationDefinition(ref int) {
+ v.skip = false
+}
+
+func (v *variableMapperVisitor) EnterArgument(ref int) {
+ if v.skip {
+ return
+ }
+ v.traverseValue(v.operation.Arguments[ref].Value)
+}
+
+func (v *variableMapperVisitor) traverseValue(value ast.Value) {
+ switch value.Kind {
+ case ast.ValueKindVariable:
+ v.mapVariable(value.Ref)
+ case ast.ValueKindList:
+ for _, ref := range v.operation.ListValues[value.Ref].Refs {
+ listValue := v.operation.Value(ref)
+ v.traverseValue(listValue)
+ }
+ case ast.ValueKindObject:
+ for _, ref := range v.operation.ObjectValues[value.Ref].Refs {
+ v.traverseValue(v.operation.ObjectField(ref).Value)
+ }
+ }
+}
+
+func (v *variableMapperVisitor) mapVariable(ref int) {
+ if _, ok := v.seen[ref]; ok {
+ return
+ }
+ v.seen[ref] = struct{}{}
+
+ canonical := "v" + strconv.Itoa(v.canonicalCounter)
+ v.canonicalCounter++
+
+ original := v.operation.VariableValueNameString(ref)
+ v.operation.VariableValues[ref].Name = v.operation.Input.AppendInputBytes([]byte(canonical))
+
+ v.canonicalOrder = append(v.canonicalOrder, canonical)
+ v.canonicalToOriginal[canonical] = original
+}
+
+func (v *variableMapperVisitor) rebuildVariablesJSON() {
+ if len(v.operation.Input.Variables) == 0 {
+ return
+ }
+
+ var values map[string]json.RawMessage
+ if err := json.Unmarshal(v.operation.Input.Variables, &values); err != nil {
+ return
+ }
+
+ entries := make([]variableEntry, 0, len(values))
+
+ for _, canonical := range v.canonicalOrder {
+ original, ok := v.canonicalToOriginal[canonical]
+ if !ok {
+ continue
+ }
+ value, ok := values[original]
+ if !ok {
+ continue
+ }
+ entries = append(entries, variableEntry{
+ Name: canonical,
+ Value: append([]byte{}, value...),
+ })
+ delete(values, original)
+ }
+
+ if len(values) > 0 {
+ remaining := make([]string, 0, len(values))
+ for key := range values {
+ remaining = append(remaining, key)
+ }
+ sort.Strings(remaining)
+ for _, key := range remaining {
+ entries = append(entries, variableEntry{
+ Name: key,
+ Value: append([]byte{}, values[key]...),
+ })
+ }
+ }
+
+ if len(entries) == 0 {
+ return
+ }
+
+ v.operation.Input.Variables = encodeVariables(entries)
+}
+
+func (v *variableMapperVisitor) Mapping() map[string]string {
+ if len(v.mapping) == 0 {
+ return nil
+ }
+ mapping := make(map[string]string, len(v.mapping))
+ for canonical, original := range v.mapping {
+ mapping[canonical] = original
+ }
+ return mapping
+}
+
+type variableEntry struct {
+ Name string
+ Value []byte
+}
+
+func encodeVariables(entries []variableEntry) []byte {
+ buf := bytes.Buffer{}
+ buf.WriteByte('{')
+ for i, entry := range entries {
+ if i > 0 {
+ buf.WriteByte(',')
+ }
+ buf.WriteString(strconv.Quote(entry.Name))
+ buf.WriteByte(':')
+ buf.Write(entry.Value)
+ }
+ buf.WriteByte('}')
+ return buf.Bytes()
+}
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/execution/handler.go b/app/pkg/execution/handler.go
index 5bcc331..838fb22 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/execution/handler.go
+++ b/app/pkg/execution/handler.go
@@ -71,7 +71,13 @@ func (h *Handler) Handle(requestData, extraVariables []byte) (executor *Executor
err = report
return
}
- normalizer := astnormalization.NewNormalizer(true, true)
+ options := []astnormalization.Option{
+ astnormalization.WithExtractVariables(),
+ astnormalization.WithRemoveFragmentDefinitions(),
+ astnormalization.WithRemoveUnusedVariables(),
+ astnormalization.WithCanonicalVariableNames(),
+ }
+ normalizer := astnormalization.NewWithOpts(options...)
normalizer.NormalizeOperation(&operationDocument, h.base.Definition, &report)
if report.HasErrors() {
err = report
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/graphql/normalization.go b/app/pkg/graphql/normalization.go
index 55e8f89..0f2a60a 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/graphql/normalization.go
+++ b/app/pkg/graphql/normalization.go
@@ -24,17 +24,22 @@ func (r *Request) Normalize(schema *Schema) (result NormalizationResult, err err
r.document.Input.Variables = r.Variables
- normalizer := astnormalization.NewWithOpts(
+ options := []astnormalization.Option{
astnormalization.WithExtractVariables(),
astnormalization.WithRemoveFragmentDefinitions(),
astnormalization.WithRemoveUnusedVariables(),
- )
+ astnormalization.WithCanonicalVariableNames(),
+ }
+ var normalizer *astnormalization.OperationNormalizer
if r.OperationName != "" {
+ normalizer = astnormalization.NewWithOpts(options...)
normalizer.NormalizeNamedOperation(&r.document, &schema.document, []byte(r.OperationName), &report)
} else {
+ normalizer = astnormalization.NewWithOpts(options...)
normalizer.NormalizeOperation(&r.document, &schema.document, &report)
}
+ r.variableNameMapping = normalizer.VariableNameMapping()
if report.HasErrors() {
return normalizationResultFromReport(report)
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/graphql/normalization_test.go b/app/pkg/graphql/normalization_test.go
index 10db22e..14c8c08 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/graphql/normalization_test.go
+++ b/app/pkg/graphql/normalization_test.go
@@ -38,11 +38,11 @@ func TestRequest_Normalize(t *testing.T) {
assert.True(t, result.Successful)
assert.True(t, request.isNormalized)
- normalizedOperation := `query Fragments($droidID: ID!){
+ normalizedOperation := `query Fragments($v0: ID!){
hero {
name
}
- droid(id: $droidID){
+ droid(id: $v0){
name
}
}`
@@ -77,8 +77,8 @@ func TestRequest_Normalize(t *testing.T) {
t.Run("should successfully normalize single query with arguments", func(t *testing.T) {
request := requestForQuery(t, starwars.FileDroidWithArgQuery)
- runNormalization(t, &request, `{"a":"R2D2"}`, `query($a: ID!){
- droid(id: $a){
+ runNormalization(t, &request, `{"v0":"R2D2"}`, `query($v0: ID!){
+ droid(id: $v0){
name
}
}`)
@@ -94,8 +94,8 @@ func TestRequest_Normalize(t *testing.T) {
Query: `query MySearch($s: String!, $other: String) {search(name: $s) {...on Human {name}}}`,
}
- runNormalization(t, &request, `{"s":"Luke"}`, `query MySearch($s: String!){
- search(name: $s){
+ runNormalization(t, &request, `{"v0":"Luke"}`, `query MySearch($v0: String!){
+ search(name: $v0){
... on Human {
name
}
@@ -138,7 +138,7 @@ func TestRequest_Normalize(t *testing.T) {
Query: `query MySearch($s: String!, $s2: String, $s3: String) {search(name: $s) {...on Human {name}}}`,
},
} {
- runNormalization(t, &v, `{"s":"Luke"}`, expectedVar)
+ runNormalization(t, &v, `{"v0":"Luke"}`, expectedVar)
}
})
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/graphql/request.go b/app/pkg/graphql/request.go
index 2c47e20..8c2a55e 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-03-05__17-48-26__gpt-5-1-codex-mini/app/pkg/graphql/request.go
+++ b/app/pkg/graphql/request.go
@@ -42,7 +42,8 @@ type Request struct {
isNormalized bool
request resolve.Request
- validForSchema map[uint64]ValidationResult
+ validForSchema map[uint64]ValidationResult
+ variableNameMapping map[string]string
}
func UnmarshalRequest(reader io.Reader, request *Request) error {
@@ -97,6 +98,17 @@ func (r *Request) IsNormalized() bool {
return r.isNormalized
}
+func (r *Request) VariableNameMapping() map[string]string {
+ if len(r.variableNameMapping) == 0 {
+ return nil
+ }
+ mapping := make(map[string]string, len(r.variableNameMapping))
+ for canonical, original := range r.variableNameMapping {
+ mapping[canonical] = original
+ }
+ return mapping
+}
+
func (r *Request) parseQueryOnce() (report operationreport.Report) {
if r.isParsed {
return report