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:
@@ -1,16 +1,34 @@
|
||||
;; 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.
|
||||
;; A report is a dict {:id :by :about :reason :evidence}. :evidence is a list of
|
||||
;; accumulated evidence entries {:kind :val} (human review, automated scanners,
|
||||
;; etc.). The engine derives keyword classifications from the reason text and
|
||||
;; projects the report, its classifications, and its accumulated evidence into
|
||||
;; Prolog facts that policy clauses match against.
|
||||
|
||||
(define mod/mk-report (fn (id by about reason) {:id id :by by :about about :reason reason}))
|
||||
(define mod/mk-report (fn (id by about reason) {:id id :by by :evidence (list) :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)))
|
||||
|
||||
(define
|
||||
mod/report-evidence
|
||||
(fn (r) (let ((e (get r :evidence))) (if (nil? e) (list) e))))
|
||||
|
||||
(define mod/mk-evidence (fn (kind val) {:val val :kind kind}))
|
||||
(define mod/evidence-kind (fn (e) (get e :kind)))
|
||||
(define mod/evidence-val (fn (e) (get e :val)))
|
||||
|
||||
(define mod/with-evidence (fn (r evs) {:id (mod/report-id r) :by (mod/report-by r) :evidence evs :about (mod/report-about r) :reason (mod/report-reason r)}))
|
||||
|
||||
(define
|
||||
mod/attach-evidence
|
||||
(fn
|
||||
(r e)
|
||||
(mod/with-evidence r (append (mod/report-evidence r) (list e)))))
|
||||
|
||||
;; ── substring search (the prolog-loaded env lacks includes?; slice/len do work) ──
|
||||
|
||||
(define
|
||||
@@ -102,6 +120,25 @@
|
||||
"\n"
|
||||
(map (fn (k) (str "classification(" id ", " k ").")) kinds))))
|
||||
|
||||
(define
|
||||
mod/evidence-facts
|
||||
(fn
|
||||
(id evs)
|
||||
(mod/join-with
|
||||
"\n"
|
||||
(map
|
||||
(fn
|
||||
(e)
|
||||
(str
|
||||
"evidence("
|
||||
id
|
||||
", "
|
||||
(mod/pl-quote (mod/evidence-kind e))
|
||||
", "
|
||||
(mod/pl-quote (str (mod/evidence-val e)))
|
||||
")."))
|
||||
evs))))
|
||||
|
||||
(define
|
||||
mod/report-facts
|
||||
(fn
|
||||
@@ -111,10 +148,12 @@
|
||||
(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))))
|
||||
((cls (mod/classification-facts id (mod/classify-keywords r)))
|
||||
(evs (mod/evidence-facts id (mod/report-evidence r))))
|
||||
(mod/join-with
|
||||
"\n"
|
||||
(list
|
||||
(str "report(" id ", " by ", " about ").")
|
||||
(str "report_count(" about ", " count ").")
|
||||
cls))))))
|
||||
cls
|
||||
evs))))))
|
||||
|
||||
Reference in New Issue
Block a user