STET

agent_patch

runs/2026-02-28__13-38-10__gpt-5-1-codex-mini/flux-pr-1128/flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/agent-logs/agent.patch

9509 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/plan/plan.go b/app/pkg/engine/plan/plan.go
index 4725d5a..4a0d415 100644
--- a/tmp/agent-patch-flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/plan/plan.go
+++ b/app/pkg/engine/plan/plan.go
@@ -246,6 +246,7 @@ func NewPlanner(ctx context.Context, config Configuration) *Planner {
 	planningVisitor := &Visitor{
 		Walker:                       &planningWalker,
 		fieldConfigs:                 map[int]*FieldConfiguration{},
+		operationDefinition:          -1,
 		disableResolveFieldPositions: config.DisableResolveFieldPositions,
 	}
 
@@ -449,6 +450,36 @@ func (v *Visitor) currentFullPath() string {
 	return path
 }
 
+func (v *Visitor) isRootField(ref int) bool {
+	return strings.Count(v.currentFullPath(), ".") == 1
+}
+
+func (v *Visitor) rootOperationTypeName() []byte {
+	if v.operationDefinition < 0 || v.operationDefinition >= len(v.Operation.OperationDefinitions) {
+		return nil
+	}
+	operationType := v.Operation.OperationDefinitions[v.operationDefinition].OperationType
+	switch operationType {
+	case ast.OperationTypeQuery:
+		if len(v.Definition.Index.QueryTypeName) != 0 {
+			return v.Definition.Index.QueryTypeName
+		}
+		return ast.DefaultQueryTypeName
+	case ast.OperationTypeMutation:
+		if len(v.Definition.Index.MutationTypeName) != 0 {
+			return v.Definition.Index.MutationTypeName
+		}
+		return ast.DefaultMutationTypeName
+	case ast.OperationTypeSubscription:
+		if len(v.Definition.Index.SubscriptionTypeName) != 0 {
+			return v.Definition.Index.SubscriptionTypeName
+		}
+		return ast.DefaultSubscriptionTypeName
+	default:
+		return nil
+	}
+}
+
 func (v *Visitor) EnterDirective(ref int) {
 	directiveName := v.Operation.DirectiveNameString(ref)
 	ancestor := v.Walker.Ancestors[len(v.Walker.Ancestors)-1]
@@ -527,13 +558,22 @@ func (v *Visitor) EnterField(ref int) {
 	fieldName := v.Operation.FieldNameBytes(ref)
 	fieldAliasOrName := v.Operation.FieldAliasOrNameBytes(ref)
 	if bytes.Equal(fieldName, literal.TYPENAME) {
+		stringNode := &resolve.String{
+			Nullable:   false,
+			IsTypeName: true,
+		}
+		if v.isRootField(ref) {
+			typeName := v.rootOperationTypeName()
+			if typeName == nil {
+				typeName = []byte{}
+			}
+			stringNode.StaticValue = append([]byte{}, typeName...)
+		} else {
+			stringNode.Path = []string{"__typename"}
+		}
 		v.currentField = &resolve.Field{
-			Name: fieldAliasOrName,
-			Value: &resolve.String{
-				Nullable:   false,
-				Path:       []string{"__typename"},
-				IsTypeName: true,
-			},
+			Name:                    fieldAliasOrName,
+			Value:                   stringNode,
 			OnTypeNames:             v.resolveOnTypeNames(),
 			Position:                v.resolveFieldPosition(ref),
 			SkipDirectiveDefined:    skip,
diff --git a/tmp/agent-patch-flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/plan/plan_test.go b/app/pkg/engine/plan/plan_test.go
index d57cad2..8889d32 100644
--- a/tmp/agent-patch-flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/plan/plan_test.go
+++ b/app/pkg/engine/plan/plan_test.go
@@ -208,6 +208,28 @@ func TestPlanner_Plan(t *testing.T) {
 		DefaultFlushIntervalMillis: 0,
 	}))
 
+	t.Run("root typename resolved statically", test(rootTypenameDefinition, `
+		query RootTypeName {
+			__typename
+		}
+	`, "RootTypeName", &SynchronousResponsePlan{
+		Response: &resolve.GraphQLResponse{
+			Data: &resolve.Object{
+				Fields: []*resolve.Field{
+					{
+						Name: []byte("__typename"),
+						Value: &resolve.String{
+							StaticValue: []byte("Query"),
+							IsTypeName:  true,
+						},
+					},
+				},
+			},
+		},
+	}, Configuration{
+		DisableResolveFieldPositions: true,
+	}))
+
 	t.Run("Union response type with interface fragments", test(testDefinition, `
 		query SearchResults {
 			searchResults {
@@ -645,6 +667,17 @@ var expectedMyHeroPlanWithFragment = &SynchronousResponsePlan{
 	},
 }
 
+const rootTypenameDefinition = `
+schema {
+    query: Query
+}
+
+type Query {
+    dummy: String
+}
+
+`
+
 const testDefinition = `
 
 directive @defer on FIELD
diff --git a/tmp/agent-patch-flux-pr-1128.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..ecf3bb0 100644
--- a/tmp/agent-patch-flux-pr-1128.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
@@ -1014,44 +1014,49 @@ func (r *Resolver) resolveString(ctx *Context, str *String, data []byte, stringB
 		err       error
 	)
 
-	value, valueType, _, err = jsonparser.Get(data, str.Path...)
-	if err != nil || valueType != jsonparser.String {
-		if err == nil && str.UnescapeResponseJson {
-			switch valueType {
-			case jsonparser.Object, jsonparser.Array, jsonparser.Boolean, jsonparser.Number, jsonparser.Null:
-				stringBuf.Data.WriteBytes(value)
-				return nil
+	if str.StaticValue != nil {
+		value = str.StaticValue
+	} else {
+
+		value, valueType, _, err = jsonparser.Get(data, str.Path...)
+		if err != nil || valueType != jsonparser.String {
+			if err == nil && str.UnescapeResponseJson {
+				switch valueType {
+				case jsonparser.Object, jsonparser.Array, jsonparser.Boolean, jsonparser.Number, jsonparser.Null:
+					stringBuf.Data.WriteBytes(value)
+					return nil
+				}
 			}
+			if value != nil && valueType != jsonparser.Null {
+				return fmt.Errorf("invalid value type '%s' for path %s, expecting string, got: %v. You can fix this by configuring this field as Int/Float/JSON Scalar", valueType, string(ctx.path()), string(value))
+			}
+			if !str.Nullable {
+				return errNonNullableFieldValueIsNull
+			}
+			r.resolveNull(stringBuf.Data)
+			return nil
 		}
-		if value != nil && valueType != jsonparser.Null {
-			return fmt.Errorf("invalid value type '%s' for path %s, expecting string, got: %v. You can fix this by configuring this field as Int/Float/JSON Scalar", valueType, string(ctx.path()), string(value))
-		}
-		if !str.Nullable {
+
+		if value == nil && !str.Nullable {
 			return errNonNullableFieldValueIsNull
 		}
-		r.resolveNull(stringBuf.Data)
-		return nil
-	}
 
-	if value == nil && !str.Nullable {
-		return errNonNullableFieldValueIsNull
-	}
+		if str.UnescapeResponseJson {
+			value = bytes.ReplaceAll(value, []byte(`\"`), []byte(`"`))
 
-	if str.UnescapeResponseJson {
-		value = bytes.ReplaceAll(value, []byte(`\"`), []byte(`"`))
+			// Do not modify values which was strings
+			// When the original value from upstream response was a plain string value `"hello"`, `"true"`, `"1"`, `"2.0"`,
+			// after getting it via jsonparser.Get we will get unquoted values `hello`, `true`, `1`, `2.0`
+			// which is not string anymore, so we need to quote it again
+			if !(bytes.ContainsAny(value, `{}[]`) && gjson.ValidBytes(value)) {
+				// wrap value in quotes to make it valid json
+				value = append(literal.QUOTE, append(value, literal.QUOTE...)...)
+			}
 
-		// Do not modify values which was strings
-		// When the original value from upstream response was a plain string value `"hello"`, `"true"`, `"1"`, `"2.0"`,
-		// after getting it via jsonparser.Get we will get unquoted values `hello`, `true`, `1`, `2.0`
-		// which is not string anymore, so we need to quote it again
-		if !(bytes.ContainsAny(value, `{}[]`) && gjson.ValidBytes(value)) {
-			// wrap value in quotes to make it valid json
-			value = append(literal.QUOTE, append(value, literal.QUOTE...)...)
+			stringBuf.Data.WriteBytes(value)
+			r.exportField(ctx, str.Export, value)
+			return nil
 		}
-
-		stringBuf.Data.WriteBytes(value)
-		r.exportField(ctx, str.Export, value)
-		return nil
 	}
 
 	value = r.renameTypeName(ctx, str, value)
@@ -1541,6 +1546,7 @@ type FieldExport struct {
 type String struct {
 	Path                 []string
 	Nullable             bool
+	StaticValue          []byte       `json:"static_value,omitempty"`
 	Export               *FieldExport `json:"export,omitempty"`
 	UnescapeResponseJson bool         `json:"unescape_response_json,omitempty"`
 	IsTypeName           bool         `json:"is_type_name,omitempty"`
diff --git a/tmp/agent-patch-flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/resolve/resolve_test.go b/app/pkg/engine/resolve/resolve_test.go
index fbc4a6a..2b7b245 100644
--- a/tmp/agent-patch-flux-pr-1128.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/pkg/engine/resolve/resolve_test.go
+++ b/app/pkg/engine/resolve/resolve_test.go
@@ -2253,6 +2253,21 @@ func TestResolver_ResolveGraphQLResponse(t *testing.T) {
 				},
 			}, `{"data":{"user":{"id":1,"name":"Jannik","__typename":"namespaced_User","aliased":"namespaced_User","rewritten":"namespaced_User"}}}`
 	}))
+	t.Run("root typename static response", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (*GraphQLResponse, Context, string) {
+		return &GraphQLResponse{
+			Data: &Object{
+				Fields: []*Field{
+					{
+						Name: []byte("__typename"),
+						Value: &String{
+							StaticValue: []byte("Query"),
+							IsTypeName:  true,
+						},
+					},
+				},
+			},
+		}, Context{ctx: context.Background()}, `{"data":{"__typename":"Query"}}`
+	}))
 	t.Run("empty graphql response for not nullable query field", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) {
 		return &GraphQLResponse{
 			Data: &Object{