@@ -149,10 +149,32 @@ export class EdgeManager {
149149 this . nodesWithActivatedEdge . add ( nodeId )
150150 }
151151
152+ /**
153+ * Deactivates the `error` edge of a successfully-resumed pause block instead of
154+ * firing it: the block completed normally, so its error path is pruned (and any
155+ * now-dead descendants cascaded), mirroring how a normally-succeeding block's
156+ * error edge is handled in {@link processOutgoingEdges}.
157+ *
158+ * `cascadeTargets` is intentionally left undefined here (unlike the
159+ * {@link processOutgoingEdges} call site, which passes an explicit Set): the
160+ * resume path has no loop/parallel sentinels to queue — the pause block's
161+ * `source` edge drives continuation — so cascade-target collection is omitted.
162+ */
152163 deactivateResumedEdge ( sourceId : string , targetId : string , sourceHandle ?: string ) : void {
153164 this . deactivateEdgeAndDescendants ( sourceId , targetId , sourceHandle )
154165 }
155166
167+ /**
168+ * Clear deactivated edges for a set of nodes (used when restoring loop state for next iteration).
169+ *
170+ * Only clears edges whose SOURCE is in the provided set. Edges pointing INTO a node in the set
171+ * whose source lives outside (e.g. an external branch whose path was cascade-deactivated) must
172+ * remain deactivated — otherwise `countActiveIncomingEdges` would count a source that will never
173+ * fire again, stalling the loop on its next iteration.
174+ *
175+ * Deactivated edge keys encode the source separately so node IDs with shared prefixes
176+ * cannot clear each other's deactivated edges.
177+ */
156178 clearDeactivatedEdgesForNodes ( nodeIds : Set < string > ) : void {
157179 const edgesToRemove : string [ ] = [ ]
158180 for ( const edgeKey of this . deactivatedEdges ) {
@@ -179,6 +201,11 @@ export class EdgeManager {
179201 return targetNode ? this . isNodeReady ( targetNode ) : false
180202 }
181203
204+ /**
205+ * Checks if the cascade target sentinel belongs to the same subflow as the source node.
206+ * A condition inside a loop that hits a dead-end should still allow the enclosing
207+ * loop's sentinel to fire so the loop can continue or exit.
208+ */
182209 private isEnclosingSentinel ( sourceNode : DAGNode , sentinelId : string ) : boolean {
183210 const sentinel = this . dag . nodes . get ( sentinelId )
184211 if ( ! sentinel ?. metadata . isSentinel ) return false
@@ -313,6 +340,9 @@ export class EdgeManager {
313340 }
314341 }
315342
343+ /**
344+ * Checks if a node has any active incoming edges besides the one being excluded.
345+ */
316346 private hasActiveIncomingEdges ( node : DAGNode , excludeEdgeKey : string ) : boolean {
317347 for ( const incomingSourceId of node . incomingEdges ) {
318348 const incomingNode = this . dag . nodes . get ( incomingSourceId )
0 commit comments