rewindNodePaths function
The full node-path set ONE Rewind resets (tg-o90): the named
targetStepIds ∪ their transitive dependents ∪ the rewinding selfStepId,
each expanded to its whole subtree.
Every returned path gets state=pending + a bumped per-node rewindCount in
ONE chokepoint write; the bump RE-KEYS each node, so keyed reconcile tears
the old incarnations down (killing any live effect) and re-runs them virgin.
SCOPE: siblings of the rewinding node, in ITS circuit. A node in a PARENT
circuit is never reset — it cannot have advanced, because its dependsOn on
this circuit resolves to this circuit's terminal descendant, which is in the
set (or downstream of it) and is going pending right now.
A dangling id in targetStepIds is SKIPPED here; the host validates first
and routes a dangling/empty rewind to a LOUD supervised failure (a typo'd
step id must never silently degrade into "re-run only myself, forever").
Implementation
Set<String> rewindNodePaths(
Circuit circuit,
String circuitPath,
Set<String> targetStepIds, {
required String selfStepId,
required Circuit? Function(String circuitId) circuitById,
}) {
final ids = <String>{
...targetStepIds,
...transitiveDependents(circuit, targetStepIds),
selfStepId,
};
final paths = <String>{};
for (final id in ids) {
final step = circuit.stepById(id);
if (step == null) continue; // dangling — the host already failed LOUD.
paths.addAll(subtreeNodePaths(circuitPath, step, circuitById: circuitById));
}
return paths;
}