(I guess I should also add, I do have an implementation that does behave the way I want, it's the loop/recur version that doesn't and it surprised me. If you replace the (def cancel! ,,,) with this implementation, it behaves as desired:
(def cancel! ((m/reduce (fn [_ x] (prn x)) nil
(m/cp (let [sig <value-sig
[wait? value :as ret] (m/?< sig)]
(if-not wait?
ret
(if (nil? value)
[true nil]
(let [!rewind-me (atom false)]
(if (m/?< (m/watch !rewind-me))
[false value]
(if (m/?< <continue-sig)
(reset! !rewind-me true)
[true nil]))))))))
If you need to describe an actual circular dependency, using a mutable reference is the way to go. I don't quite get what problem you're trying to solve but feel free to propose better solutions, I don't have a clear path forward yet https://github.com/leonoel/missionary/issues/99
My graph is a DAG, this achieves "synchronized start" when multiple input edges to the dag (atoms) are updated, conceptually, at the same time. I have to set the <continue-sig's underlying to atom to false, update multiple values with [true <value>] so they'll propagate the delay, then reset! the <continue-sig's underlying atom to true, at which time all delayed computations unblock simultaneously and values begin to propagate again with [false ,,,] in the front.
For a single atom update, you just set the input atom to [false ,,,] and leave the <continual-signal's atom alone (it will have a value of true, but it should have no subscribers).