feat: require warning before mute + sustained toxicity escalation
Gate mutes behind a prior warning — first offense always gets a warning, mute only fires if warned_since_reset is True. Warned flag is persisted to DB (new Warned column on UserState) and survives restarts. Add post-warning escalation boost to drama_score: each high-scoring message after a warning adds +0.04 (configurable) so sustained bad behavior ramps toward the mute threshold instead of plateauing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -292,7 +292,8 @@ class SentimentCog(commands.Cog):
|
||||
|
||||
# Track the result in DramaTracker
|
||||
self.bot.drama_tracker.add_entry(user_id, score, categories, reasoning)
|
||||
drama_score = self.bot.drama_tracker.get_drama_score(user_id)
|
||||
escalation_boost = sentiment_config.get("escalation_boost", 0.04)
|
||||
drama_score = self.bot.drama_tracker.get_drama_score(user_id, escalation_boost=escalation_boost)
|
||||
|
||||
logger.info(
|
||||
"User %s (%d) | msg_score=%.2f | drama_score=%.2f | categories=%s | %s",
|
||||
@@ -358,10 +359,16 @@ class SentimentCog(commands.Cog):
|
||||
mute_threshold = self.bot.drama_tracker.get_mute_threshold(
|
||||
user_id, base_mute_threshold
|
||||
)
|
||||
user_data = self.bot.drama_tracker.get_user(user_id)
|
||||
# Mute: rolling average OR single message spike
|
||||
if drama_score >= mute_threshold or score >= spike_mute:
|
||||
effective_score = max(drama_score, score)
|
||||
await self._mute_user(user_ref_msg, effective_score, categories, db_message_id)
|
||||
if user_data.warned_since_reset:
|
||||
await self._mute_user(user_ref_msg, effective_score, categories, db_message_id)
|
||||
else:
|
||||
# Downgrade to warning — require a warning before muting
|
||||
logger.info("Downgrading mute to warning for %s (no prior warning)", user_ref_msg.author)
|
||||
await self._warn_user(user_ref_msg, effective_score, db_message_id)
|
||||
# Warn: rolling average OR single message spike
|
||||
elif drama_score >= warning_threshold or score >= spike_warn:
|
||||
effective_score = max(drama_score, score)
|
||||
@@ -556,7 +563,8 @@ class SentimentCog(commands.Cog):
|
||||
self._mark_analyzed(m.id)
|
||||
|
||||
self.bot.drama_tracker.add_entry(user_id, score, categories, reasoning)
|
||||
drama_score = self.bot.drama_tracker.get_drama_score(user_id)
|
||||
escalation_boost = sentiment_config.get("escalation_boost", 0.04)
|
||||
drama_score = self.bot.drama_tracker.get_drama_score(user_id, escalation_boost=escalation_boost)
|
||||
|
||||
# Save to DB
|
||||
content_summary = f"[Mention scan] {worst_msg}" if worst_msg else "[Mention scan] See conversation"
|
||||
@@ -599,9 +607,14 @@ class SentimentCog(commands.Cog):
|
||||
mute_threshold = self.bot.drama_tracker.get_mute_threshold(
|
||||
user_id, base_mute_threshold
|
||||
)
|
||||
user_data = self.bot.drama_tracker.get_user(user_id)
|
||||
if drama_score >= mute_threshold or score >= spike_mute:
|
||||
effective_score = max(drama_score, score)
|
||||
await self._mute_user(ref_msg, effective_score, categories, db_message_id)
|
||||
if user_data.warned_since_reset:
|
||||
await self._mute_user(ref_msg, effective_score, categories, db_message_id)
|
||||
else:
|
||||
logger.info("Downgrading mute to warning for %s (no prior warning)", ref_msg.author)
|
||||
await self._warn_user(ref_msg, effective_score, db_message_id)
|
||||
elif drama_score >= warning_threshold or score >= spike_warn:
|
||||
effective_score = max(drama_score, score)
|
||||
await self._warn_user(ref_msg, effective_score, db_message_id)
|
||||
@@ -747,6 +760,8 @@ class SentimentCog(commands.Cog):
|
||||
message_id=db_message_id,
|
||||
details=f"score={score:.2f}",
|
||||
))
|
||||
# Persist warned flag immediately so it survives restarts
|
||||
self._save_user_state(message.author.id)
|
||||
|
||||
async def _handle_topic_drift(
|
||||
self, message: discord.Message, topic_category: str, topic_reasoning: str,
|
||||
@@ -897,6 +912,7 @@ class SentimentCog(commands.Cog):
|
||||
off_topic_count=user_data.off_topic_count,
|
||||
baseline_coherence=user_data.baseline_coherence,
|
||||
user_notes=user_data.notes or None,
|
||||
warned=user_data.warned_since_reset,
|
||||
))
|
||||
self._dirty_users.discard(user_id)
|
||||
|
||||
@@ -923,6 +939,7 @@ class SentimentCog(commands.Cog):
|
||||
off_topic_count=user_data.off_topic_count,
|
||||
baseline_coherence=user_data.baseline_coherence,
|
||||
user_notes=user_data.notes or None,
|
||||
warned=user_data.warned_since_reset,
|
||||
)
|
||||
logger.info("Flushed %d dirty user states to DB.", len(dirty))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user