Rolls child task outcomes up into the parent's status and progress.
Replaces the previous behavior of unconditionally marking the parent Complete at 100%, which
reported success for graphs that had actually failed or stalled.
Precedence once no work remains in flight: any Failed → Failed; else any Blocked → Blocked;
else any Cancelled → Cancelled; else Complete. While work remains, the parent is
In Progress. An empty graph is Complete — vacuously true, and it keeps a degenerate submission
from hanging.
percentComplete counts Complete and Skipped children — a fork's loser branch is done, and
counting it as outstanding would leave every branching flow stuck below 100%.
Skipped is invisible to precedence. A branch that was not taken says nothing about whether
the graph succeeded, so it neither fails nor blocks the parent. Without this, a sequential flow
containing a single fork would settle Blocked every time.
handledFailureIDs (spec failureSemantics: 'edges') names Failed children that produced a
satisfied outgoing edge — a recovery path ran. Those are treated like Skipped for precedence,
so a flow that failed a step, recovered, and reached the end settles Complete, exactly as the
flow engine does today. A Failed child with no recovery path stays a failure.
Rolls child task outcomes up into the parent's status and progress.
Replaces the previous behavior of unconditionally marking the parent
Completeat 100%, which reported success for graphs that had actually failed or stalled.Precedence once no work remains in flight: any
Failed→Failed; else anyBlocked→Blocked; else anyCancelled→Cancelled; elseComplete. While work remains, the parent isIn Progress. An empty graph isComplete— vacuously true, and it keeps a degenerate submission from hanging.percentCompletecountsCompleteandSkippedchildren — a fork's loser branch is done, and counting it as outstanding would leave every branching flow stuck below 100%.Skippedis invisible to precedence. A branch that was not taken says nothing about whether the graph succeeded, so it neither fails nor blocks the parent. Without this, a sequential flow containing a single fork would settleBlockedevery time.handledFailureIDs(specfailureSemantics: 'edges') names Failed children that produced a satisfied outgoing edge — a recovery path ran. Those are treated like Skipped for precedence, so a flow that failed a step, recovered, and reached the end settlesComplete, exactly as the flow engine does today. A Failed child with no recovery path stays a failure.