Agent Wranglers

TNS-8Recommended

Warn before you suspend and count every strike

Give each confirmed violation a strike that expires after a fixed time. Warn at the first strike, and suspend for a fixed period only when strikes pass the limit. Treat people who often send baseless reports the same way.

How to do it

Article 23 of the Digital Services Act covers users who often post manifestly illegal content. Online platforms suspend them for a reasonable period, after a warning. It also covers people who often send manifestly unfounded notices or complaints, whose reports you may stop processing. Decide case by case from the count, the share of the user's posts, the gravity and the intent. Article 23(4) asks your terms to describe this policy and the length of suspensions. Keep the ladder in code next to the policy table, so the terms show the same numbers. Severity 1 reasons skip the ladder and suspend at once. Every warning and suspension needs a statement of reasons, as Take notices about illegal content and answer each one requires.

Examples

JavaScript example

const STRIKE_LIFETIME_DAYS = 90;
const SUSPEND_AT_STRIKES = 3;
const SUSPENSION_DAYS = 7;
const DAY_MS = 86_400_000;

export function nextAction(strikes, now = Date.now()) {
  const live = strikes.filter(s => now - Date.parse(s.at) < STRIKE_LIFETIME_DAYS * DAY_MS);
  if (live.some(s => s.severity === 1)) return { action: 'suspend', days: null };
  if (live.length >= SUSPEND_AT_STRIKES) return { action: 'suspend', days: SUSPENSION_DAYS };
  return { action: live.length > 0 ? 'warn' : 'none' };
}

Python example

from datetime import datetime, timedelta, timezone

STRIKE_LIFETIME = timedelta(days=90)
SUSPEND_AT_STRIKES = 3
SUSPENSION_DAYS = 7

def next_action(strikes: list[dict], now: datetime | None = None) -> dict:
    now = now or datetime.now(timezone.utc)
    live = [s for s in strikes if now - s["at"] < STRIKE_LIFETIME]
    if any(s["severity"] == 1 for s in live):
        return {"action": "suspend", "days": None}
    if len(live) >= SUSPEND_AT_STRIKES:
        return {"action": "suspend", "days": SUSPENSION_DAYS}
    return {"action": "warn" if live else "none"}

How to check

A unit test gives a user one strike and gets a warning, then two more within 90 days and gets a 7-day suspension. A strike older than 90 days no longer counts. A reporter with 10 rejected reports in 30 days and no upheld ones gets a warning.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/trust-and-safety/decisions-and-appeals/strikes-and-suspensions">Agent Wranglers trust and safety playbook</a>. In code you write, add a comment next to it with the same link.