STET

agent_patch

runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-1338/flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch

11918 bytes

Back to adjudication
diff --git a/tmp/agent-patch-flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/datasource_filter_node_suggestions.go b/app/v2/pkg/engine/plan/datasource_filter_node_suggestions.go
index 9722949..e8cf5b3 100644
--- a/tmp/agent-patch-flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/datasource_filter_node_suggestions.go
+++ b/app/v2/pkg/engine/plan/datasource_filter_node_suggestions.go
@@ -156,6 +156,23 @@ func (f *NodeSuggestions) RemoveTreeNodeChilds(fieldRef int) {
 		return
 	}
 
+	children := node.GetChildren()
+	if len(children) > 0 {
+		queue := make([]tree.Node[[]int], 0, len(children))
+		queue = append(queue, children...)
+
+		for len(queue) > 0 {
+			current := queue[0]
+			queue = queue[1:]
+
+			for _, itemID := range current.GetData() {
+				f.items[itemID].unselect()
+			}
+
+			queue = append(queue, current.GetChildren()...)
+		}
+	}
+
 	node.ReplaceChildren()
 }
 
diff --git a/tmp/agent-patch-flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/node_selection_visitor.go b/app/v2/pkg/engine/plan/node_selection_visitor.go
index 0345af2..c24b966 100644
--- a/tmp/agent-patch-flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/node_selection_visitor.go
+++ b/app/v2/pkg/engine/plan/node_selection_visitor.go
@@ -99,6 +99,7 @@ type keyRequirements struct {
 type fieldRequirements struct {
 	dsHash                       DSHash
 	path                         string
+	typeName                     string
 	selectionSet                 string
 	requestedByFieldRefs         []int
 	isTypenameForEntityInterface bool
@@ -182,6 +183,11 @@ func (c *nodeSelectionVisitor) EnterOperationDefinition(ref int) {
 func (c *nodeSelectionVisitor) EnterSelectionSet(ref int) {
 	c.debugPrint("EnterSelectionSet ref:", ref)
 	c.selectionSetRefs = append(c.selectionSetRefs, ref)
+
+	// Process pending requirements before walking nested fields to avoid mutating
+	// sibling selections after they were already visited.
+	c.processPendingFieldRequirements(ref)
+	c.processPendingKeyRequirements(ref)
 }
 
 func (c *nodeSelectionVisitor) LeaveSelectionSet(ref int) {
@@ -389,6 +395,7 @@ func (c *nodeSelectionVisitor) handleKeyRequirementsForBackJumpOnSameDataSource(
 
 func (c *nodeSelectionVisitor) addPendingFieldRequirements(requestedByFieldRef int, dsHash DSHash, fieldConfiguration FederationFieldConfiguration, currentPath string, isTypenameForEntityInterface bool) {
 	currentSelectionSet := c.currentSelectionSet()
+	typeName := c.walker.EnclosingTypeDefinition.NameString(c.definition)
 
 	requirements, hasRequirements := c.pendingFieldRequirements[currentSelectionSet]
 	if !hasRequirements {
@@ -402,6 +409,7 @@ func (c *nodeSelectionVisitor) addPendingFieldRequirements(requestedByFieldRef i
 		config := fieldRequirements{
 			dsHash:                       dsHash,
 			path:                         currentPath,
+			typeName:                     typeName,
 			selectionSet:                 fieldConfiguration.SelectionSet,
 			requestedByFieldRefs:         []int{requestedByFieldRef},
 			isTypenameForEntityInterface: isTypenameForEntityInterface,
@@ -476,8 +484,6 @@ func (c *nodeSelectionVisitor) processPendingFieldRequirements(selectionSetRef i
 }
 
 func (c *nodeSelectionVisitor) addFieldRequirementsToOperation(selectionSetRef int, requirements fieldRequirements) {
-	typeName := c.walker.EnclosingTypeDefinition.NameString(c.definition)
-
 	input := &addRequiredFieldsConfiguration{
 		operation:                     c.operation,
 		definition:                    c.definition,
@@ -485,14 +491,14 @@ func (c *nodeSelectionVisitor) addFieldRequirementsToOperation(selectionSetRef i
 		isTypeNameForEntityInterface:  requirements.isTypenameForEntityInterface,
 		isKey:                         false,
 		allowTypename:                 false,
-		typeName:                      typeName,
+		typeName:                      requirements.typeName,
 		fieldSet:                      requirements.selectionSet,
 		addTypenameInNestedSelections: c.addTypenameInNestedSelections,
 	}
 
 	addFieldsResult, report := addRequiredFields(input)
 	if report.HasErrors() {
-		c.walker.StopWithInternalErr(fmt.Errorf("failed to add required fields %s for %s at path %s", requirements.selectionSet, typeName, requirements.path))
+		c.walker.StopWithInternalErr(fmt.Errorf("failed to add required fields %s for %s at path %s", requirements.selectionSet, requirements.typeName, requirements.path))
 		return
 	}
 	c.resetVisitedAbstractChecksForModifiedFields(addFieldsResult.modifiedFieldRefs)
@@ -507,7 +513,7 @@ func (c *nodeSelectionVisitor) addFieldRequirementsToOperation(selectionSetRef i
 		// TODO: actually we could probably build representations right away?
 		// e.g. build it here, pass to path visitor and down to datasource, without the need to parse it there?
 		fieldConfiguration := FederationFieldConfiguration{
-			TypeName:      typeName,
+			TypeName:      requirements.typeName,
 			FieldName:     c.operation.FieldNameString(requestedByFieldRef),
 			SelectionSet:  requirements.selectionSet,
 			RemappedPaths: addFieldsResult.remappedPaths,
@@ -688,31 +694,108 @@ func (c *nodeSelectionVisitor) resetVisitedAbstractChecksForModifiedFields(modif
 }
 
 func (c *nodeSelectionVisitor) updateFieldDependsOn(changedFieldRefs map[int][]int) {
-	for key, fieldRefs := range c.fieldDependsOn {
-		updatedFieldRefs := make([]int, 0, len(fieldRefs))
+	remapFieldRefs := func(fieldRefs []int) []int {
+		out := make([]int, 0, len(fieldRefs))
+		seen := make(map[int]struct{}, len(fieldRefs))
 		for _, fieldRef := range fieldRefs {
-			if newRefs := changedFieldRefs[fieldRef]; newRefs != nil {
-				updatedFieldRefs = append(updatedFieldRefs, newRefs...)
-			} else {
-				updatedFieldRefs = append(updatedFieldRefs, fieldRef)
+			if newRefs := changedFieldRefs[fieldRef]; len(newRefs) > 0 {
+				for _, newRef := range newRefs {
+					if _, ok := seen[newRef]; ok {
+						continue
+					}
+					seen[newRef] = struct{}{}
+					out = append(out, newRef)
+				}
+				continue
 			}
-		}
 
-		c.fieldDependsOn[key] = updatedFieldRefs
+			if _, ok := seen[fieldRef]; ok {
+				continue
+			}
+			seen[fieldRef] = struct{}{}
+			out = append(out, fieldRef)
+		}
+		return out
 	}
 
-	for key, fieldRefs := range c.fieldRefDependsOn {
-		updatedFieldRefs := make([]int, 0, len(fieldRefs))
-		for _, fieldRef := range fieldRefs {
-			if newRefs := changedFieldRefs[fieldRef]; newRefs != nil {
-				updatedFieldRefs = append(updatedFieldRefs, newRefs...)
-			} else {
-				updatedFieldRefs = append(updatedFieldRefs, fieldRef)
+	appendUniqueFieldConfigs := func(dst []FederationFieldConfiguration, src ...FederationFieldConfiguration) []FederationFieldConfiguration {
+		dstCfg := FederationFieldConfigurations(dst)
+		for _, cfg := range src {
+			if !dstCfg.HasSelectionSet(cfg.TypeName, cfg.FieldName, cfg.SelectionSet) {
+				dst = append(dst, cfg)
+				dstCfg = FederationFieldConfigurations(dst)
 			}
 		}
+		return dst
+	}
 
-		c.fieldRefDependsOn[key] = updatedFieldRefs
+	updatedFieldDependsOn := make(map[fieldIndexKey][]int, len(c.fieldDependsOn))
+	for key, fieldRefs := range c.fieldDependsOn {
+		remappedFieldRefs := remapFieldRefs(fieldRefs)
+		remappedKeys := changedFieldRefs[key.fieldRef]
+		if len(remappedKeys) == 0 {
+			updatedFieldDependsOn[key] = remappedFieldRefs
+			continue
+		}
+
+		for _, newRef := range remappedKeys {
+			updatedKey := fieldIndexKey{fieldRef: newRef, dsHash: key.dsHash}
+			updatedFieldDependsOn[updatedKey] = append(updatedFieldDependsOn[updatedKey], remappedFieldRefs...)
+			updatedFieldDependsOn[updatedKey] = remapFieldRefs(updatedFieldDependsOn[updatedKey])
+		}
+	}
+	c.fieldDependsOn = updatedFieldDependsOn
+
+	updatedFieldRefDependsOn := make(map[int][]int, len(c.fieldRefDependsOn))
+	for fieldRef, dependencies := range c.fieldRefDependsOn {
+		remappedDependencies := remapFieldRefs(dependencies)
+		remappedRefs := changedFieldRefs[fieldRef]
+		if len(remappedRefs) == 0 {
+			updatedFieldRefDependsOn[fieldRef] = remappedDependencies
+			continue
+		}
+
+		for _, remappedRef := range remappedRefs {
+			updatedFieldRefDependsOn[remappedRef] = append(updatedFieldRefDependsOn[remappedRef], remappedDependencies...)
+			updatedFieldRefDependsOn[remappedRef] = remapFieldRefs(updatedFieldRefDependsOn[remappedRef])
+		}
+	}
+	c.fieldRefDependsOn = updatedFieldRefDependsOn
+
+	updatedFieldRequirementsConfigs := make(map[fieldIndexKey][]FederationFieldConfiguration, len(c.fieldRequirementsConfigs))
+	for key, requirements := range c.fieldRequirementsConfigs {
+		remappedKeys := changedFieldRefs[key.fieldRef]
+		if len(remappedKeys) == 0 {
+			updatedFieldRequirementsConfigs[key] = appendUniqueFieldConfigs(updatedFieldRequirementsConfigs[key], requirements...)
+			continue
+		}
+
+		for _, newRef := range remappedKeys {
+			updatedKey := fieldIndexKey{fieldRef: newRef, dsHash: key.dsHash}
+			updatedFieldRequirementsConfigs[updatedKey] = appendUniqueFieldConfigs(updatedFieldRequirementsConfigs[updatedKey], requirements...)
+		}
+	}
+	c.fieldRequirementsConfigs = updatedFieldRequirementsConfigs
+
+	updatedFieldDependencyKind := make(map[fieldDependencyKey]fieldDependencyKind, len(c.fieldDependencyKind))
+	for dependency, kind := range c.fieldDependencyKind {
+		remappedFields := changedFieldRefs[dependency.field]
+		if len(remappedFields) == 0 {
+			remappedFields = []int{dependency.field}
+		}
+
+		remappedDependencies := changedFieldRefs[dependency.dependsOn]
+		if len(remappedDependencies) == 0 {
+			remappedDependencies = []int{dependency.dependsOn}
+		}
+
+		for _, field := range remappedFields {
+			for _, dependsOn := range remappedDependencies {
+				updatedFieldDependencyKind[fieldDependencyKey{field: field, dependsOn: dependsOn}] = kind
+			}
+		}
 	}
+	c.fieldDependencyKind = updatedFieldDependencyKind
 
 	for _, newRefs := range changedFieldRefs {
 		c.addNewFieldRefs(newRefs...)
diff --git a/tmp/agent-patch-flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/path_builder_visitor.go b/app/v2/pkg/engine/plan/path_builder_visitor.go
index 2152cf8..ce8ba88 100644
--- a/tmp/agent-patch-flux-pr-1338.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/engine/plan/path_builder_visitor.go
+++ b/app/v2/pkg/engine/plan/path_builder_visitor.go
@@ -458,6 +458,7 @@ func (c *pathBuilderVisitor) EnterField(fieldRef int) {
 
 	suggestions := c.nodeSuggestions.SuggestionsForPath(typeName, fieldName, currentPath)
 	shareable := len(suggestions) > 1
+	planned := false
 	for _, suggestion := range suggestions {
 		dsIdx := slices.IndexFunc(c.dataSources, func(d DataSource) bool {
 			return d.Hash() == suggestion.DataSourceHash
@@ -470,16 +471,20 @@ func (c *pathBuilderVisitor) EnterField(fieldRef int) {
 
 		if !c.couldPlanField(fieldRef, ds.Hash()) {
 			c.handleMissingPath(false, typeName, fieldName, currentPath, shareable)
-
-			// if we could not plan the field, we should skip walking into it
-			// as the dependencies conditions are tight to this field,
-			// and we could mistakenly plan the nested fields on this datasource without current field
-			// It could happen when there are the same field as current on another datasource, and it is allowed to plan it
-			c.walker.SkipNode()
-			return
+			continue
 		}
 
 		c.handlePlanningField(fieldRef, typeName, fieldName, currentPath, parentPath, precedingParentPath, suggestion, ds, shareable)
+		if _, ok := c.fieldsPlannedOn[fieldRef]; ok {
+			planned = true
+		}
+	}
+
+	if !planned {
+		// if we could not plan the field at all, we should skip walking into it.
+		// otherwise nested fields could be planned without their parent path.
+		c.walker.SkipNode()
+		return
 	}
 
 	// we should update response path and array fields only when we are able to plan - so field is not skipped