Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 55s
(:reporters-at-least N) compiles to setof(Br, report(_, Br, Sr), Bsr), length(Bsr, Nr), Nr >= N — counts distinct reporters, not raw reports. mod/decide-quorum asserts every report's report/3 fact (base engine scopes to the decided report) so Prolog can aggregate reporters. One user filing 3 reports stays :keep under quorum while the count rule escalates. Own suite. +9 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
120 lines
3.2 KiB
Plaintext
120 lines
3.2 KiB
Plaintext
;; 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}))
|