mod: Phase 2 — evidence accumulation + proof trees + audit log, 60/60
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m7s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m7s
Reports carry an :evidence list, asserted as evidence/3 facts; reviewer-remove rule (highest precedence) lets human review override classification. Proof tree built constructively by re-querying each rule body goal against the same DB with the report id bound, so derivations carry real unification bindings. Append-only audit log records decision + proof + evidence snapshot per decide, monotonic seq, never mutates prior entries. +29 audit tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
;; 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.
|
||||
;;
|
||||
;; cond->goal takes an id-term so the same condition can be compiled with the
|
||||
;; head variable "Id" (for clause bodies) or a concrete report id (for proof-tree
|
||||
;; goal-by-goal re-querying in the engine).
|
||||
|
||||
(define mod/mk-rule (fn (name action conds) {:when conds :name name :action action}))
|
||||
|
||||
@@ -15,6 +19,9 @@
|
||||
(define
|
||||
mod/default-rules
|
||||
(list
|
||||
(mod/mk-rule
|
||||
"reviewer-remove"
|
||||
:remove (list (list :evidence "confirmed-abuse")))
|
||||
(mod/mk-rule "spam-hide" :hide (list (list :classification "spam")))
|
||||
(mod/mk-rule
|
||||
"abuse-remove"
|
||||
@@ -27,31 +34,41 @@
|
||||
;; ── condition → Prolog goal ──
|
||||
;;
|
||||
;; (:classification "spam") → classification(Id, spam)
|
||||
;; (:evidence "kind") → evidence(Id, 'kind', _)
|
||||
;; (:count-at-least 3) → report(Id, B, S), report_count(S, N), N >= 3
|
||||
|
||||
(define
|
||||
mod/cond->goal
|
||||
(fn
|
||||
(c)
|
||||
(c idterm)
|
||||
(let
|
||||
((tag (first c)))
|
||||
(cond
|
||||
((= tag :classification)
|
||||
(str "classification(Id, " (nth c 1) ")"))
|
||||
(str "classification(" idterm ", " (nth c 1) ")"))
|
||||
((= tag :evidence)
|
||||
(str
|
||||
"evidence("
|
||||
idterm
|
||||
", "
|
||||
(mod/pl-quote (nth c 1))
|
||||
", _)"))
|
||||
((= tag :count-at-least)
|
||||
(str
|
||||
"report(Id, B, S), report_count(S, N), N >= "
|
||||
"report("
|
||||
idterm
|
||||
", B, S), report_count(S, N), N >= "
|
||||
(nth c 1)))
|
||||
(true "true")))))
|
||||
|
||||
(define
|
||||
mod/conds->body
|
||||
(fn
|
||||
(conds)
|
||||
(conds idterm)
|
||||
(if
|
||||
(empty? conds)
|
||||
"true"
|
||||
(mod/join-with ", " (map mod/cond->goal conds)))))
|
||||
(mod/join-with ", " (map (fn (c) (mod/cond->goal c idterm)) conds)))))
|
||||
|
||||
(define
|
||||
mod/rule->clause
|
||||
@@ -63,7 +80,7 @@
|
||||
", '"
|
||||
(mod/rule-name r)
|
||||
"') :- "
|
||||
(mod/conds->body (mod/rule-when r))
|
||||
(mod/conds->body (mod/rule-when r) "Id")
|
||||
".")))
|
||||
|
||||
(define
|
||||
|
||||
Reference in New Issue
Block a user