Skip to content

13.2 What a rule may say — the validated fragment

Validation at install time enforces the fragment that makes hosted rules safe — each restriction is a leg of the guarantee that evaluation terminates:

You may You may not
conclude a label or a relationship, with derived properties write the graph (CREATE/MERGE/SET/DELETE in a body)
reference the derived label positively — recursion, any(…), EXISTS reference it under a negation: NOT, or the quantifiers none(…) / all(…) / single(…)
aggregate in recursion with sum / count / max / collect use min / avg / percentiles inside recursion
reference other labels, views and virtual joins as usual RETURN in a body — the head is the projection
reference declared params as $name reference a param the set does not declare
conclude the same kind in every rule of a set mix a node head and a relationship head — one fixpoint cannot be both
declare requires: to bring the facts in first (§13.6) write the graph in a demand — it is read-only like a body

none(…) is NOT any(…), and both all(…) and single(…) can be falsified by a member a later round adds — all three are the same non-monotone self-reference as NOT, whatever they look like, so all three are refused. Say it the monotone way instead: any(…) and EXISTS only become more true as membership grows, which is exactly what the fixpoint needs.

The rule is monotonicity, not the word NOT, and it is checked position by position: a reference to the derived label must sit where a new member can only make the body MORE true. A negation in any other spelling is refused the same way — a count compared from above (size([x IN xs WHERE x:Derived]) = 0, COUNT { (p)-[:R]->(:Derived) } <= 3), a CASE that inverts the label, an OPTIONAL MATCH of it followed by IS NULL, a SKIP/LIMIT a new member could push a row out of. Count members from below instead (>= n), or use any(…)/EXISTS; sum(CASE WHEN x:Derived THEN 1 ELSE 0 END) >= n is admitted because it only grows. Such a rule would otherwise settle at once on a set its own body contradicts, which the round cap cannot notice because nothing is still moving — so a body the host cannot prove monotone is refused rather than trusted.

A rule set that breaks the fragment fails validation with a message naming the rule and the property it broke; it never half-installs. A conforming set’s MEMBERSHIP is guaranteed to terminate: rules can only conclude over nodes that exist, membership only grows, and a growing subset of a finite set must stop growing. For a relationship set the finite set is the square of the node count, which is why it carries its own budget (maxPairs, §13.4) on top of the argument.

That argument is about membership, and it does not extend to a derived NUMERIC PROPERTY defined in terms of its own value on a neighbour. phoenixDepth above is one: it settles because appointment dates strictly increase, so the chain it climbs cannot close. On CYCLIC data — mutual blocks in a tracker, cross-holdings in an ownership graph, dependency cycles in a registry — two members lift each other by one every round and there is no ceiling for the fixpoint to stop at. The evaluation then fails loudly at its round cap, naming the property that would not settle and the rule that stamps it; it never truncates silently. Note that the aggregate is not what decides this — max cannot shrink as membership grows, so the fragment admits it, while a grounded min descending to a floor would converge and is refused; what bounds such a value is groundedness, which lives in your data and not in the rule. Conclude membership in the rule set and compute a distance in the projection view (§13.5), where min(length(p)) is finite because a path may not repeat a relationship.

A rule body’s labels are checked when the realm is validated. A body label that is a near miss for a known one (Compnay beside Company) is an error at the rule’s from, naming the likely intended label: a misspelled body matches nothing, so the rule would derive nothing and say nothing.