Dependencies and data flow
Understand how All and Single dependency rules release downstream workflow work.
A workflow is a directed acyclic graph. Each dependency points from a downstream step to an
upstream step and declares exactly how the downstream work is released. Sonar supports two rules:
All and Single.
All: wait, then fan in
An All dependency is a barrier. The downstream step becomes ready only when the upstream step
is complete: every task is terminal, at least one task completed successfully, and any required
result finalization has finished. Sonar then creates the downstream step's normal task set once.
Use All when the downstream command needs a complete stage rather than one upstream task:
If a step has several All dependencies, every upstream step must satisfy the barrier. All does
not automatically concatenate upstream output into one variable; the workflow must give the
downstream command the shared files or paths it should read.
Single: stream one task at a time
A Single dependency creates one downstream task for each completed upstream task. It is a
streaming fan-out rule: the first downstream task may start while later upstream tasks are still
running.
The upstream step must declare one propagation channel:
OUTPUTbecomesINPUT_UPSTREAM; orOUTPUT_FILEbecomesINPUT_FILE_UPSTREAM.
The downstream command reads the corresponding input token. Sonar allows at most one Single
dependency on a step, because two independent per-task streams would not define an unambiguous
pairing rule.
Combining the rules
A step may have one Single dependency plus one or more All dependencies. In that case, all
All barriers must be satisfied before Single fan-out begins. After the barriers open, each
eligible completed task from the Single upstream creates one child.
A step using custom SQL input cannot also use Single: both mechanisms would own the task's input.
Parentage, lineage, and repeatability
Every Single child records the source task as ParentTaskId. The reconciler creates a child only
when no downstream task already points to that parent, so repeating a reconciliation tick does not
repeat the fan-out effect.
LineageId answers a different question: which original input produced this branch? Root work
starts a lineage, and descendants carry that identifier across later steps. ParentTaskId traces
one edge; LineageId groups the whole branch.
File and line expansion uses the same fields: the generated task points to its expansion parent and keeps the parent's lineage.
Completion behavior
- A root step with no task is not complete.
- A step completes only after all of its tasks are terminal, at least one task completed, and required result finalization has settled.
- If all tasks for a step are terminal and none completed, the scan completes with errors.
- An expansion that finds no files or lines records a terminal no-work result so descendants do not mistake the placeholder task for real output and the graph does not remain open forever.