Pure DAG construction: a list of ReactiveDag.Cell → a ReactiveDag.Plan.
No live data — only the plan (cells, parent edges, depths). Validates that
every referenced input exists and the graph is acyclic (raises ArgumentError
on a dangling input or cycle; a host's DSL transformer should catch these at
compile time, but the runtime builder re-checks so a hand-built plan can't
wedge a cascade).
Summary
Functions
What each parent CLAIMS when child's keys change, applying the key rule
each parent DECLARED. The rule sees the parent, the specific child input, and
the changed keys, and returns :all (whole-cell recompute, the "*"
wildcard) or {:keys, mapped}.
Functions
@spec build([ReactiveDag.Cell.t()]) :: ReactiveDag.Plan.t()
@spec claims_for( ReactiveDag.Plan.t(), ReactiveDag.Cell.id(), [String.t()], module(), map() ) :: [ {ReactiveDag.Cell.id(), [String.t()]} ]
What each parent CLAIMS when child's keys change, applying the key rule
each parent DECLARED. The rule sees the parent, the specific child input, and
the changed keys, and returns :all (whole-cell recompute, the "*"
wildcard) or {:keys, mapped}.
Returns [{parent_id, [key]}]. key_rule defaults to
ReactiveDag.Node.KeyRule, which reads :identity | :all | :group off the
authored block — a cascade always uses that one, and the parameter exists so
a host calling this directly gets the same answer.
A rule that returns anything outside its contract is answered :all and
logged, rather than passed on: an out-of-contract value used to travel into
the walk and fail several frames away, naming neither the rule nor the edge.
diffs maps a changed key to the DIFF of that change — both sides, as
captured by the payload write that produced it. A rule implementing rule/4
receives it and can derive a claim from a row that no longer exists; one
implementing only rule/3 is called exactly as before.