8000 A rule calling a rule with not / not-join returns too few rows · Issue #628 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

A rule calling a rule with not / not-join returns too few rows #628

Closed

Description

@adityamukho

A rule that calls a rule with not / not-join in its body returns too few rows, often none. Calling the negated rule from the query works:

(transact [[:m1 :msg/actor :a1]
           [:r1 :run/actor :a1] [:r1 :run/to :s1]
           [:r2 :run/actor :a1] [:r2 :run/to :s2] [:r2 :run/done true]])
(rule [(cur ?a ?s) [?r :run/actor ?a] [?r :run/to ?s] (not-join [?r] [?r :run/done true])])
(rule [(st ?m ?s) [?m :msg/actor ?a] (cur ?a ?s)])

(query [:find ?m ?s :where [?m :msg/actor ?a] (cur ?a ?s)])
;; => :m1 :s1

(query [:find ?m ?s :where (st ?m ?s)])
;; expected: :m1 :s1
;; actual:   No results found.

The same happens with not in place of not-join, with a literal argument ((st :m1 ?s)), and with a rule that only forwards the call ((rule [(st3 ?a ?s) (cur ?a ?s)])). A rule calling a rule without negation is not affected.

Reproduces on v2.0.7 and on v3 (c501f549), in the REPL.

Cause

StratifiedEvaluator::evaluate (src/query/datalog/evaluator.rs) gives a positive dependency the same stratum as the rule it depends on, so st and cur share stratum 0. Within a stratum it then:

  1. runs the positive-only rules to a fixpoint (st here), then
  2. runs each mixed rule (not, not-join, or, or-join) once, in all_preds order (cur here).

So st is evaluated before any cur fact exists. When the caller is a mixed rule too, the order of all_preds decides: callers are listed before the rules they call, so the caller still runs first. Asking for the callee first in the query changes the answer:

(rule [(stm ?m ?s) [?m :msg/actor ?a] (cur ?a ?s) (not-join [?m] [?m :nope true])])
(query [:find ?m ?s :where (stm ?m ?s)])             ;; => No results found.
(query [:find ?m ?s :where (cur ?a ?x) (stm ?m ?s)]) ;; => :m1 :s1

The result is silently wrong, with no error.

Possible fix

Evaluate rules within a stratum in dependency order, so a rule runs only after every mixed rule it calls has finished. One way: in stratify(), treat a positive dependency on a mixed predicate like a negative one (dep_stratum + 1), so the callee always completes in a lower stratum. That also covers a mixed rule calling a mixed rule. Recursion through a mixed rule needs a separate look, since each mixed rule runs only once per stratum.

Found while

Writing the actor state use case for the docs (project-minigraf/minigraf-docs#36). The docs example uses a query in place of the rule to avoid this.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    known-issueBug present in a published release and not yet fixed in one; listed in the pinned known-issues issue
    on Oct 19, 2026
  2. added this to the v3.0.0 milestone on Oct 19, 2026
  3. adityamukho commented on Oct 19, 2026

    @adityamukho
    CollaboratorAuthor

    Fixed on v3 in #631 (224c290) and on main in #634, for the next v2.0.x patch. The fix puts a rule in a stratum above any rule with not / not-join / or / or-join that it calls, unless the two call each other. Recursion through such a rule is still broken and is tracked in #633. This issue stays open until the v2.x patch is released (support policy).

  4. added a commit that references this issue on Oct 20, 2026
  5. adityamukho commented on Oct 20, 2026

    @adityamukho
    CollaboratorAuthor

    Released in v2.0.8 (crates.io 2.0.8, 2026-10-20); also fixed on v3 for v3.0.0. Moved to "Fixed in v2.0.8" in #421.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdata-integrityData integrity issueknown-issueBug present in a published release and not yet fixed in one; listed in the pinned known-issues issue

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0