;; lib/mod/schema.sx — report representation + Prolog fact generation. ;; ;; A report is a dict {:id :by :about :reason}. The engine derives evidence ;; (classification kinds) from the reason text, then projects the report and its ;; evidence into Prolog facts that policy clauses can match against. (define mod/mk-report (fn (id by about reason) {:id id :by by :about about :reason reason})) (define mod/report-id (fn (r) (get r :id))) (define mod/report-by (fn (r) (get r :by))) (define mod/report-about (fn (r) (get r :about))) (define mod/report-reason (fn (r) (get r :reason))) ;; ── substring search (the prolog-loaded env lacks includes?; slice/len do work) ── (define mod/contains-at? (fn (hay needle hl nl pos) (if (< hl (+ pos nl)) false (if (= (slice hay pos (+ pos nl)) needle) true (mod/contains-at? hay needle hl nl (+ pos 1)))))) (define mod/str-contains? (fn (hay needle) (let ((hl (len hay)) (nl (len needle))) (if (= nl 0) true (mod/contains-at? hay needle hl nl 0))))) ;; ── evidence derivation (keyword classification) ── (define mod/spam-keywords (list "spam" "buy now" "click here" "free money" "viagra" "limited offer")) (define mod/abuse-keywords (list "abuse" "harassment" "threat" "slur" "hate speech")) (define mod/any? (fn (pred coll) (reduce (fn (acc x) (if acc acc (pred x))) false coll))) (define mod/reason-matches? (fn (reason kws) (let ((low (downcase reason))) (mod/any? (fn (k) (mod/str-contains? low k)) kws)))) (define mod/classify-keywords (fn (r) (let ((reason (mod/report-reason r)) (kinds (list))) (begin (when (mod/reason-matches? reason mod/spam-keywords) (append! kinds "spam")) (when (mod/reason-matches? reason mod/abuse-keywords) (append! kinds "abuse")) kinds)))) (define mod/report-count (fn (about reports) (reduce (fn (acc r) (if (= (mod/report-about r) about) (+ acc 1) acc)) 0 reports))) ;; ── Prolog fact projection ── (define mod/join-with (fn (sep items) (reduce (fn (acc x) (if (= acc "") x (str acc sep x))) "" items))) (define mod/pl-quote (fn (s) (str "'" s "'"))) (define mod/classification-facts (fn (id kinds) (mod/join-with "\n" (map (fn (k) (str "classification(" id ", " k ").")) kinds)))) (define mod/report-facts (fn (r count) (let ((id (mod/report-id r)) (by (mod/pl-quote (mod/report-by r))) (about (mod/pl-quote (mod/report-about r)))) (let ((cls (mod/classification-facts id (mod/classify-keywords r)))) (mod/join-with "\n" (list (str "report(" id ", " by ", " about ").") (str "report_count(" about ", " count ").") cls))))))