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
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