;; lib/mod/tests/trace.sx — Ext 9: policy dry-run diagnostics.

(define mod-tr-count 0)
(define mod-tr-pass 0)
(define mod-tr-fail 0)
(define mod-tr-failures (list))

(define
  mod-tr-test!
  (fn
    (name got expected)
    (begin
      (set! mod-tr-count (+ mod-tr-count 1))
      (if
        (= got expected)
        (set! mod-tr-pass (+ mod-tr-pass 1))
        (begin
          (set! mod-tr-fail (+ mod-tr-fail 1))
          (append!
            mod-tr-failures
            (str name "\n    expected: " expected "\n    got:      " got)))))))

(define
  mod-tr-find
  (fn
    (trace nm)
    (reduce (fn (acc t) (if (= (get t :rule) nm) t acc)) nil trace)))

;; ── trace a spam report against the default rules ──

(define mod-tr-spam (mod/mk-report "r1" "alice" "bob" "this is spam"))
(define
  mod-tr-t
  (mod/trace-rules mod-tr-spam (list mod-tr-spam) mod/default-rules))

(mod-tr-test! "trace covers every rule" (len mod-tr-t) 6)
(mod-tr-test!
  "spam-hide fires"
  (get (mod-tr-find mod-tr-t "spam-hide") :proved)
  true)
(mod-tr-test!
  "default-keep always fires"
  (get (mod-tr-find mod-tr-t "default-keep") :proved)
  true)
(mod-tr-test!
  "reviewer-remove does not fire (no evidence)"
  (get (mod-tr-find mod-tr-t "reviewer-remove") :proved)
  false)
(mod-tr-test!
  "exonerated-keep does not fire"
  (get (mod-tr-find mod-tr-t "exonerated-keep") :proved)
  false)
(mod-tr-test!
  "abuse-remove does not fire"
  (get (mod-tr-find mod-tr-t "abuse-remove") :proved)
  false)

;; ── winner matches the engine ──

(mod-tr-test!
  "first-proved is spam-hide"
  (get (mod/first-proved mod-tr-t) :rule)
  "spam-hide")
(mod-tr-test!
  "winner action matches decide-report"
  (get (mod/first-proved mod-tr-t) :action)
  (get
    (mod/decide-report mod-tr-spam (list mod-tr-spam) mod/default-rules)
    :action))

;; ── an unproved rule shows which goal failed ──

(define
  mod-tr-rev-goals
  (get (mod-tr-find mod-tr-t "reviewer-remove") :goals))
(mod-tr-test!
  "reviewer-remove goal is unsolved"
  (get (first mod-tr-rev-goals) :solved)
  false)
(define mod-tr-spam-goals (get (mod-tr-find mod-tr-t "spam-hide") :goals))
(mod-tr-test!
  "spam-hide goal is solved"
  (get (first mod-tr-spam-goals) :solved)
  true)

;; ── proved-rules list + rendering ──

(mod-tr-test!
  "proved-rules lists fired rules in order"
  (mod/proved-rules mod-tr-t)
  (list "spam-hide" "default-keep"))
(mod-tr-test!
  "trace-report marks a firing rule"
  (mod/str-contains? (mod/trace-report mod-tr-t) "[fires] spam-hide")
  true)
(mod-tr-test!
  "trace-report marks a non-firing rule"
  (mod/str-contains? (mod/trace-report mod-tr-t) "[  -  ] reviewer-remove")
  true)

;; ── clean report: only default-keep fires ──

(define mod-tr-clean (mod/mk-report "r2" "a" "b" "a fine post"))
(define
  mod-tr-tc
  (mod/trace-rules mod-tr-clean (list mod-tr-clean) mod/default-rules))
(mod-tr-test!
  "clean report: only default-keep proves"
  (mod/proved-rules mod-tr-tc)
  (list "default-keep"))
(mod-tr-test!
  "clean report winner is default-keep"
  (get (mod/first-proved mod-tr-tc) :rule)
  "default-keep")

(define mod-trace-tests-run! (fn () {:failures mod-tr-failures :total mod-tr-count :passed mod-tr-pass :failed mod-tr-fail}))
