datalog: rule-shape validators in dl-add-rule! (253/253)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 43s

Two malformed-rule paths used to slip through:

- Empty head list `{:head () :body ()}` was accepted; the rule
  would never fire but the relation-name lookup later returned
  nil with confusing downstream errors.
- Non-list body (`{:head (...) :body 42}`) crashed in `rest`
  during safety check with a cryptic "rest: 1 list arg".

dl-add-rule! now checks head shape (non-empty list with symbol
head) and body type (list) before any safety walk. Errors are
descriptive and surface at add time rather than during the next
saturation.

2 new eval tests.
This commit is contained in:
2026-05-10 21:09:33 +00:00
parent 5bcda5c88c
commit 96c9e90743
4 changed files with 31 additions and 6 deletions

View File

@@ -318,6 +318,15 @@
(error (str "dl-add-rule!: expected rule dict, got " rule)))
((not (has-key? rule :head))
(error (str "dl-add-rule!: rule missing :head, got " rule)))
((not (and (list? (get rule :head))
(> (len (get rule :head)) 0)
(symbol? (first (get rule :head)))))
(error (str "dl-add-rule!: head must be a non-empty list "
"starting with a relation-name symbol, got "
(get rule :head))))
((not (list? (if (has-key? rule :body) (get rule :body) (list))))
(error (str "dl-add-rule!: body must be a list of literals, got "
(get rule :body))))
((dl-reserved-rel? (dl-rel-name (get rule :head)))
(error (str "dl-add-rule!: '" (dl-rel-name (get rule :head))
"' is a reserved name (built-in / aggregate / negation)")))