;; lib/mod/tests/quorum.sx — Ext 8: quorum over distinct reporters.

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

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

(define
  mod-q-rules
  (list
    (mod/mk-rule
      "quorum-hide"
      :hide (list (list :reporters-at-least 2)))
    (mod/mk-rule "default-keep" :keep (list))))

;; ── two distinct reporters meet quorum ──

(define
  mod-q-two
  (list
    (mod/mk-report "r1" "alice" "bob" "off-topic")
    (mod/mk-report "r2" "carol" "bob" "off-topic")))

(mod-q-test!
  "two distinct reporters → hide"
  (get (mod/decide-quorum (first mod-q-two) mod-q-two mod-q-rules) :action)
  "hide")
(mod-q-test!
  "quorum decision names the rule"
  (get (mod/decide-quorum (first mod-q-two) mod-q-two mod-q-rules) :rule)
  "quorum-hide")
(mod-q-test!
  "quorum decision tagged strategy"
  (get (mod/decide-quorum (first mod-q-two) mod-q-two mod-q-rules) :strategy)
  "quorum")

;; ── single reporter does not meet quorum ──

(define mod-q-one (list (mod/mk-report "r1" "alice" "bob" "off-topic")))
(mod-q-test!
  "one reporter → keep (below quorum)"
  (get (mod/decide-quorum (first mod-q-one) mod-q-one mod-q-rules) :action)
  "keep")

;; ── anti-brigade: one user filing many reports does NOT meet quorum ──

(define
  mod-q-brigade
  (list
    (mod/mk-report "r1" "alice" "bob" "off-topic")
    (mod/mk-report "r2" "alice" "bob" "off-topic")
    (mod/mk-report "r3" "alice" "bob" "off-topic")))

(mod-q-test!
  "three reports, one reporter → keep (quorum counts distinct)"
  (get
    (mod/decide-quorum (first mod-q-brigade) mod-q-brigade mod-q-rules)
    :action)
  "keep")

;; contrast: the count rule WOULD fire on the same brigade (3 reports ≥ 3) —
;; quorum is strictly stronger against single-actor brigading
(mod-q-test!
  "count rule fires on the brigade (distinct from quorum)"
  (get
    (mod/decide-report (first mod-q-brigade) mod-q-brigade mod/default-rules)
    :action)
  "escalate")

;; ── three distinct reporters ──

(define
  mod-q-three
  (list
    (mod/mk-report "r1" "alice" "bob" "off-topic")
    (mod/mk-report "r2" "carol" "bob" "off-topic")
    (mod/mk-report "r3" "dave" "bob" "off-topic")))

(mod-q-test!
  "three distinct reporters → hide"
  (get
    (mod/decide-quorum (first mod-q-three) mod-q-three mod-q-rules)
    :action)
  "hide")
(mod-q-test!
  "quorum proof goal solved"
  (get
    (first
      (get
        (get
          (mod/decide-quorum (first mod-q-three) mod-q-three mod-q-rules)
          :proof)
        :goals))
    :solved)
  true)

;; ── cond->goal compiles :reporters-at-least ──

(mod-q-test!
  "cond->goal :reporters-at-least"
  (mod/cond->goal (list :reporters-at-least 2) "Id")
  "report(Id, _, Sr), setof(Br, report(_, Br, Sr), Bsr), length(Bsr, Nr), Nr >= 2")

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