agent_patch
runs/2026-02-28__13-38-10__gpt-5-1-codex-mini/flux-pr-1034/flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/agent-logs/agent.patch
21650 bytes
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/engine/execution_engine.go b/app/execution/engine/execution_engine.go
index 823882f..d081826 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/engine/execution_engine.go
+++ b/app/execution/engine/execution_engine.go
@@ -37,10 +37,11 @@ func newInternalExecutionContext() *internalExecutionContext {
}
}
-func (e *internalExecutionContext) prepare(ctx context.Context, variables []byte, request resolve.Request) {
+func (e *internalExecutionContext) prepare(ctx context.Context, variables []byte, request resolve.Request, variableNameMapping map[string]string) {
e.setContext(ctx)
e.setVariables(variables)
e.setRequest(request)
+ e.setVariableNameMapping(variableNameMapping)
}
func (e *internalExecutionContext) setRequest(request resolve.Request) {
@@ -57,8 +58,13 @@ func (e *internalExecutionContext) setVariables(variables []byte) {
}
}
+func (e *internalExecutionContext) setVariableNameMapping(mapping map[string]string) {
+ e.resolveContext.VariableNameMapping = mapping
+}
+
func (e *internalExecutionContext) reset() {
e.resolveContext.Free()
+ e.resolveContext.VariableNameMapping = nil
}
type ExecutionEngine struct {
@@ -183,10 +189,22 @@ func (e *ExecutionEngine) Execute(ctx context.Context, operation *graphql.Reques
}
}
+ remapResult, err := operation.Normalize(e.config.schema,
+ astnormalization.WithVariableRemapping(),
+ )
+ if err != nil {
+ return err
+ } else if !remapResult.Successful {
+ return remapResult.Errors
+ }
+
+ variableNameMapping := operation.VariableNameMapping()
+
// Validate user-supplied and extracted variables against the operation.
if len(operation.Variables) > 0 && operation.Variables[0] == '{' {
validator := variablesvalidation.NewVariablesValidator(variablesvalidation.VariablesValidatorOptions{
ApolloCompatibilityFlags: e.apolloCompatibilityFlags,
+ VariableNameMapping: variableNameMapping,
})
if err := validator.Validate(operation.Document(), e.config.schema.Document(), operation.Variables); err != nil {
return err
@@ -194,7 +212,7 @@ func (e *ExecutionEngine) Execute(ctx context.Context, operation *graphql.Reques
}
execContext := newInternalExecutionContext()
- execContext.prepare(ctx, operation.Variables, operation.InternalRequest())
+ execContext.prepare(ctx, operation.Variables, operation.InternalRequest(), variableNameMapping)
for i := range options {
options[i](execContext)
}
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/graphql/normalization.go b/app/execution/graphql/normalization.go
index 62253b0..f938ec3 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/graphql/normalization.go
+++ b/app/execution/graphql/normalization.go
@@ -22,6 +22,7 @@ func (r *Request) Normalize(schema *Schema, options ...astnormalization.Option)
}
r.document.Input.Variables = r.Variables
+ r.variableNameMapping = nil
// use default normalization options if none are provided
if len(options) == 0 {
@@ -30,6 +31,7 @@ func (r *Request) Normalize(schema *Schema, options ...astnormalization.Option)
astnormalization.WithRemoveFragmentDefinitions(),
astnormalization.WithRemoveUnusedVariables(),
astnormalization.WithInlineFragmentSpreads(),
+ astnormalization.WithVariableRemapping(),
}
}
@@ -51,6 +53,7 @@ func (r *Request) Normalize(schema *Schema, options ...astnormalization.Option)
r.isNormalized = true
r.Variables = r.document.Input.Variables
+ r.variableNameMapping = normalizer.VariableNameMapping().CanonicalToOriginal
return NormalizationResult{Successful: true, Errors: nil}, nil
}
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/graphql/request.go b/app/execution/graphql/request.go
index 1e10748..c324786 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/graphql/request.go
+++ b/app/execution/graphql/request.go
@@ -37,14 +37,19 @@ type Request struct {
Variables json.RawMessage `json:"variables,omitempty"`
Query string `json:"query"`
- document ast.Document
- isParsed bool
- isNormalized bool
- request resolve.Request
+ document ast.Document
+ isParsed bool
+ isNormalized bool
+ request resolve.Request
+ variableNameMapping map[string]string
validForSchema map[uint64]ValidationResult
}
+func (r *Request) VariableNameMapping() map[string]string {
+ return r.variableNameMapping
+}
+
func UnmarshalRequest(reader io.Reader, request *Request) error {
requestBytes, err := io.ReadAll(reader)
if err != nil {
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/astnormalization/astnormalization.go b/app/pkg/astnormalization/astnormalization.go
index 7cb6e18..e17ed16 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/astnormalization/astnormalization.go
+++ b/app/pkg/astnormalization/astnormalization.go
@@ -89,10 +89,11 @@ func NormalizeNamedOperation(operation, definition *ast.Document, operationName
// OperationNormalizer walks a given AST and applies all registered rules
type OperationNormalizer struct {
- operationWalkers []*astvisitor.Walker
- variablesExtraction *variablesExtractionVisitor
- options options
- definitionNormalizer *DefinitionNormalizer
+ operationWalkers []*astvisitor.Walker
+ variablesExtraction *variablesExtractionVisitor
+ options options
+ definitionNormalizer *DefinitionNormalizer
+ variableRemappingVisitor *variablesRemappingVisitor
}
// NewNormalizer creates a new OperationNormalizer and sets up all default rules
@@ -130,6 +131,7 @@ type options struct {
extractVariables bool
removeUnusedVariables bool
normalizeDefinition bool
+ remapVariables bool
}
type Option func(options *options)
@@ -158,6 +160,12 @@ func WithNormalizeDefinition() Option {
}
}
+func WithVariableRemapping() Option {
+ return func(options *options) {
+ options.remapVariables = true
+ }
+}
+
func (o *OperationNormalizer) setupOperationWalkers() {
o.operationWalkers = make([]*astvisitor.Walker, 0, 4)
@@ -194,6 +202,19 @@ func (o *OperationNormalizer) setupOperationWalkers() {
o.operationWalkers = append(o.operationWalkers, &variablesProcessing)
}
+
+ if o.options.remapVariables {
+ remapWalker := astvisitor.NewWalker(48)
+ o.variableRemappingVisitor = remapVariables(&remapWalker)
+ o.operationWalkers = append(o.operationWalkers, &remapWalker)
+ }
+}
+
+func (o *OperationNormalizer) VariableNameMapping() VariableNamesMapping {
+ if o.variableRemappingVisitor == nil {
+ return VariableNamesMapping{}
+ }
+ return o.variableRemappingVisitor.Mapping()
}
func (o *OperationNormalizer) prepareDefinition(definition *ast.Document, report *operationreport.Report) {
diff --git a/app/pkg/astnormalization/variables_remapping.go b/app/pkg/astnormalization/variables_remapping.go
new file mode 100644
index 0000000..dab1338
--- /dev/null
+++ b/app/pkg/astnormalization/variables_remapping.go
@@ -0,0 +1,111 @@
+package astnormalization
+
+import (
+ "strconv"
+
+ "github.com/buger/jsonparser"
+ "github.com/tidwall/sjson"
+
+ "github.com/wundergraph/graphql-go-tools/pkg/ast"
+ "github.com/wundergraph/graphql-go-tools/pkg/astvisitor"
+)
+
+// VariableNamesMapping tracks the mapping between original variable names and their
+// canonical normalized counterparts.
+type VariableNamesMapping struct {
+ CanonicalToOriginal map[string]string
+ OriginalToCanonical map[string]string
+}
+
+type variablesRemappingVisitor struct {
+ *astvisitor.Walker
+ operation *ast.Document
+ mapping VariableNamesMapping
+ operationCounter map[int]int
+}
+
+func remapVariables(walker *astvisitor.Walker) *variablesRemappingVisitor {
+ visitor := &variablesRemappingVisitor{
+ Walker: walker,
+ }
+ walker.RegisterEnterDocumentVisitor(visitor)
+ walker.RegisterEnterOperationVisitor(visitor)
+ walker.RegisterEnterVariableDefinitionVisitor(visitor)
+ return visitor
+}
+
+func (v *variablesRemappingVisitor) EnterDocument(operation, definition *ast.Document) {
+ v.operation = operation
+ v.mapping = VariableNamesMapping{
+ CanonicalToOriginal: make(map[string]string),
+ OriginalToCanonical: make(map[string]string),
+ }
+ v.operationCounter = make(map[int]int)
+}
+
+func (v *variablesRemappingVisitor) EnterOperationDefinition(ref int) {
+ if v.operationCounter == nil {
+ v.operationCounter = make(map[int]int)
+ }
+ v.operationCounter[ref] = 0
+}
+
+func (v *variablesRemappingVisitor) EnterVariableDefinition(ref int) {
+ if v.operation == nil {
+ return
+ }
+ if len(v.Ancestors) == 0 || v.Ancestors[0].Kind != ast.NodeKindOperationDefinition {
+ return
+ }
+
+ operationRef := v.Ancestors[0].Ref
+ index := v.operationCounter[operationRef]
+ canonical := canonicalVariableName(index)
+ v.operationCounter[operationRef] = index + 1
+
+ variableValueRef := v.operation.VariableDefinitions[ref].VariableValue.Ref
+ oldName := v.operation.VariableValueNameString(variableValueRef)
+
+ canonicalBytes := []byte(canonical)
+ v.operation.VariableValues[variableValueRef].Name = v.operation.Input.AppendInputBytes(canonicalBytes)
+ v.renameInputVariable(oldName, canonical)
+
+ v.mapping.CanonicalToOriginal[canonical] = oldName
+ v.mapping.OriginalToCanonical[oldName] = canonical
+}
+
+func (v *variablesRemappingVisitor) Mapping() VariableNamesMapping {
+ return v.mapping
+}
+
+func (v *variablesRemappingVisitor) renameInputVariable(oldName, canonical string) {
+ if oldName == canonical {
+ return
+ }
+ value, _, _, err := jsonparser.Get(v.operation.Input.Variables, oldName)
+ if err != nil {
+ if err == jsonparser.KeyPathNotFoundError {
+ return
+ }
+ v.StopWithInternalErr(err)
+ return
+ }
+
+ variablesStr, err := sjson.Delete(string(v.operation.Input.Variables), oldName)
+ if err != nil {
+ v.StopWithInternalErr(err)
+ return
+ }
+
+ variables, err := sjson.SetRawBytes([]byte(variablesStr), canonical, value)
+ if err != nil {
+ v.StopWithInternalErr(err)
+ return
+ }
+
+ v.operation.Input.Variables = variables
+}
+
+func canonicalVariableName(index int) string {
+ return "v" + strconv.Itoa(index+1)
+}
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/resolve/resolve.go b/app/pkg/engine/resolve/resolve.go
index f6b93a0..6f80737 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/resolve/resolve.go
+++ b/app/pkg/engine/resolve/resolve.go
@@ -117,22 +117,23 @@ type AfterFetchHook interface {
}
type Context struct {
- ctx context.Context
- Variables []byte
- Request Request
- pathElements [][]byte
- responseElements []string
- lastFetchID int
- patches []patch
- usedBuffers []*bytes.Buffer
- currentPatch int
- maxPatch int
- pathPrefix []byte
- dataLoader *dataLoader
- beforeFetchHook BeforeFetchHook
- afterFetchHook AfterFetchHook
- position Position
- RenameTypeNames []RenameTypeName
+ ctx context.Context
+ Variables []byte
+ Request Request
+ VariableNameMapping map[string]string
+ pathElements [][]byte
+ responseElements []string
+ lastFetchID int
+ patches []patch
+ usedBuffers []*bytes.Buffer
+ currentPatch int
+ maxPatch int
+ pathPrefix []byte
+ dataLoader *dataLoader
+ beforeFetchHook BeforeFetchHook
+ afterFetchHook AfterFetchHook
+ position Position
+ RenameTypeNames []RenameTypeName
}
type Request struct {
@@ -192,19 +193,28 @@ func (c *Context) clone() Context {
copy(patches[i].extraPath, c.patches[i].extraPath)
copy(patches[i].data, c.patches[i].data)
}
+ var mapping map[string]string
+ if len(c.VariableNameMapping) > 0 {
+ mapping = make(map[string]string, len(c.VariableNameMapping))
+ for k, v := range c.VariableNameMapping {
+ mapping[k] = v
+ }
+ }
+
return Context{
- ctx: c.ctx,
- Variables: variables,
- Request: c.Request,
- pathElements: pathElements,
- patches: patches,
- usedBuffers: make([]*bytes.Buffer, 0, 48),
- currentPatch: c.currentPatch,
- maxPatch: c.maxPatch,
- pathPrefix: pathPrefix,
- beforeFetchHook: c.beforeFetchHook,
- afterFetchHook: c.afterFetchHook,
- position: c.position,
+ ctx: c.ctx,
+ Variables: variables,
+ Request: c.Request,
+ VariableNameMapping: mapping,
+ pathElements: pathElements,
+ patches: patches,
+ usedBuffers: make([]*bytes.Buffer, 0, 48),
+ currentPatch: c.currentPatch,
+ maxPatch: c.maxPatch,
+ pathPrefix: pathPrefix,
+ beforeFetchHook: c.beforeFetchHook,
+ afterFetchHook: c.afterFetchHook,
+ position: c.position,
}
}
@@ -226,6 +236,7 @@ func (c *Context) Free() {
c.position = Position{}
c.dataLoader = nil
c.RenameTypeNames = nil
+ c.VariableNameMapping = nil
}
func (c *Context) SetBeforeFetchHook(hook BeforeFetchHook) {
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/graphql/execution_engine_v2.go b/app/pkg/graphql/execution_engine_v2.go
index 8ca7f3b..f2eba25 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/graphql/execution_engine_v2.go
+++ b/app/pkg/graphql/execution_engine_v2.go
@@ -117,10 +117,11 @@ func newInternalExecutionContext() *internalExecutionContext {
}
}
-func (e *internalExecutionContext) prepare(ctx context.Context, variables []byte, request resolve.Request) {
+func (e *internalExecutionContext) prepare(ctx context.Context, variables []byte, request resolve.Request, variableNameMapping map[string]string) {
e.setContext(ctx)
e.setVariables(variables)
e.setRequest(request)
+ e.setVariableNameMapping(variableNameMapping)
}
func (e *internalExecutionContext) setRequest(request resolve.Request) {
@@ -137,6 +138,11 @@ func (e *internalExecutionContext) setVariables(variables []byte) {
func (e *internalExecutionContext) reset() {
e.resolveContext.Free()
+ e.resolveContext.VariableNameMapping = nil
+}
+
+func (e *internalExecutionContext) setVariableNameMapping(mapping map[string]string) {
+ e.resolveContext.VariableNameMapping = mapping
}
type ExecutionEngineV2 struct {
@@ -248,6 +254,18 @@ func (e *ExecutionEngineV2) Execute(ctx context.Context, operation *Request, wri
}
}
+ remapResult, err := operation.Normalize(e.config.schema,
+ astnormalization.WithVariableRemapping(),
+ )
+ if err != nil {
+ return err
+ }
+ if !remapResult.Successful {
+ return remapResult.Errors
+ }
+
+ variableNameMapping := operation.VariableNameMapping()
+
result, err := operation.ValidateForSchema(e.config.schema)
if err != nil {
return err
@@ -259,7 +277,7 @@ func (e *ExecutionEngineV2) Execute(ctx context.Context, operation *Request, wri
execContext := e.getExecutionCtx()
defer e.putExecutionCtx(execContext)
- execContext.prepare(ctx, operation.Variables, operation.request)
+ execContext.prepare(ctx, operation.Variables, operation.request, variableNameMapping)
for i := range options {
options[i](execContext)
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/graphql/normalization_test.go b/app/pkg/graphql/normalization_test.go
index 10db22e..0e608ee 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/graphql/normalization_test.go
+++ b/app/pkg/graphql/normalization_test.go
@@ -84,6 +84,28 @@ func TestRequest_Normalize(t *testing.T) {
}`)
})
+ t.Run("should remap variables to canonical names and record the mapping", func(t *testing.T) {
+ schema := starwarsSchema(t)
+ request := Request{
+ Query: `query Foo($userId: ID!, $status: String) {
+ droid(id: $userId) {
+ name
+ }
+ search(text: $status) {
+ ... on Droid {
+ name
+ }
+ }
+ }`,
+ Variables: []byte(`{"userId":"R2D2","status":"ACTIVE"}`),
+ }
+ result, err := request.Normalize(schema)
+ require.NoError(t, err)
+ assert.True(t, result.Successful)
+ assert.Equal(t, `{"v1":"R2D2","v2":"ACTIVE"}`, string(request.document.Input.Variables))
+ assert.Equal(t, map[string]string{"v1": "userId", "v2": "status"}, request.VariableNameMapping())
+ })
+
t.Run("should successfully normalize query and remove unused variables", func(t *testing.T) {
request := Request{
OperationName: "MySearch",
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/variablesvalidation/variablesvalidation.go b/app/v2/pkg/variablesvalidation/variablesvalidation.go
index 6410033..9921cb5 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/variablesvalidation/variablesvalidation.go
+++ b/app/v2/pkg/variablesvalidation/variablesvalidation.go
@@ -41,6 +41,7 @@ func (v *variablesVisitor) invalidEnumValueIfAllowed(variableContent string) str
}
func (v *variablesVisitor) invalidValueMessage(variableName, variableContent string) string {
+ variableName = v.variableNameStringForDisplay(variableName)
if v.opts.DisableExposingVariablesContent {
return fmt.Sprintf(`Variable "$%s" got invalid value`, variableName)
}
@@ -66,13 +67,15 @@ type VariablesValidator struct {
type VariablesValidatorOptions struct {
ApolloCompatibilityFlags apollocompatibility.Flags
DisableExposingVariablesContent bool
+ VariableNameMapping map[string]string
}
func NewVariablesValidator(options VariablesValidatorOptions) *VariablesValidator {
walker := astvisitor.NewWalker(8)
visitor := &variablesVisitor{
- walker: &walker,
- opts: options,
+ walker: &walker,
+ opts: options,
+ variableNameMapping: options.VariableNameMapping,
}
walker.RegisterEnterVariableDefinitionVisitor(visitor)
return &VariablesValidator{
@@ -106,6 +109,7 @@ type variablesVisitor struct {
currentVariableValue *astjson.Value
path []pathItem
opts VariablesValidatorOptions
+ variableNameMapping map[string]string
}
func (v *variablesVisitor) renderPath() string {
@@ -215,7 +219,8 @@ func (v *variablesVisitor) renderVariableRequiredError(variableName []byte, type
v.err = err
return
}
- v.err = v.newInvalidVariableError(fmt.Sprintf(`Variable "$%s" of required type "%s" was not provided.`, string(variableName), out.String()))
+ variableDisplayName := v.variableNameForDisplay(variableName)
+ v.err = v.newInvalidVariableError(fmt.Sprintf(`Variable "$%s" of required type "%s" was not provided.`, variableDisplayName, out.String()))
}
func (v *variablesVisitor) renderVariableInvalidObjectTypeError(typeName []byte, variablesNode *astjson.Value) {
@@ -294,7 +299,22 @@ func (v *variablesVisitor) renderVariableInvalidNullError(variableName []byte, t
return
}
typeName := buf.String()
- v.err = v.newInvalidVariableError(fmt.Sprintf(`Variable "$%s" got invalid value null; Expected non-nullable type "%s" not to be null.`, string(variableName), typeName))
+ variableDisplayName := v.variableNameForDisplay(variableName)
+ v.err = v.newInvalidVariableError(fmt.Sprintf(`Variable "$%s" got invalid value null; Expected non-nullable type "%s" not to be null.`, variableDisplayName, typeName))
+}
+
+func (v *variablesVisitor) variableNameForDisplay(name []byte) string {
+ return v.variableNameStringForDisplay(string(name))
+}
+
+func (v *variablesVisitor) variableNameStringForDisplay(name string) string {
+ if v.variableNameMapping == nil {
+ return name
+ }
+ if mapped, ok := v.variableNameMapping[name]; ok {
+ return mapped
+ }
+ return name
}
func (v *variablesVisitor) traverseFieldDefinitionType(fieldTypeDefinitionNodeKind ast.NodeKind, fieldName ast.ByteSlice, jsonValue *astjson.Value, typeRef, inputFieldRef int) {
diff --git a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/variablesvalidation/variablesvalidation_test.go b/app/v2/pkg/variablesvalidation/variablesvalidation_test.go
index 41a911f..555959e 100644
--- a/tmp/agent-patch-flux-pr-1034.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/variablesvalidation/variablesvalidation_test.go
+++ b/app/v2/pkg/variablesvalidation/variablesvalidation_test.go
@@ -29,6 +29,20 @@ func TestVariablesValidation(t *testing.T) {
assert.Equal(t, `Variable "$bar" of required type "String!" was not provided.`, err.Error())
})
+ t.Run("maps canonical variable names back to original in errors", func(t *testing.T) {
+ tc := testCase{
+ schema: `type Query { hello(id: ID!): String }`,
+ operation: `query Foo($v1: ID!) { hello(id: $v1) }`,
+ variables: `{"v1": null}`,
+ }
+ opts := VariablesValidatorOptions{
+ VariableNameMapping: map[string]string{"v1": "userId"},
+ }
+ err := runTestWithOptions(t, tc, opts)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `"$userId"`)
+ })
+
t.Run("a missing required input produces an error", func(t *testing.T) {
tc := testCase{
schema: inputSchema,