Skip to content

Commit b5d1450

Browse files
authored
ref(feedback): clean up graduated spam actions and event link flags (#95309)
Ref [REPLAY-513: \[PR Tracker\] refactor backend user feedback code](https://linear.app/getsentry/issue/REPLAY-513/pr-tracker-refactor-backend-user-feedback-code)
1 parent 87b9f29 commit b5d1450

File tree

5 files changed

+161
-190
lines changed

5 files changed

+161
-190
lines changed

src/sentry/features/temporary.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,8 @@ def register_temporary_features(manager: FeatureManager):
465465
manager.add("organizations:user-feedback-ai-summaries", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
466466
# Enable auto spam classification at User Feedback ingest time
467467
manager.add("organizations:user-feedback-spam-ingest", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
468-
# Enable auto spam filtering at User Feedback ingest time, if spam-ingest is also enabled
469-
manager.add("organizations:user-feedback-spam-filter-actions", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
470468
# Enable User Feedback v2 UI
471469
manager.add("organizations:user-feedback-ui", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
472-
# User Feedback Error Link Ingestion Changes
473-
manager.add("organizations:user-feedback-event-link-ingestion-changes", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)
474470
# Enable view hierarchies options
475471
manager.add("organizations:view-hierarchies-options-dev", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
476472
# Enable aggregates table editor on the new explore page

src/sentry/feedback/usecases/create_feedback.py

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import jsonschema
1111

12-
from sentry import features, options
12+
from sentry import options
1313
from sentry.constants import DataCategory
1414
from sentry.eventstore.models import Event, GroupEvent
1515
from sentry.feedback.lib.types import UserReportDict
@@ -428,7 +428,16 @@ def create_feedback_issue(
428428
)
429429
# Mark as spam. We need this since IP doesn't currently support an initial status of IGNORED.
430430
if is_message_spam:
431-
auto_ignore_spam_feedbacks(project, issue_fingerprint)
431+
produce_occurrence_to_kafka(
432+
payload_type=PayloadType.STATUS_CHANGE,
433+
status_change=StatusChangeMessage(
434+
fingerprint=issue_fingerprint,
435+
project_id=project.id,
436+
new_status=GroupStatus.IGNORED, # we use ignored in the UI for the spam tab
437+
new_substatus=GroupSubStatus.FOREVER,
438+
),
439+
)
440+
432441
metrics.incr(
433442
"feedback.create_feedback_issue.produced_occurrence",
434443
tags={
@@ -452,24 +461,6 @@ def create_feedback_issue(
452461
return event_fixed
453462

454463

455-
def auto_ignore_spam_feedbacks(project, issue_fingerprint):
456-
"""
457-
Marks an issue as spam with a STATUS_CHANGE kafka message. The IGNORED status allows the occurrence to skip alerts
458-
and be picked up by frontend spam queries.
459-
"""
460-
if features.has("organizations:user-feedback-spam-filter-actions", project.organization):
461-
metrics.incr("feedback.spam-detection-actions.set-ignored")
462-
produce_occurrence_to_kafka(
463-
payload_type=PayloadType.STATUS_CHANGE,
464-
status_change=StatusChangeMessage(
465-
fingerprint=issue_fingerprint,
466-
project_id=project.id,
467-
new_status=GroupStatus.IGNORED, # we use ignored in the UI for the spam tab
468-
new_substatus=GroupSubStatus.FOREVER,
469-
),
470-
)
471-
472-
473464
###########
474465
# Shim code
475466
###########

src/sentry/tasks/post_process.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,9 +1351,7 @@ def should_postprocess_feedback(job: PostProcessJob) -> bool:
13511351
if not hasattr(event, "occurrence") or event.occurrence is None:
13521352
return False
13531353

1354-
if event.occurrence.evidence_data.get("is_spam") is True and features.has(
1355-
"organizations:user-feedback-spam-filter-actions", job["event"].project.organization
1356-
):
1354+
if event.occurrence.evidence_data.get("is_spam") is True:
13571355
metrics.incr("feedback.spam-detection-actions.dont-send-notification")
13581356
return False
13591357

@@ -1436,12 +1434,7 @@ def link_event_to_user_report(job: PostProcessJob) -> None:
14361434
project = event.project
14371435
group = event.group
14381436

1439-
if (
1440-
features.has(
1441-
"organizations:user-feedback-event-link-ingestion-changes", project.organization
1442-
)
1443-
and not job["is_reprocessed"]
1444-
):
1437+
if not job["is_reprocessed"]:
14451438
metrics.incr("event_manager.save._update_user_reports_with_event_link")
14461439
event = job["event"]
14471440
project = event.project

tests/sentry/feedback/usecases/test_create_feedback.py

Lines changed: 59 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -548,74 +548,72 @@ def test_create_feedback_spam_detection_produce_to_kafka(
548548
monkeypatch,
549549
feature_flag,
550550
):
551-
with Feature({"organizations:user-feedback-spam-filter-actions": True}):
552-
553-
with Feature({"organizations:user-feedback-spam-ingest": feature_flag}):
554-
event = {
555-
"project_id": default_project.id,
556-
"request": {
557-
"url": "https://sentry.sentry.io/feedback/?statsPeriod=14d",
558-
"headers": {
559-
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
560-
},
551+
with Feature({"organizations:user-feedback-spam-ingest": feature_flag}):
552+
event = {
553+
"project_id": default_project.id,
554+
"request": {
555+
"url": "https://sentry.sentry.io/feedback/?statsPeriod=14d",
556+
"headers": {
557+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
561558
},
562-
"event_id": "56b08cf7852c42cbb95e4a6998c66ad6",
563-
"timestamp": 1698255009.574,
564-
"received": "2021-10-24T22:23:29.574000+00:00",
565-
"environment": "prod",
566-
"release": "frontend@daf1316f209d961443664cd6eb4231ca154db502",
567-
"user": {
568-
"ip_address": "72.164.175.154",
569-
"email": "josh.ferge@sentry.io",
570-
"id": 880461,
571-
"isStaff": False,
559+
},
560+
"event_id": "56b08cf7852c42cbb95e4a6998c66ad6",
561+
"timestamp": 1698255009.574,
562+
"received": "2021-10-24T22:23:29.574000+00:00",
563+
"environment": "prod",
564+
"release": "frontend@daf1316f209d961443664cd6eb4231ca154db502",
565+
"user": {
566+
"ip_address": "72.164.175.154",
567+
"email": "josh.ferge@sentry.io",
568+
"id": 880461,
569+
"isStaff": False,
570+
"name": "Josh Ferge",
571+
},
572+
"contexts": {
573+
"feedback": {
574+
"contact_email": "josh.ferge@sentry.io",
572575
"name": "Josh Ferge",
576+
"message": input_message,
577+
"replay_id": "3d621c61593c4ff9b43f8490a78ae18e",
578+
"url": "https://sentry.sentry.io/feedback/?statsPeriod=14d",
573579
},
574-
"contexts": {
575-
"feedback": {
576-
"contact_email": "josh.ferge@sentry.io",
577-
"name": "Josh Ferge",
578-
"message": input_message,
579-
"replay_id": "3d621c61593c4ff9b43f8490a78ae18e",
580-
"url": "https://sentry.sentry.io/feedback/?statsPeriod=14d",
581-
},
582-
},
583-
"breadcrumbs": [],
584-
"platform": "javascript",
585-
}
580+
},
581+
"breadcrumbs": [],
582+
"platform": "javascript",
583+
}
586584

587-
mock_openai = Mock()
588-
mock_openai().chat.completions.create = create_dummy_response
585+
mock_openai = Mock()
586+
mock_openai().chat.completions.create = create_dummy_response
589587

590-
monkeypatch.setattr("sentry.llm.providers.openai.OpenAI", mock_openai)
588+
monkeypatch.setattr("sentry.llm.providers.openai.OpenAI", mock_openai)
591589

592-
create_feedback_issue(
593-
event, default_project.id, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE
594-
)
590+
create_feedback_issue(
591+
event, default_project.id, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE
592+
)
595593

596-
# Check if the 'is_spam' evidence in the Kafka message matches the expected result
597-
is_spam_evidence = [
598-
evidence.value
599-
for evidence in mock_produce_occurrence_to_kafka.call_args_list[0]
600-
.kwargs["occurrence"]
601-
.evidence_display
602-
if evidence.name == "is_spam"
603-
]
604-
found_is_spam = is_spam_evidence[0] if is_spam_evidence else None
605-
assert (
606-
found_is_spam == expected_result
607-
), f"Expected {expected_result} but found {found_is_spam} for {input_message} and feature flag {feature_flag}"
594+
# Check if the 'is_spam' evidence in the Kafka message matches the expected result
595+
is_spam_evidence = [
596+
evidence.value
597+
for evidence in mock_produce_occurrence_to_kafka.call_args_list[0]
598+
.kwargs["occurrence"]
599+
.evidence_display
600+
if evidence.name == "is_spam"
601+
]
602+
found_is_spam = is_spam_evidence[0] if is_spam_evidence else None
603+
assert (
604+
found_is_spam == expected_result
605+
), f"Expected {expected_result} but found {found_is_spam} for {input_message} and feature flag {feature_flag}"
608606

609-
if expected_result and feature_flag:
610-
assert (
611-
mock_produce_occurrence_to_kafka.call_args_list[1]
612-
.kwargs["status_change"]
613-
.new_status
614-
== GroupStatus.IGNORED
615-
)
607+
if expected_result and feature_flag:
608+
assert (
609+
mock_produce_occurrence_to_kafka.call_args_list[1]
610+
.kwargs["status_change"]
611+
.new_status
612+
== GroupStatus.IGNORED
613+
)
616614

617-
if not (expected_result and feature_flag):
618-
assert mock_produce_occurrence_to_kafka.call_count == 1
615+
if not (expected_result and feature_flag):
616+
assert mock_produce_occurrence_to_kafka.call_count == 1
619617

620618

621619
@django_db_all
@@ -904,7 +902,6 @@ def test_create_feedback_filters_large_message(
904902
"""Large messages are filtered before spam detection and producing to kafka."""
905903
features = (
906904
{
907-
"organizations:user-feedback-spam-filter-actions": True,
908905
"organizations:user-feedback-spam-ingest": True,
909906
}
910907
if spam_enabled
@@ -950,8 +947,8 @@ def test_create_feedback_evidence_has_spam(
950947
source = FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE
951948
create_feedback_issue(event, default_project.id, source)
952949

953-
assert mock_produce_occurrence_to_kafka.call_count == 1
954-
evidence = mock_produce_occurrence_to_kafka.call_args.kwargs["occurrence"].evidence_data
950+
assert mock_produce_occurrence_to_kafka.call_count == 2 # second call is status change
951+
evidence = mock_produce_occurrence_to_kafka.call_args_list[0].kwargs["occurrence"].evidence_data
955952
assert evidence["is_spam"] is True
956953

957954

0 commit comments

Comments
 (0)