;; lib/mod/tests/escalation.sx — Phase 3: lifecycle state machine + escalation. (define mod-esc-count 0) (define mod-esc-pass 0) (define mod-esc-fail 0) (define mod-esc-failures (list)) (define mod-esc-test! (fn (name got expected) (begin (set! mod-esc-count (+ mod-esc-count 1)) (if (= got expected) (set! mod-esc-pass (+ mod-esc-pass 1)) (begin (set! mod-esc-fail (+ mod-esc-fail 1)) (append! mod-esc-failures (str name "\n expected: " expected "\n got: " got))))))) ;; ── transition table guard ── (mod-esc-test! "open → triaged allowed" (mod/lc-can-transition? "open" "triaged") true) (mod-esc-test! "triaged → decided allowed" (mod/lc-can-transition? "triaged" "decided") true) (mod-esc-test! "decided → appealed allowed" (mod/lc-can-transition? "decided" "appealed") true) (mod-esc-test! "appealed → final allowed" (mod/lc-can-transition? "appealed" "final") true) (mod-esc-test! "open → decided rejected" (mod/lc-can-transition? "open" "decided") false) (mod-esc-test! "triaged → final rejected" (mod/lc-can-transition? "triaged" "final") false) (mod-esc-test! "final is terminal" (mod/lc-can-transition? "final" "open") false) ;; ── initial state ── (define mod-esc-c0 (mod/mk-case (mod/mk-report "r1" "alice" "bob" "this is spam"))) (mod-esc-test! "new case is open" (mod/case-state mod-esc-c0) "open") (mod-esc-test! "new case has no decision" (mod/case-decision mod-esc-c0) nil) ;; ── auto-tier: spam triages + resolves to decided/hide ── (define mod-esc-spam-rep (list (mod/mk-report "r1" "alice" "bob" "this is spam"))) (define mod-esc-t1 (mod/case-triage mod-esc-c0 mod-esc-spam-rep mod/default-rules)) (mod-esc-test! "spam triaged" (mod/case-state mod-esc-t1) "triaged") (mod-esc-test! "spam triage tier auto" (mod/case-tier mod-esc-t1) "auto") (mod-esc-test! "spam triage action hide" (mod/case-action mod-esc-t1) "hide") (define mod-esc-r1 (mod/case-resolve mod-esc-t1)) (mod-esc-test! "auto resolve → decided" (mod/case-state mod-esc-r1) "decided") (mod-esc-test! "decision preserved through resolve" (mod/case-action mod-esc-r1) "hide") ;; ── illegal transition flags :error, leaves state ── (define mod-esc-bad (mod/case-finalize mod-esc-c0)) (mod-esc-test! "finalize from open is illegal" (mod/case-state mod-esc-bad) "open") (mod-esc-test! "illegal transition sets error" (nil? (mod/case-error mod-esc-bad)) false) ;; ── human-tier: repeated report escalates, resolve blocked, review decides ── (define mod-esc-rep-r (mod/mk-report "r3" "ann" "dave" "off-topic")) (define mod-esc-rep-reports (list mod-esc-rep-r mod-esc-rep-r mod-esc-rep-r)) (define mod-esc-rep-c0 (mod/mk-case mod-esc-rep-r)) (define mod-esc-rep-t (mod/case-triage mod-esc-rep-c0 mod-esc-rep-reports mod/default-rules)) (mod-esc-test! "repeated triage action escalate" (mod/case-action mod-esc-rep-t) "escalate") (mod-esc-test! "repeated triage tier human" (mod/case-tier mod-esc-rep-t) "human") (mod-esc-test! "repeated still triaged after triage" (mod/case-state mod-esc-rep-t) "triaged") (define mod-esc-rep-block (mod/case-resolve mod-esc-rep-t)) (mod-esc-test! "auto-resolve blocked on human tier (state unchanged)" (mod/case-state mod-esc-rep-block) "triaged") (mod-esc-test! "blocked resolve sets error" (nil? (mod/case-error mod-esc-rep-block)) false) (define mod-esc-rep-rev (mod/case-review mod-esc-rep-t "confirmed-abuse" "human" mod-esc-rep-reports mod/default-rules)) (mod-esc-test! "human review → decided" (mod/case-state mod-esc-rep-rev) "decided") (mod-esc-test! "human review action remove" (mod/case-action mod-esc-rep-rev) "remove") (mod-esc-test! "review attached evidence to report" (len (mod/report-evidence (mod/case-report mod-esc-rep-rev))) 1) (define mod-esc-rep-final (mod/case-finalize mod-esc-rep-rev)) (mod-esc-test! "review case finalizes" (mod/case-state mod-esc-rep-final) "final") ;; ── appeal overrides a prior decision ── (define mod-esc-ap-c0 (mod/mk-case (mod/mk-report "r5" "u" "v" "buy now spam"))) (define mod-esc-ap-rep (list (mod/mk-report "r5" "u" "v" "buy now spam"))) (define mod-esc-ap-t (mod/case-triage mod-esc-ap-c0 mod-esc-ap-rep mod/default-rules)) (define mod-esc-ap-d (mod/case-resolve mod-esc-ap-t)) (mod-esc-test! "appeal precondition decided/hide" (mod/case-action mod-esc-ap-d) "hide") (define mod-esc-ap-appealed (mod/case-appeal mod-esc-ap-d "exonerated" "moderator" mod-esc-ap-rep mod/default-rules)) (mod-esc-test! "appeal → appealed state" (mod/case-state mod-esc-ap-appealed) "appealed") (mod-esc-test! "appeal overrides hide → keep" (mod/case-action mod-esc-ap-appealed) "keep") (mod-esc-test! "appeal recorded via exonerated-keep rule" (get (mod/case-decision mod-esc-ap-appealed) :rule) "exonerated-keep") (define mod-esc-ap-final (mod/case-finalize mod-esc-ap-appealed)) (mod-esc-test! "appealed → final" (mod/case-state mod-esc-ap-final) "final") ;; ── history records the full traversal ── (mod-esc-test! "full lifecycle history length 4 (triage,resolve,appeal,finalize)" (len (mod/case-history mod-esc-ap-final)) 4) (mod-esc-test! "first history step open→triaged" (get (first (mod/case-history mod-esc-ap-final)) :to) "triaged") (mod-esc-test! "last history step → final" (get (nth (mod/case-history mod-esc-ap-final) 3) :to) "final") ;; ── api-level lifecycle façade ── (mod/reset!) (mod/report "alice" "bob" "this is spam") (mod/report "carol" "dave" "off-topic") (mod/report "carol" "dave" "off-topic") (mod/report "carol" "dave" "off-topic") (mod-esc-test! "api: case opens at open" (mod/case-state (mod/case-of "r1")) "open") (define mod-esc-api-t1 (mod/triage "r1")) (mod-esc-test! "api: triage spam → triaged" (mod/case-state mod-esc-api-t1) "triaged") (mod-esc-test! "api: triage spam action hide" (mod/case-action mod-esc-api-t1) "hide") (define mod-esc-api-r1 (mod/resolve "r1")) (mod-esc-test! "api: resolve → decided" (mod/case-state mod-esc-api-r1) "decided") (mod-esc-test! "api: resolve logged decision" (len (mod/audit "r1")) 1) (define mod-esc-api-app (mod/appeal "r1" "exonerated" "mod")) (mod-esc-test! "api: appeal → appealed" (mod/case-state mod-esc-api-app) "appealed") (mod-esc-test! "api: appeal overrides → keep" (mod/case-action mod-esc-api-app) "keep") (mod-esc-test! "api: appeal logged second decision" (len (mod/audit "r1")) 2) (mod-esc-test! "api: finalize → final" (mod/case-state (mod/finalize "r1")) "final") ;; r4 is the 3rd report about dave → escalates via the human tier (define mod-esc-api-t4 (mod/triage "r4")) (mod-esc-test! "api: repeated triage escalates (human tier)" (mod/case-tier mod-esc-api-t4) "human") (define mod-esc-api-blk (mod/resolve "r4")) (mod-esc-test! "api: escalated resolve blocked" (mod/case-state mod-esc-api-blk) "triaged") (define mod-esc-api-rev (mod/review "r4" "confirmed-abuse" "human")) (mod-esc-test! "api: review → decided/remove" (mod/case-action mod-esc-api-rev) "remove") (mod-esc-test! "api: unknown id → nil" (mod/triage "r99") nil) (define mod-escalation-tests-run! (fn () {:failures mod-esc-failures :total mod-esc-count :passed mod-esc-pass :failed mod-esc-fail}))