STET

agent_patch

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

18813 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/authorization_test.go b/app/v2/pkg/engine/resolve/authorization_test.go
index 263724a..5667905 100644
--- a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/authorization_test.go
+++ b/app/v2/pkg/engine/resolve/authorization_test.go
@@ -72,7 +72,7 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(2), authorizer.(*testAuthorizer).preFetchCalls.Load())
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
-				require.Nil(t, resolveCtx.subgraphErrors)
+				require.Nil(t, resolveCtx.SubgraphErrors())
 			}
 	}))
 	t.Run("validate authorizer args", testFnWithPostEvaluation(func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx *Context, expectedOutput string, postEvaluation func(t *testing.T)) {
@@ -139,7 +139,7 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(2), authorizer.(*testAuthorizer).preFetchCalls.Load())
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
-				require.Nil(t, resolveCtx.subgraphErrors)
+				require.Nil(t, resolveCtx.SubgraphErrors())
 			}
 	}))
 	t.Run("disallow field with extension", testFnWithPostEvaluation(func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx *Context, expectedOutput string, postEvaluation func(t *testing.T)) {
@@ -167,7 +167,7 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(2), authorizer.(*testAuthorizer).preFetchCalls.Load())
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
-				require.Nil(t, resolveCtx.subgraphErrors)
+				require.Nil(t, resolveCtx.SubgraphErrors())
 			}
 	}))
 	t.Run("no authorization rules/checks", testFnWithPostEvaluation(func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx *Context, expectedOutput string, postEvaluation func(t *testing.T)) {
@@ -187,7 +187,7 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(0), authorizer.(*testAuthorizer).preFetchCalls.Load())
 				assert.Equal(t, int64(0), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
-				require.Nil(t, resolveCtx.subgraphErrors)
+				require.Nil(t, resolveCtx.SubgraphErrors())
 			}
 	}))
 	t.Run("disallow root fetch", testFnWithPostEvaluation(func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx *Context, expectedOutput string, postEvaluation func(t *testing.T)) {
@@ -213,7 +213,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(0), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				userErr := resolveCtx.SubgraphErrorByName("users")
+				require.ErrorAs(t, userErr, &subgraphError)
 				require.Equal(t, "users", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "query", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch from users Subgraph", subgraphError.Reason)
@@ -244,7 +245,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(0), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				userErr := resolveCtx.SubgraphErrorByName("users")
+				require.ErrorAs(t, userErr, &subgraphError)
 				require.Equal(t, "users", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "query", subgraphError.Path)
 				require.Equal(t, "", subgraphError.Reason)
@@ -276,11 +278,13 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(2), authorizer.(*testAuthorizer).preFetchCalls.Load())
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
-				require.NotEmpty(t, resolveCtx.subgraphErrors)
-				require.EqualError(t, resolveCtx.subgraphErrors, "Failed to fetch from Subgraph 'products' at Path: 'query.me.reviews.@.product', Reason: Not allowed to fetch from products Subgraph.")
+				require.NotEmpty(t, resolveCtx.SubgraphErrors())
+				prodErr := resolveCtx.SubgraphErrorByName("products")
+				require.Error(t, prodErr)
+				require.EqualError(t, prodErr, "Failed to fetch from Subgraph 'products' at Path: 'query.me.reviews.@.product', Reason: Not allowed to fetch from products Subgraph.")
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				require.ErrorAs(t, prodErr, &subgraphError)
 				require.Equal(t, "products", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "query.me.reviews.@.product", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch from products Subgraph", subgraphError.Reason)
@@ -311,7 +315,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				prodErr := resolveCtx.SubgraphErrorByName("products")
+				require.ErrorAs(t, prodErr, &subgraphError)
 				require.Equal(t, "products", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "Query.me.reviews.product.data.name", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch name on Product", subgraphError.Reason)
@@ -344,7 +349,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				prodErr := resolveCtx.SubgraphErrorByName("products")
+				require.ErrorAs(t, prodErr, &subgraphError)
 				require.Equal(t, "products", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "query.me.reviews.@.product", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch from products Subgraph", subgraphError.Reason)
@@ -388,7 +394,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				reviewsErr := resolveCtx.SubgraphErrorByName("reviews")
+				require.ErrorAs(t, reviewsErr, &subgraphError)
 				require.Equal(t, "reviews", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "Query.me.reviews.body", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch body on Review", subgraphError.Reason)
@@ -417,7 +424,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				reviewsErr := resolveCtx.SubgraphErrorByName("reviews")
+				require.ErrorAs(t, reviewsErr, &subgraphError)
 				require.Equal(t, "reviews", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "Query.me.reviews.body", subgraphError.Path)
 				require.Equal(t, "", subgraphError.Reason)
@@ -448,7 +456,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				prodErr := resolveCtx.SubgraphErrorByName("products")
+				require.ErrorAs(t, prodErr, &subgraphError)
 				require.Equal(t, "products", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "query.me.reviews.@.product", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch name on Product", subgraphError.Reason)
@@ -479,7 +488,8 @@ func TestAuthorization(t *testing.T) {
 				assert.Equal(t, int64(4), authorizer.(*testAuthorizer).objectFieldCalls.Load())
 
 				var subgraphError *SubgraphError
-				require.ErrorAs(t, resolveCtx.subgraphErrors, &subgraphError)
+				prodErr := resolveCtx.SubgraphErrorByName("products")
+				require.ErrorAs(t, prodErr, &subgraphError)
 				require.Equal(t, "products", subgraphError.DataSourceInfo.Name)
 				require.Equal(t, "Query.me.reviews.product.data.name", subgraphError.Path)
 				require.Equal(t, "Not allowed to fetch name on Product", subgraphError.Reason)
diff --git a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/context.go b/app/v2/pkg/engine/resolve/context.go
index 65d2d6b..86856b8 100644
--- a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/context.go
+++ b/app/v2/pkg/engine/resolve/context.go
@@ -6,6 +6,8 @@ import (
 	"errors"
 	"io"
 	"net/http"
+	"sort"
+	"sync"
 	"time"
 
 	"github.com/wundergraph/astjson"
@@ -31,7 +33,7 @@ type Context struct {
 	rateLimiter   RateLimiter
 	fieldRenderer FieldValueRenderer
 
-	subgraphErrors error
+	subgraphErrors subgraphErrors
 }
 
 type ExecutionOptions struct {
@@ -138,11 +140,119 @@ func (c *Context) SetRateLimiter(limiter RateLimiter) {
 }
 
 func (c *Context) SubgraphErrors() error {
-	return c.subgraphErrors
+	return c.subgraphErrors.joinAll()
 }
 
-func (c *Context) appendSubgraphErrors(errs ...error) {
-	c.subgraphErrors = errors.Join(c.subgraphErrors, errors.Join(errs...))
+// SubgraphErrorByName returns the joined error for the given subgraph name or data source ID.
+func (c *Context) SubgraphErrorByName(name string) error {
+	return c.subgraphErrors.errorByName(name)
+}
+
+func (c *Context) appendSubgraphErrors(ds DataSourceInfo, errs ...error) {
+	c.subgraphErrors.append(ds, errs...)
+}
+
+func (c *Context) subgraphErrorFor(ds DataSourceInfo) error {
+	return c.subgraphErrors.errorFor(ds)
+}
+
+type subgraphKey struct {
+	ID   string
+	Name string
+}
+
+type subgraphErrorEntry struct {
+	ds   DataSourceInfo
+	errs []error
+}
+
+type subgraphErrors struct {
+	mu      sync.Mutex
+	entries map[subgraphKey]*subgraphErrorEntry
+}
+
+func (se *subgraphErrors) append(ds DataSourceInfo, errs ...error) {
+	filtered := make([]error, 0, len(errs))
+	for _, err := range errs {
+		if err == nil {
+			continue
+		}
+		filtered = append(filtered, err)
+	}
+	if len(filtered) == 0 {
+		return
+	}
+
+	se.mu.Lock()
+	defer se.mu.Unlock()
+
+	if se.entries == nil {
+		se.entries = make(map[subgraphKey]*subgraphErrorEntry)
+	}
+	key := subgraphKey{ID: ds.ID, Name: ds.Name}
+	entry, ok := se.entries[key]
+	if !ok {
+		entry = &subgraphErrorEntry{ds: ds}
+		se.entries[key] = entry
+	} else {
+		entry.ds = ds
+	}
+	entry.errs = append(entry.errs, filtered...)
+}
+
+func (se *subgraphErrors) errorFor(ds DataSourceInfo) error {
+	se.mu.Lock()
+	defer se.mu.Unlock()
+	if len(se.entries) == 0 {
+		return nil
+	}
+	entry := se.entries[subgraphKey{ID: ds.ID, Name: ds.Name}]
+	if entry == nil {
+		return nil
+	}
+	return errors.Join(entry.errs...)
+}
+
+func (se *subgraphErrors) joinAll() error {
+	se.mu.Lock()
+	defer se.mu.Unlock()
+
+	if len(se.entries) == 0 {
+		return nil
+	}
+
+	keys := make([]subgraphKey, 0, len(se.entries))
+	for key := range se.entries {
+		keys = append(keys, key)
+	}
+	sort.Slice(keys, func(i, j int) bool {
+		if keys[i].ID != keys[j].ID {
+			return keys[i].ID < keys[j].ID
+		}
+		return keys[i].Name < keys[j].Name
+	})
+
+	var joined error
+	for _, key := range keys {
+		entry := se.entries[key]
+		entryErr := errors.Join(entry.errs...)
+		joined = errors.Join(joined, entryErr)
+	}
+	return joined
+}
+
+func (se *subgraphErrors) errorByName(name string) error {
+	se.mu.Lock()
+	defer se.mu.Unlock()
+	if len(se.entries) == 0 {
+		return nil
+	}
+	for _, entry := range se.entries {
+		if entry.ds.Name == name || entry.ds.ID == name {
+			return errors.Join(entry.errs...)
+		}
+	}
+	return nil
 }
 
 type Request struct {
@@ -202,7 +312,7 @@ func (c *Context) Free() {
 	c.RemapVariables = nil
 	c.TracingOptions.DisableAll()
 	c.Extensions = nil
-	c.subgraphErrors = nil
+	c.subgraphErrors = subgraphErrors{}
 	c.authorizer = nil
 	c.LoaderHooks = nil
 }
diff --git a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/loader.go b/app/v2/pkg/engine/resolve/loader.go
index 7a14d61..9bb95ae 100644
--- a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/loader.go
+++ b/app/v2/pkg/engine/resolve/loader.go
@@ -243,7 +243,7 @@ func (l *Loader) resolveParallel(nodes []*FetchTreeNode) error {
 				if l.ctx.LoaderHooks != nil && results[i].nestedMergeItems[j].loaderHookContext != nil {
 					l.ctx.LoaderHooks.OnFinished(results[i].nestedMergeItems[j].loaderHookContext,
 						results[i].nestedMergeItems[j].ds,
-						newResponseInfo(results[i].nestedMergeItems[j], l.ctx.subgraphErrors))
+						newResponseInfo(results[i].nestedMergeItems[j], l.ctx.subgraphErrorFor(results[i].nestedMergeItems[j].ds)))
 				}
 				if err != nil {
 					return errors.WithStack(err)
@@ -252,7 +252,7 @@ func (l *Loader) resolveParallel(nodes []*FetchTreeNode) error {
 		} else {
 			err = l.mergeResult(nodes[i].Item, results[i], itemsItems[i])
 			if l.ctx.LoaderHooks != nil {
-				l.ctx.LoaderHooks.OnFinished(results[i].loaderHookContext, results[i].ds, newResponseInfo(results[i], l.ctx.subgraphErrors))
+				l.ctx.LoaderHooks.OnFinished(results[i].loaderHookContext, results[i].ds, newResponseInfo(results[i], l.ctx.subgraphErrorFor(results[i].ds)))
 			}
 			if err != nil {
 				return errors.WithStack(err)
@@ -289,7 +289,7 @@ func (l *Loader) resolveSingle(item *FetchItem) error {
 		}
 		err = l.mergeResult(item, res, items)
 		if l.ctx.LoaderHooks != nil {
-			l.ctx.LoaderHooks.OnFinished(res.loaderHookContext, res.ds, newResponseInfo(res, l.ctx.subgraphErrors))
+			l.ctx.LoaderHooks.OnFinished(res.loaderHookContext, res.ds, newResponseInfo(res, l.ctx.subgraphErrorFor(res.ds)))
 		}
 
 		return err
@@ -303,7 +303,7 @@ func (l *Loader) resolveSingle(item *FetchItem) error {
 		}
 		err = l.mergeResult(item, res, items)
 		if l.ctx.LoaderHooks != nil {
-			l.ctx.LoaderHooks.OnFinished(res.loaderHookContext, res.ds, newResponseInfo(res, l.ctx.subgraphErrors))
+			l.ctx.LoaderHooks.OnFinished(res.loaderHookContext, res.ds, newResponseInfo(res, l.ctx.subgraphErrorFor(res.ds)))
 		}
 		return err
 	case *EntityFetch:
@@ -316,7 +316,7 @@ func (l *Loader) resolveSingle(item *FetchItem) error {
 		}
 		err = l.mergeResult(item, res, items)
 		if l.ctx.LoaderHooks != nil {
-			l.ctx.LoaderHooks.OnFinished(res.loaderHookContext, res.ds, newResponseInfo(res, l.ctx.subgraphErrors))
+			l.ctx.LoaderHooks.OnFinished(res.loaderHookContext, res.ds, newResponseInfo(res, l.ctx.subgraphErrorFor(res.ds)))
 		}
 		return err
 	case *ParallelListItemFetch:
@@ -349,7 +349,7 @@ func (l *Loader) resolveSingle(item *FetchItem) error {
 		for i := range results {
 			err = l.mergeResult(item, results[i], items[i:i+1])
 			if l.ctx.LoaderHooks != nil {
-				l.ctx.LoaderHooks.OnFinished(results[i].loaderHookContext, results[i].ds, newResponseInfo(results[i], l.ctx.subgraphErrors))
+				l.ctx.LoaderHooks.OnFinished(results[i].loaderHookContext, results[i].ds, newResponseInfo(results[i], l.ctx.subgraphErrorFor(results[i].ds)))
 			}
 			if err != nil {
 				return errors.WithStack(err)
@@ -740,7 +740,7 @@ func (l *Loader) appendSubgraphError(res *result, fetchItem *FetchItem, value *a
 		subgraphError.AppendDownstreamError(&gErr)
 	}
 
-	l.ctx.appendSubgraphErrors(res.err, subgraphError)
+	l.ctx.appendSubgraphErrors(res.ds, res.err, subgraphError)
 
 	return nil
 }
@@ -1088,7 +1088,7 @@ func (l *Loader) renderErrorsFailedDeps(fetchItem *FetchItem, res *result) error
 }
 
 func (l *Loader) renderErrorsFailedToFetch(fetchItem *FetchItem, res *result, reason string) error {
-	l.ctx.appendSubgraphErrors(res.err, NewSubgraphError(res.ds, fetchItem.ResponsePath, reason, res.statusCode))
+	l.ctx.appendSubgraphErrors(res.ds, res.err, NewSubgraphError(res.ds, fetchItem.ResponsePath, reason, res.statusCode))
 	errorObject, err := astjson.ParseWithoutCache(l.renderSubgraphBaseError(res.ds, fetchItem.ResponsePath, reason))
 	if err != nil {
 		return err
@@ -1104,7 +1104,7 @@ func (l *Loader) renderErrorsStatusFallback(fetchItem *FetchItem, res *result, s
 		reason += fmt.Sprintf(": %s", statusText)
 	}
 
-	l.ctx.appendSubgraphErrors(res.err, NewSubgraphError(res.ds, fetchItem.ResponsePath, reason, res.statusCode))
+	l.ctx.appendSubgraphErrors(res.ds, res.err, NewSubgraphError(res.ds, fetchItem.ResponsePath, reason, res.statusCode))
 
 	errorObject, err := astjson.ParseWithoutCache(fmt.Sprintf(`{"message":"%s"}`, reason))
 	if err != nil {
@@ -1133,7 +1133,7 @@ func (l *Loader) renderSubgraphBaseError(ds DataSourceInfo, path, reason string)
 
 func (l *Loader) renderAuthorizationRejectedErrors(fetchItem *FetchItem, res *result) error {
 	for i := range res.authorizationRejectedReasons {
-		l.ctx.appendSubgraphErrors(res.err, NewSubgraphError(res.ds, fetchItem.ResponsePath, res.authorizationRejectedReasons[i], res.statusCode))
+		l.ctx.appendSubgraphErrors(res.ds, res.err, NewSubgraphError(res.ds, fetchItem.ResponsePath, res.authorizationRejectedReasons[i], res.statusCode))
 	}
 	pathPart := l.renderAtPathErrorPart(fetchItem.ResponsePath)
 	extensionErrorCode := fmt.Sprintf(`"extensions":{"code":"%s"}`, errorcodes.UnauthorizedFieldOrType)
@@ -1174,7 +1174,7 @@ func (l *Loader) renderAuthorizationRejectedErrors(fetchItem *FetchItem, res *re
 }
 
 func (l *Loader) renderRateLimitRejectedErrors(fetchItem *FetchItem, res *result) error {
-	l.ctx.appendSubgraphErrors(res.err, NewRateLimitError(res.ds.Name, fetchItem.ResponsePath, res.rateLimitRejectedReason))
+	l.ctx.appendSubgraphErrors(res.ds, res.err, NewRateLimitError(res.ds.Name, fetchItem.ResponsePath, res.rateLimitRejectedReason))
 	pathPart := l.renderAtPathErrorPart(fetchItem.ResponsePath)
 	var (
 		err         error
diff --git a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/resolvable.go b/app/v2/pkg/engine/resolve/resolvable.go
index 5219c91..13df1db 100644
--- a/tmp/agent-patch-flux-pr-1351.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/resolvable.go
+++ b/app/v2/pkg/engine/resolve/resolvable.go
@@ -758,7 +758,7 @@ func (r *Resolvable) addRejectFieldError(reason string, ds DataSourceInfo, field
 	} else {
 		errorMessage = fmt.Sprintf("Unauthorized to load field '%s', Reason: %s.", fieldPath, reason)
 	}
-	r.ctx.appendSubgraphErrors(errors.New(errorMessage),
+	r.ctx.appendSubgraphErrors(ds, errors.New(errorMessage),
 		NewSubgraphError(ds, fieldPath, reason, 0))
 	fastjsonext.AppendErrorWithExtensionsCodeToArray(r.astjsonArena, r.errors, errorMessage, errorcodes.UnauthorizedFieldOrType, r.path)
 	r.popNodePathElement(nodePath)