Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m5s
Reports → Prolog facts (report/3, classification/2, report_count/2); ordered policy rules compile to policy_action/3 clauses, first match wins via pl-query-one. Decisions carry their proof (matching rule + conditions + evidence). Spam/abuse keyword classification, repeated-report escalation via Prolog join+arithmetic, no-rule→keep default. Registry api + conformance harness. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72 lines
1.9 KiB
Plaintext
72 lines
1.9 KiB
Plaintext
;; lib/mod/policy.sx — moderation rules → Prolog clauses.
|
|
;;
|
|
;; A rule is {:name :action :when}. :when is a list of condition forms; each
|
|
;; compiles to a Prolog goal. Rule order is precedence: the engine queries with
|
|
;; pl-query-one, so the first clause that proves wins. The final default rule has
|
|
;; an empty body (true) so every report yields at least :keep — "no rule matched"
|
|
;; is a real result, not a query failure.
|
|
|
|
(define mod/mk-rule (fn (name action conds) {:when conds :name name :action action}))
|
|
|
|
(define mod/rule-name (fn (r) (get r :name)))
|
|
(define mod/rule-action (fn (r) (get r :action)))
|
|
(define mod/rule-when (fn (r) (get r :when)))
|
|
|
|
(define
|
|
mod/default-rules
|
|
(list
|
|
(mod/mk-rule "spam-hide" :hide (list (list :classification "spam")))
|
|
(mod/mk-rule
|
|
"abuse-remove"
|
|
:remove (list (list :classification "abuse")))
|
|
(mod/mk-rule
|
|
"repeated-escalate"
|
|
:escalate (list (list :count-at-least 3)))
|
|
(mod/mk-rule "default-keep" :keep (list))))
|
|
|
|
;; ── condition → Prolog goal ──
|
|
;;
|
|
;; (:classification "spam") → classification(Id, spam)
|
|
;; (:count-at-least 3) → report(Id, B, S), report_count(S, N), N >= 3
|
|
|
|
(define
|
|
mod/cond->goal
|
|
(fn
|
|
(c)
|
|
(let
|
|
((tag (first c)))
|
|
(cond
|
|
((= tag :classification)
|
|
(str "classification(Id, " (nth c 1) ")"))
|
|
((= tag :count-at-least)
|
|
(str
|
|
"report(Id, B, S), report_count(S, N), N >= "
|
|
(nth c 1)))
|
|
(true "true")))))
|
|
|
|
(define
|
|
mod/conds->body
|
|
(fn
|
|
(conds)
|
|
(if
|
|
(empty? conds)
|
|
"true"
|
|
(mod/join-with ", " (map mod/cond->goal conds)))))
|
|
|
|
(define
|
|
mod/rule->clause
|
|
(fn
|
|
(r)
|
|
(str
|
|
"policy_action(Id, "
|
|
(mod/rule-action r)
|
|
", '"
|
|
(mod/rule-name r)
|
|
"') :- "
|
|
(mod/conds->body (mod/rule-when r))
|
|
".")))
|
|
|
|
(define
|
|
mod/rules->program
|
|
(fn (rules) (mod/join-with "\n" (map mod/rule->clause rules))))
|