fix: exclude handler compound children from main flow ELK graph
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 56s
CI / docker (push) Successful in 39s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 35s

Root cause found: RouteGraph.getNodes() is a FLAT list that includes
handler compound children (log8, setBody1, etc.) as top-level entries
alongside the main flow nodes. The handler separation only identified
the compound PARENTS (ON_EXCEPTION) but not their children, so 7
handler children leaked into rootNode as main flow nodes, causing
ELK to place the real main flow at wrong Y positions.

Fix: two-pass separation — first identify handler compounds and
collect ALL descendant IDs, then build mainNodes excluding both
handler compounds AND their descendants.

Debug logging left in temporarily for verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-27 22:33:40 +01:00
parent 19d3c8fa93
commit acb7cade90

View File

@@ -206,15 +206,24 @@ public class ElkDiagramRenderer implements DiagramRenderer {
Map<String, Color> nodeColors = new HashMap<>();
Set<String> compoundNodeIds = new HashSet<>();
// Separate handler sections from main flow nodes
// Separate handler sections from main flow nodes.
// graph.getNodes() is a FLAT list that includes handler compound children
// as top-level entries. We must identify and exclude them.
List<RouteNode> mainNodes = new ArrayList<>();
List<RouteNode> handlerNodes = new ArrayList<>();
Set<String> handlerDescendantIds = new HashSet<>();
if (graph.getNodes() != null) {
// First pass: identify handler compounds and collect their descendant IDs
for (RouteNode rn : graph.getNodes()) {
if (rn.getType() != null && HANDLER_SECTION_TYPES.contains(rn.getType())
&& rn.getChildren() != null && !rn.getChildren().isEmpty()) {
handlerNodes.add(rn);
} else {
collectDescendantIds(rn.getChildren(), handlerDescendantIds);
}
}
// Second pass: main flow = everything that isn't a handler or handler descendant
for (RouteNode rn : graph.getNodes()) {
if (!handlerNodes.contains(rn) && !handlerDescendantIds.contains(rn.getId())) {
mainNodes.add(rn);
}
}
@@ -643,6 +652,16 @@ public class ElkDiagramRenderer implements DiagramRenderer {
}
/** Recursively collect all node IDs from a tree. */
/** Collect IDs of all RouteNode descendants (for handler separation). */
private void collectDescendantIds(List<RouteNode> nodes, Set<String> ids) {
for (RouteNode n : nodes) {
ids.add(n.getId());
if (n.getChildren() != null) {
collectDescendantIds(n.getChildren(), ids);
}
}
}
private void collectAllIds(PositionedNode node, Set<String> ids) {
ids.add(node.id());
if (node.children() != null) {