;; lib/mod/quorum.sx — quorum decisions over distinct reporters (anti-brigade).
;;
;; The base engine asserts only the decided report's report/3 fact, so it can't
;; reason about WHO reported a subject. The quorum engine additionally asserts
;; every report's report/3 fact (via link's rel-facts), letting a rule require N
;; *distinct* reporters with `setof`/`length` — so one user filing many reports
;; does not manufacture consensus. Same decision shape as the base engine, plus
;; :strategy "quorum".

(define
  mod/build-quorum-program
  (fn
    (r count reports rules)
    (str
      (mod/report-rel-facts reports)
      "\n"
      (mod/report-facts r count)
      "\n"
      (mod/rules->program rules))))

(define
  mod/decide-quorum
  (fn
    (r reports rules)
    (let
      ((count (mod/report-count (mod/report-about r) reports))
        (kinds (mod/classify-keywords r))
        (id (mod/report-id r)))
      (let
        ((program (mod/build-quorum-program r count reports rules)))
        (let
          ((db (pl-load program)))
          (let
            ((sol (pl-query-one db (str "policy_action(" id ", Action, Rule)"))))
            (if
              (nil? sol)
              {:action "keep" :proof {:goals (list) :evidence kinds :conditions (list) :rule "none" :count count} :report-id id :rule "none" :strategy "quorum"}
              (let
                ((rule (mod/find-rule rules (dict-get sol "Rule"))))
                {:action (mod/rule-action rule) :proof {:goals (mod/proof-goals db id (mod/rule-when rule)) :evidence kinds :conditions (mod/rule-when rule) :rule (mod/rule-name rule) :count count} :report-id id :rule (mod/rule-name rule) :strategy "quorum"}))))))))
