Skip to content

perf(contests): swap aggregate_user.score filter for karma-reported authors#814

Merged
dylanjeffers merged 1 commit into
mainfrom
dylan/remove-aggregate-user-score-filter
May 15, 2026
Merged

perf(contests): swap aggregate_user.score filter for karma-reported authors#814
dylanjeffers merged 1 commit into
mainfrom
dylan/remove-aggregate-user-score-filter

Conversation

@dylanjeffers
Copy link
Copy Markdown
Contributor

@dylanjeffers dylanjeffers commented May 15, 2026

Problem

/v1/events/remix-contests?limit=12&offset=0&status=all is timing out / hanging the contests page in production. Measured against api.audius.co:

Call First (cold) Subsequent (warm)
status=all 24.7s 0.12s
status=ended 24.0s 0.12s
status=active 1.96s 0.08s

Root cause

The shadowban filter introduced in #803 added an aggregate_user.score < 0 CTE on the contest query. aggregate_user has one row per user (millions of rows) and no index covering score, so the CTE runs a full sequential scan of aggregate_user on every cold call.

WITH low_abuse_score AS (SELECT user_id FROM aggregate_user WHERE score < 0)
...
WHERE e.user_id NOT IN (SELECT user_id FROM low_abuse_score)

Approach — align with the existing comment-visibility filter

Rather than indexing around aggregate_user.score, this PR switches the contest filter to the same community-karma signal that already governs comment visibility on v1_track_comments / v1_event_comments. A comment is hidden when reporters' summed follower_count crosses karmaCommentCountThreshold (the high_karma_reporters CTE). This PR lifts that signal from comment_id up to user_id: if a host has authored any comment that crossed the threshold, their contests are hidden too.

New CTEs on the contest query:

high_karma_reporters AS (
    SELECT comment_reports.comment_id
    FROM comment_reports
    JOIN aggregate_user ON comment_reports.user_id = aggregate_user.user_id
    WHERE comment_reports.is_delete = false
    GROUP BY comment_reports.comment_id
    HAVING SUM(aggregate_user.follower_count) >= @karmaCommentCountThreshold
),
karma_reported_authors AS (
    SELECT DISTINCT comments.user_id
    FROM comments
    JOIN high_karma_reporters USING (comment_id)
)

Filter:

WHERE e.user_id NOT IN (SELECT user_id FROM karma_reported_authors)
  AND e.user_id NOT IN (SELECT muted_user_id FROM muted_by_karma)

muted_by_karma is unchanged — still in the filter list. The AAO score remains the moderation lane for the comment endpoints themselves (v1_track_comments, v1_event_comments, v1_fan_club_feed, v1_track_comment_count are all untouched).

Why this is faster

The new CTE walks comment_reports (a small table, indexed on comment_id) joined with aggregate_user on the reporter id, plus a hash-join on comments for the author lookup. The cost is bounded by report volume — no sequential scan over millions of aggregate_user rows.

Supersedes #813

#813 proposed a partial index on aggregate_user (user_id) WHERE score < 0. That works but keeps the AAO score as the moderation lane for contests; this PR routes contests through the same karma-reports signal as comments, which is the preferred semantic. Closing #813.

Test plan

  • go build ./api/... clean
  • go vet ./api/... clean
  • TestRemixContestsExcludesShadowbannedHosts updated to seed comment_reports + aggregate_user.follower_count bump and assert the karma-reported host is excluded
  • CI test suite green
  • Time /v1/events/remix-contests?status=all cold on staging — expect sub-second
  • Confirm a host with karma-reported comments is excluded
  • Confirm karma-muted hosts are still excluded (unchanged)
  • Comment endpoints (track / event / fan-club) unchanged — low_abuse_score, high_karma_reporters, muted_by_karma, deactivated_users all still in place

🤖 Generated with Claude Code

@dylanjeffers dylanjeffers changed the title perf(contests,comments): drop aggregate_user.score shadow-ban filter perf(contests,comments): switch shadowban source from aggregate_user.score to chat_ban May 15, 2026
@dylanjeffers dylanjeffers force-pushed the dylan/remove-aggregate-user-score-filter branch from 13f2b26 to 228370d Compare May 15, 2026 19:40
@dylanjeffers dylanjeffers changed the title perf(contests,comments): switch shadowban source from aggregate_user.score to chat_ban perf(contests): partial index for shadowban CTE on aggregate_user.score May 15, 2026
…uthors

The previous shadow-ban filter on the contest discovery list used
`aggregate_user.score < 0` (AAO output). Two problems:

  1. `aggregate_user` has no index covering `score`, so the CTE forced a
     full seq scan on every cold call. /v1/events/remix-contests?status=all
     was hanging ~22s cold-cache (warm: ~100ms).
  2. The AAO signal is a separate moderation lane from the community
     karma-reports system that already governs comment visibility.
     The two can drift.

Fix: align the contest filter with the comment-visibility filter. A host
is shadow-banned from contest discovery if they authored a comment that
crossed the same `high_karma_reporters` threshold (sum of reporters'
follower_count >= karmaCommentCountThreshold) that hides the comment
itself on v1_track_comments / v1_event_comments. The new CTE
`karma_reported_authors` lifts the comment-level signal up to user_id.

`muted_by_karma` is unchanged — still filters hosts muted by high-karma
users.

`comment_reports` is a small table indexed on `comment_id`, and the new
CTE only adds a hash-join on comments (PK lookup per hkr row), so the
cost is bounded by report volume rather than user-table size — no
sequential scan over millions of aggregate_user rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dylanjeffers dylanjeffers force-pushed the dylan/remove-aggregate-user-score-filter branch from 228370d to c7d4c50 Compare May 15, 2026 19:47
@dylanjeffers dylanjeffers changed the title perf(contests): partial index for shadowban CTE on aggregate_user.score perf(contests): swap aggregate_user.score filter for karma-reported authors May 15, 2026
@dylanjeffers dylanjeffers merged commit 7d435c7 into main May 15, 2026
5 checks passed
@dylanjeffers dylanjeffers deleted the dylan/remove-aggregate-user-score-filter branch May 15, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant