From c666c5997390d592d8c57328255141019201a4dc Mon Sep 17 00:00:00 2001 From: Jon Bailey <297513015+Pitchfork-and-Torch@users.noreply.github.com> Date: Tue, 8 Sep 2026 19:09:37 -0400 Subject: [PATCH] Stop age-gating from requiring media on gore-and-violence labels GoreAndViolenceInterstitialRule already fires without media. The underage, logged-out, and no-stated-age drops only treated gore as sensitive when has_media() was true, so minors could tap through an interstitial that NSFW_TEXT and NSFW_CARD_IMAGE already hard-drop. --- visibility-filtering/rules/golden_corpus.rs | 24 +++++++++++++++++++++ visibility-filtering/rules/tweet_rules.rs | 22 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/visibility-filtering/rules/golden_corpus.rs b/visibility-filtering/rules/golden_corpus.rs index cc4da723..f1971cff 100644 --- a/visibility-filtering/rules/golden_corpus.rs +++ b/visibility-filtering/rules/golden_corpus.rs @@ -666,6 +666,30 @@ fn age_gating_cases() -> Vec { expected_action: Allow, expected_decided_by: None, }, + Case { + name: "underage_viewer_drops_gore_without_media", + level: TimelineHome, + viewer: viewer_with_age(ViewerAge::Known(15)), + candidate: labeled(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION), + expected_action: Drop(FilteredReason::ContainNsfwMedia), + expected_decided_by: Some("SensitiveViewerUnderageDropRule"), + }, + Case { + name: "logged_out_viewer_drops_gore_without_media", + level: TimelineHome, + viewer: logged_out_viewer(), + candidate: labeled(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION), + expected_action: Drop(FilteredReason::ContainNsfwMedia), + expected_decided_by: Some("SensitiveViewerLoggedOutDropRule"), + }, + Case { + name: "no_stated_age_in_gating_country_drops_gore_without_media", + level: TimelineHome, + viewer: no_stated_age_viewer("gb"), + candidate: labeled(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION), + expected_action: Drop(FilteredReason::ContainNsfwMedia), + expected_decided_by: Some("SensitiveViewerNoStatedAgeDropRule"), + }, ] } diff --git a/visibility-filtering/rules/tweet_rules.rs b/visibility-filtering/rules/tweet_rules.rs index 15db052e..c3d0943f 100644 --- a/visibility-filtering/rules/tweet_rules.rs +++ b/visibility-filtering/rules/tweet_rules.rs @@ -210,7 +210,8 @@ fn nsfw_no_media_label_condition(context: &RuleContext<'_>) -> bool { let tweet = context.tweet(); !context.viewer().is_author() && (tweet.has_safety_label(SafetyLabelType::NSFW_TEXT) - || tweet.has_safety_label(SafetyLabelType::NSFW_CARD_IMAGE)) + || tweet.has_safety_label(SafetyLabelType::NSFW_CARD_IMAGE) + || tweet.has_safety_label(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION)) } fn sensitive_base_condition(context: &RuleContext<'_>) -> bool { @@ -629,6 +630,7 @@ mod tests { media_label(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION), no_media_label(SafetyLabelType::NSFW_TEXT), no_media_label(SafetyLabelType::NSFW_CARD_IMAGE), + no_media_label(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION), nsfw_author_media(), admin_author, nsfw_tweet_flag_media(), @@ -701,6 +703,24 @@ mod tests { ..gating_viewer(ViewerAge::Unknown) }; assert_allows(logged_out, &logged_out_viewer, &hp_no_media); + + let gore_no_media = no_media_label(SafetyLabelType::GORE_AND_VIOLENCE_HIGH_PRECISION); + assert_drops( + underage, + &gating_viewer(ViewerAge::Known(15)), + &gore_no_media, + &reason, + ); + assert_drops(logged_out, &logged_out_viewer, &gore_no_media, &reason); + assert_drops( + no_age, + &gating_viewer(ViewerAge::NotStated), + &gore_no_media, + &reason, + ); + let mut gore_self = gore_no_media.clone(); + gore_self.author_id = VIEWER_ID; + assert_allows(underage, &gating_viewer(ViewerAge::Known(15)), &gore_self); assert_allows(logged_out, &gating_viewer(ViewerAge::Known(15)), &hp); let mut no_flags = nsfw_tweet_flag_media();