Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 55s
Cross-instance reports ingest into the local registry with origin tags; the engine decides them unchanged. Decision sharing pushes to a mock fed-sx outbox (mod/fed-send! is the transport seam). Trust is advisory by default: a peer's decision binds locally only under (mod/trusted? peer :mod), else it lands in the advisory log unapplied. Revocation composes with the Phase-2 proof model — fed-revoke-if-invalidated re-runs the engine and undoes moderation only when the action no longer holds (exoneration flips hide→keep → revoked + origin notified). +26 fed tests. Full mod-on-sx roadmap complete. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
155 lines
4.6 KiB
Plaintext
155 lines
4.6 KiB
Plaintext
;; lib/mod/tests/fed.sx — Phase 4: federation (mock fed-sx).
|
|
|
|
(define mod-fed-count 0)
|
|
(define mod-fed-pass 0)
|
|
(define mod-fed-fail 0)
|
|
(define mod-fed-failures (list))
|
|
|
|
(define
|
|
mod-fed-test!
|
|
(fn
|
|
(name got expected)
|
|
(begin
|
|
(set! mod-fed-count (+ mod-fed-count 1))
|
|
(if
|
|
(= got expected)
|
|
(set! mod-fed-pass (+ mod-fed-pass 1))
|
|
(begin
|
|
(set! mod-fed-fail (+ mod-fed-fail 1))
|
|
(append!
|
|
mod-fed-failures
|
|
(str name "\n expected: " expected "\n got: " got)))))))
|
|
|
|
(mod/reset!)
|
|
(mod/fed-reset!)
|
|
|
|
;; ── trust model (advisory by default) ──
|
|
|
|
(mod-fed-test! "trust initially false" (mod/trusted? "peerA" :mod) false)
|
|
(mod/grant-trust "peerA" :mod)
|
|
(mod-fed-test! "trust after grant" (mod/trusted? "peerA" :mod) true)
|
|
(mod-fed-test! "trust wrong scope" (mod/trusted? "peerA" :other) false)
|
|
(mod-fed-test! "trust other peer" (mod/trusted? "peerB" :mod) false)
|
|
(mod/revoke-trust "peerA" :mod)
|
|
(mod-fed-test! "trust after revoke" (mod/trusted? "peerA" :mod) false)
|
|
|
|
;; ── cross-instance reports ──
|
|
|
|
(define
|
|
mod-fed-fr
|
|
(mod/fed-receive-report "peerB" "alice" "bob" "this is spam"))
|
|
(mod-fed-test! "fed report assigned id r1" (mod/report-id mod-fed-fr) "r1")
|
|
(mod-fed-test! "fed report origin is peer" (mod/report-origin "r1") "peerB")
|
|
(define mod-fed-local (mod/report "carol" "dave" "fine post"))
|
|
(mod-fed-test!
|
|
"local report origin is local"
|
|
(mod/report-origin (mod/report-id mod-fed-local))
|
|
"local")
|
|
(mod-fed-test!
|
|
"engine decides fed report (spam → hide)"
|
|
(get
|
|
(mod/decide-report mod-fed-fr (list mod-fed-fr) mod/default-rules)
|
|
:action)
|
|
"hide")
|
|
|
|
;; ── decision sharing (outbox) ──
|
|
|
|
(define mod-fed-dec {:action "hide" :rule "spam-hide" :report-id "r1"})
|
|
(define
|
|
mod-fed-shared
|
|
(mod/fed-share-decision mod-fed-dec (list "peerB" "peerC")))
|
|
(mod-fed-test! "share returns notified peers" (len mod-fed-shared) 2)
|
|
(mod-fed-test! "outbox has two messages" (len (mod/fed-outbox)) 2)
|
|
(mod-fed-test!
|
|
"outbox message type decision"
|
|
(get (first (mod/fed-outbox)) :type)
|
|
"decision")
|
|
(mod-fed-test!
|
|
"outbox message addressed to peer"
|
|
(get (first (mod/fed-outbox)) :to)
|
|
"peerB")
|
|
|
|
;; ── receiving a peer decision: advisory unless trusted ──
|
|
|
|
(define mod-fed-untrusted (mod/fed-receive-decision "peerZ" {:action "remove" :rule "reviewer-remove" :report-id "rx"}))
|
|
(mod-fed-test!
|
|
"untrusted decision not applied"
|
|
(get mod-fed-untrusted :applied)
|
|
false)
|
|
(mod-fed-test!
|
|
"untrusted decision advisory"
|
|
(get mod-fed-untrusted :advisory)
|
|
true)
|
|
(mod-fed-test!
|
|
"untrusted decision absent from applied log"
|
|
(mod/fed-applied-action "rx")
|
|
nil)
|
|
(mod-fed-test!
|
|
"advisory log records suggestion"
|
|
(len mod/*fed-advisory*)
|
|
1)
|
|
|
|
(mod/grant-trust "peerT" :mod)
|
|
(define mod-fed-trusted (mod/fed-receive-decision "peerT" {:action "hide" :rule "spam-hide" :report-id "ry"}))
|
|
(mod-fed-test! "trusted decision applied" (get mod-fed-trusted :applied) true)
|
|
(mod-fed-test!
|
|
"trusted decision binds locally"
|
|
(get (mod/fed-applied-action "ry") :action)
|
|
"hide")
|
|
|
|
;; ── revocation ──
|
|
|
|
(mod-fed-test!
|
|
"applied action not yet revoked"
|
|
(get (mod/fed-applied-action "ry") :revoked)
|
|
false)
|
|
(mod/fed-revoke! "ry" "manual")
|
|
(mod-fed-test!
|
|
"revoke marks applied action revoked"
|
|
(get (mod/fed-applied-action "ry") :revoked)
|
|
true)
|
|
(mod-fed-test!
|
|
"revoke emits a revocation message"
|
|
(mod/any? (fn (m) (= (get m :type) "revocation")) (mod/fed-outbox))
|
|
true)
|
|
|
|
;; revoke-if-invalidated: proof still holds → no revocation
|
|
(define mod-fed-spam-r (mod/mk-report "rs" "a" "b" "this is spam"))
|
|
(define
|
|
mod-fed-spam-d
|
|
(mod/decide-report mod-fed-spam-r (list mod-fed-spam-r) mod/default-rules))
|
|
(mod-fed-test! "spam decision is hide" (get mod-fed-spam-d :action) "hide")
|
|
(define
|
|
mod-fed-rev-same
|
|
(mod/fed-revoke-if-invalidated
|
|
mod-fed-spam-r
|
|
mod-fed-spam-d
|
|
(list mod-fed-spam-r)
|
|
mod/default-rules))
|
|
(mod-fed-test!
|
|
"valid proof → not revoked"
|
|
(get mod-fed-rev-same :revoked)
|
|
false)
|
|
|
|
;; exoneration invalidates the proof → revocation
|
|
(define
|
|
mod-fed-exon-r
|
|
(mod/attach-evidence mod-fed-spam-r (mod/mk-evidence "exonerated" "mod")))
|
|
(define
|
|
mod-fed-rev-inv
|
|
(mod/fed-revoke-if-invalidated
|
|
mod-fed-exon-r
|
|
mod-fed-spam-d
|
|
(list mod-fed-exon-r)
|
|
mod/default-rules))
|
|
(mod-fed-test!
|
|
"invalidated proof → revoked"
|
|
(get mod-fed-rev-inv :revoked)
|
|
true)
|
|
(mod-fed-test!
|
|
"re-decision after exoneration is keep"
|
|
(get (get mod-fed-rev-inv :decision) :action)
|
|
"keep")
|
|
|
|
(define mod-fed-tests-run! (fn () {:failures mod-fed-failures :total mod-fed-count :passed mod-fed-pass :failed mod-fed-fail}))
|