;; lib/mod/batch.sx — batch triage + corpus analytics.
;;
;; Operational layer: decide a whole queue of reports at once, summarize the
;; outcomes by action, and measure which rules actually fire across a corpus.
;; mod/never-fired is the empirical complement to lint's static unreachable check
;; (Ext 5): lint finds rules that CAN'T fire by structure; never-fired finds rules
;; that DIDN'T fire on real data.

(define
  mod/decide-batch
  (fn
    (reports rules)
    (map (fn (r) (mod/decide-report r reports rules)) reports)))

(define
  mod/count-action
  (fn
    (decisions action)
    (reduce
      (fn (acc d) (if (= (get d :action) action) (+ acc 1) acc))
      0
      decisions)))

(define mod/action-histogram (fn (decisions) {:keep (mod/count-action decisions "keep") :remove (mod/count-action decisions "remove") :escalate (mod/count-action decisions "escalate") :hide (mod/count-action decisions "hide") :ban (mod/count-action decisions "ban")}))

(define
  mod/rule-fire-count
  (fn
    (decisions rule-name)
    (reduce
      (fn (acc d) (if (= (get d :rule) rule-name) (+ acc 1) acc))
      0
      decisions)))

(define
  mod/rule-coverage
  (fn
    (reports rules)
    (let
      ((decisions (mod/decide-batch reports rules)))
      (map (fn (rule) {:rule (mod/rule-name rule) :fired (mod/rule-fire-count decisions (mod/rule-name rule))}) rules))))

(define
  mod/never-fired
  (fn
    (reports rules)
    (reduce
      (fn
        (acc c)
        (if
          (= (get c :fired) 0)
          (append acc (list (get c :rule)))
          acc))
      (list)
      (mod/rule-coverage reports rules))))
