Files
GMW/services/discord-gateway/tests/nicknameEnforcement.test.ts
T
asepharyana 85204ca6f0 fix(moderation): enforcement safety net — username-only offense never auto-deleted
Even with the prompt firewall (username vs content), the LLM can still
occasionally mis-apply a content-level zero-tolerance flag (sara /
conflict_instigation) to a message whose ONLY violation is the username
(e.g. 'matikanetanyahu'). The auto-delete eligibility check only recognized
exact offensive_username flags, so such false positives still deleted the
message.

Add a belt-and-suspenders guard in isNicknameOnlyViolation: if the flag set
is entirely username-attributable (offensive_username/sara/conflict_instigation)
AND the analysis text corroborates that the violation is username-only with
clean message content, route to nickname-reset instead of message deletion.

Adds 6 test cases covering the real matikanetanyahu scenario and the
false-positive/negative boundaries.
2026-09-03 20:39:17 +07:00

118 lines
4.4 KiB
TypeScript

// ═══════════════════════════════════════════════════════════════════════════
// Nickname-only enforcement — offensive username flag handling (pure, no DB)
// ═══════════════════════════════════════════════════════════════════════════
import { describe, expect, it } from "vitest";
import {
isNicknameOnlyViolation,
parseModerationFlags,
} from "../src/modules/ai-moderation/autoDeleteEligibility.js";
import type {
AnalysisResult,
MessageRecord,
} from "../src/modules/message-capture/types.js";
function msg(
flagsJson: string | null,
analysis?: string | null,
): MessageRecord {
return {
id: "m1",
guild_id: "g1",
channel_id: "c1",
thread_id: null,
user_id: "u1",
username: "user1",
avatar_url: null,
content: "halo semua",
edited_content: null,
created_at: Date.now(),
edited_at: null,
deleted_at: null,
type: "text",
is_reply: null,
is_forward: null,
is_crosspost: null,
reference_message_id: null,
reference_channel_id: null,
reference_guild_id: null,
metadata: null,
ai_moderation_flags: flagsJson,
ai_analysis: analysis ?? null,
};
}
describe("parseModerationFlags", () => {
it("parses JSON array from stored column", () => {
expect(parseModerationFlags(msg('["offensive_username","sara"]'))).toEqual([
"offensive_username",
"sara",
]);
});
it("returns [] for null / malformed values", () => {
expect(parseModerationFlags(msg(null))).toEqual([]);
expect(parseModerationFlags(msg("not-json"))).toEqual([]);
});
it("prefers structured analysisResult flags", () => {
const result = { flags: ["vulgar_language"] } as AnalysisResult;
expect(parseModerationFlags(msg('["old_flag"]'), result)).toEqual([
"vulgar_language",
]);
});
});
describe("isNicknameOnlyViolation", () => {
it("true when the ONLY flag is offensive_username", () => {
expect(isNicknameOnlyViolation(msg('["offensive_username"]'))).toBe(true);
});
it("false when other flags ride along (message itself violated)", () => {
expect(isNicknameOnlyViolation(msg('["offensive_username","sara"]'))).toBe(
false,
);
expect(isNicknameOnlyViolation(msg('["harassment"]'))).toBe(false);
});
it("false when no flags at all", () => {
expect(isNicknameOnlyViolation(msg(null))).toBe(false);
expect(isNicknameOnlyViolation(msg("[]"))).toBe(false);
});
// ── Safety-net: content-level flags mis-applied to a username-only offense ──
it("true: partial flags sara/conflict + analysis attributes violation to username with clean content (matikanetanyahu case)", () => {
const analysis =
"Pengirim menggunakan username 'matikanetanyahu' yang menyerang tokoh politik terkait konflik Israel-Palestina. Meskipun isi pesan membahas alasan hilangnya tugas, keberadaan username tersebut tetap melanggar aturan server.";
expect(
isNicknameOnlyViolation(msg('["sara","conflict_instigation"]', analysis)),
).toBe(true);
});
it("true: sara-only flag + analysis clearly attributes to username with clean content", () => {
const analysis =
"Username mengandung referensi politik (Netanyahu), tapi isi pesan hanya obrolan biasa tanpa diskusi politik. Warning ringan untuk username saja.";
expect(isNicknameOnlyViolation(msg('["sara"]', analysis))).toBe(true);
});
it("false: username-attributable flags but analysis lacks clean-content signal", () => {
const analysis =
"Pengirim mengkritik kebijakan luar negeri Israel secara eksplisit di dalam pesan. Pelanggaran diskusi topik terlarang.";
expect(
isNicknameOnlyViolation(msg('["sara","conflict_instigation"]', analysis)),
).toBe(false);
});
it("false: mixed flags including a real content violation, even with clean analysis", () => {
const analysis =
"Username ofensif dan isi pesan berisi ancaman kekerasan terarah.";
expect(isNicknameOnlyViolation(msg('["sara","violence"]', analysis))).toBe(
false,
);
});
it("false: username-attributable flags but no analysis text available", () => {
expect(isNicknameOnlyViolation(msg('["sara"]', null))).toBe(false);
});
});