This project has been succeeded by GraphReFly. New development happens at graphrefly-ts. npm install @graphrefly/graphrefly
Skip to content

March 24, 2026

RESOLVED: The Signal That Skips Entire Subtrees

RESOLVED Signal

Arc 4, Post 12 — Architecture v3: The Type 3 Breakthrough


DIRTY tells downstream: prepare — a dependency is in flux. DATA delivers the next value. RESOLVED is the third outcome: I was part of that pending wave, and I have nothing new to ship.

If that sounds like a small detail, try implementing multi-dep operators without it. Every convergence node tracks which dependencies were dirty. When the last pending bit clears, the node must either emit or explicitly settle the wave. Silence is not neutral — silence is a stuck bitmask and a downstream graph waiting forever.

What RESOLVED means mechanically

  • Send RESOLVED only after you participated in the current dirty cycle (you forwarded DIRTY, or you are absorbing a branch of the wave).
  • Never send RESOLVED “cold” without a matching DIRTY story — it is not a generic heartbeat.
  • When equals(prev, next) is true after a derived recompute, we do not emit duplicate DATA. We send RESOLVED so parents and siblings can clear their dirty state without redoing heavy work.

That last point is where subtree skipping comes from. Push-phase memoization is not only “avoid allocating a new object.” It is avoid waking children when the mathematical output is unchanged — and RESOLVED is the message that carries that decision through the same protocol as DIRTY/DATA.

Diamond resolution stays glued together

At a join node, multiple upstream branches can go dirty. The bitmask waits until all relevant deps have reported DATA or RESOLVED. Only then does the join recompute — and if its own output is unchanged, it can RESOLVED in turn. The cascade matches the phase-one / phase-two story from v2, but with an explicit no-value completion on STATE instead of inferring it from absence.

Why “just filter out emissions” was not enough

Pull-time equality after compute still paid for the compute. v3’s goal was to make “no change” a first-class push decision, visible to the graph: downstream sees RESOLVED, not silence, not a duplicate value.

Further reading


Next: Five primitives, two tiers, zero schedulers.

Released under the MIT License.