From 44db6a120d8017c468af9925c88510b4a4c688ae Mon Sep 17 00:00:00 2001 From: Siddharth Ganesan Date: Wed, 28 Jan 2026 11:25:38 -0800 Subject: [PATCH] Fix --- apps/sim/executor/dag/construction/edges.ts | 11 +++++++---- apps/sim/executor/execution/edge-manager.ts | 20 ++++++++++++-------- apps/sim/executor/execution/engine.ts | 6 ++++++ apps/sim/executor/orchestrators/node.ts | 2 +- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/apps/sim/executor/dag/construction/edges.ts b/apps/sim/executor/dag/construction/edges.ts index 4a36e5f91..3e1c65670 100644 --- a/apps/sim/executor/dag/construction/edges.ts +++ b/apps/sim/executor/dag/construction/edges.ts @@ -207,6 +207,7 @@ export class EdgeConstructor { for (const connection of workflow.connections) { let { source, target } = connection const originalSource = source + const originalTarget = target let sourceHandle = this.generateSourceHandle( source, target, @@ -257,14 +258,16 @@ export class EdgeConstructor { target = sentinelStartId } - if (loopSentinelStartId) { - this.addEdge(dag, loopSentinelStartId, target, EDGE.LOOP_EXIT, targetHandle) - } - if (this.edgeCrossesLoopBoundary(source, target, blocksInLoops, dag)) { continue } + // Only add LOOP_EXIT edge if target is outside the loop + // (target would be inside if it's in blocksInLoops for the same loop) + if (loopSentinelStartId && !blocksInLoops.has(originalTarget)) { + this.addEdge(dag, loopSentinelStartId, target, EDGE.LOOP_EXIT, targetHandle) + } + if (!this.isEdgeReachable(source, target, reachableBlocks, dag)) { continue } diff --git a/apps/sim/executor/execution/edge-manager.ts b/apps/sim/executor/execution/edge-manager.ts index f0ac33fa7..149a8a48b 100644 --- a/apps/sim/executor/execution/edge-manager.ts +++ b/apps/sim/executor/execution/edge-manager.ts @@ -78,14 +78,18 @@ export class EdgeManager { } // Check if any deactivation targets that previously received an activated edge are now ready - for (const { target } of edgesToDeactivate) { - if ( - !readyNodes.includes(target) && - !activatedTargets.includes(target) && - this.nodesWithActivatedEdge.has(target) && - this.isTargetReady(target) - ) { - readyNodes.push(target) + // Skip this check when exiting a loop/parallel, as deactivated targets are loop body nodes + // that should not execute + if (output.selectedRoute !== EDGE.LOOP_EXIT && output.selectedRoute !== EDGE.PARALLEL_EXIT) { + for (const { target } of edgesToDeactivate) { + if ( + !readyNodes.includes(target) && + !activatedTargets.includes(target) && + this.nodesWithActivatedEdge.has(target) && + this.isTargetReady(target) + ) { + readyNodes.push(target) + } } } diff --git a/apps/sim/executor/execution/engine.ts b/apps/sim/executor/execution/engine.ts index 05e7e0484..86e7fd625 100644 --- a/apps/sim/executor/execution/engine.ts +++ b/apps/sim/executor/execution/engine.ts @@ -390,6 +390,12 @@ export class ExecutionEngine { logger.info('Processing outgoing edges', { nodeId, outgoingEdgesCount: node.outgoingEdges.size, + outgoingEdges: Array.from(node.outgoingEdges.entries()).map(([id, e]) => ({ + id, + target: e.target, + sourceHandle: e.sourceHandle, + })), + output, readyNodesCount: readyNodes.length, readyNodes, }) diff --git a/apps/sim/executor/orchestrators/node.ts b/apps/sim/executor/orchestrators/node.ts index e5d7bc1a1..6ac9661ce 100644 --- a/apps/sim/executor/orchestrators/node.ts +++ b/apps/sim/executor/orchestrators/node.ts @@ -97,7 +97,7 @@ export class NodeExecutionOrchestrator { if (loopId) { const shouldExecute = await this.loopOrchestrator.evaluateInitialCondition(ctx, loopId) if (!shouldExecute) { - logger.info('While loop initial condition false, skipping loop body', { loopId }) + logger.info('Loop initial condition false, skipping loop body', { loopId }) return { sentinelStart: true, shouldExit: true,