Skip to content

Smart search for tagging: prioritize relevant users in @ mentions#4327

Draft
SylvainChevalier wants to merge 5 commits intomainfrom
claude/issue-4280-smart-search-for-tagging
Draft

Smart search for tagging: prioritize relevant users in @ mentions#4327
SylvainChevalier wants to merge 5 commits intomainfrom
claude/issue-4280-smart-search-for-tagging

Conversation

@SylvainChevalier
Copy link
Contributor

Closes #4280

Summary

  • Add optional post_id param to /users/ search endpoint to prioritize relevant users (commenters, authors, project members) in @ mention suggestions
  • Thread postId through frontend mentions context to API call
  • Add backend tests for relevance-based user search

Test plan

  • Run python -m pytest tests/unit/test_users/test_search.py -v
  • Test @ mentions in comment editor on a post with known commenters
  • Verify that commenters appear first when searching by username
  • Verify existing @ mention behavior still works without post context

Generated with Claude Code

When a user types @ to mention someone in a comment, the search results
now prioritize users who are relevant to the post being commented on:

1. Users who have commented on the post (highest priority)
2. The post author and coauthors
3. Users with explicit project permissions (e.g., tournament members)

Backend: Added optional `post_id` parameter to the `/users/` search
endpoint. When provided without a search query, returns only relevant
users. When combined with a search query, all matching users are returned
but relevant ones are sorted to the top.

Frontend: Threads `postId` from the comment feed through the mentions
context to the API call, preserving the backend's relevance-based
ordering.

Closes #4280

Co-authored-by: Sylvain <SylvainChevalier@users.noreply.github.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/issue-4280-smart-search-for-tagging

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SylvainChevalier
Copy link
Contributor Author

@claude keep the requirement of 3 characters before suggestions.

@claude
Copy link

claude bot commented Feb 12, 2026

Claude finished @SylvainChevalier's task in 54s —— View job


Verifying 3-character minimum for @ mention suggestions

  • Gather context: review PR changes related to character threshold
  • Identify where the threshold is set
  • Verify the 3-character minimum is preserved

Result

No changes needed — the 3-character minimum requirement is already preserved in this PR at both layers:

  1. Frontend (front_end/src/components/markdown_editor/plugins/mentions/utils.ts:33):

    if (query.length < 3) {
      return clientSearch(query, fallbackMentions);
    }

    This is unchanged from the original code. When fewer than 3 characters are typed, only local fallback results are shown (no API call).

  2. Backend (users/serializers.py:206):

    search = serializers.CharField(required=False, min_length=3)

    The API endpoint enforces min_length=3 on the search parameter, so even if the frontend were to send a shorter query, the backend would reject it.

The smart search changes (passing postId, relevance sorting) only affect the API call that fires after 3+ characters are typed. No modifications required.

--- |

@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2026

🚀 Preview Environment

Your preview environment is ready!

Resource Details
🌐 Preview URL https://metaculus-pr-4327-claude-issue-4280-smart-search-preview.mtcl.cc
📦 Docker Image ghcr.io/metaculus/metaculus:claude-issue-4280-smart-search-for-tagging-2b72ee7
🗄️ PostgreSQL NeonDB branch preview/pr-4327-claude-issue-4280-smart-search
Redis Fly Redis mtc-redis-pr-4327-claude-issue-4280-smart-search

Details

  • Commit: 6a331fbefd1fb904cc97fd1a01c507984282d6ed
  • Branch: claude/issue-4280-smart-search-for-tagging
  • Fly App: metaculus-pr-4327-claude-issue-4280-smart-search

ℹ️ Preview Environment Info

Isolation:

  • PostgreSQL and Redis are fully isolated from production
  • Each PR gets its own database branch and Redis instance
  • Changes pushed to this PR will trigger a new deployment

Limitations:

  • Background workers and cron jobs are not deployed in preview environments
  • If you need to test background jobs, use Heroku staging environments

Cleanup:

  • This preview will be automatically destroyed when the PR is closed

@SylvainChevalier
Copy link
Contributor Author

@claude what does the @ member tag do?

@claude
Copy link

claude bot commented Feb 13, 2026

Claude finished @SylvainChevalier's task in 35s —— View job


What does the @ member tag do?

  • Gather context on the @ mention feature
  • Provide explanation

The @ mention feature is a user tagging system inside the comment editor on Metaculus. When you're writing a comment and type @ followed by a username, it triggers a typeahead/autocomplete dropdown that lets you tag other users.

Here's how it works step-by-step:

  1. You type @ in the comment editor — this activates the mentions plugin (BeautifulMentionsPlugin from lexical-beautiful-mentions).

  2. With fewer than 3 characters typed, only local/fallback results are shown (no API call). These are pre-loaded defaults like recent commenters on the current post.

  3. Once you type 3+ characters, the frontend fires an API call to GET /users/?search=<query> to search for matching usernames.

  4. The dropdown shows matching users — you can select one to insert an @username mention into your comment.

  5. Group mentions are also available: @moderators, @admins, @members, and (for curators/admins) @predictors.

What this PR adds — the "smart search" enhancement:

Previously, the search just matched usernames alphabetically. This PR adds a post_id parameter so the backend can prioritize relevant users for the post you're commenting on. The priority order is:

Priority User type
1st Users who have commented on this post
2nd The post author and coauthors
3rd Users with permissions on the post's project
4th All other matching users

This is implemented in users/services/common.py:24-117 via Django ORM annotations (is_commenter, is_author, has_permission) that drive the sort order. The postId is threaded from the CommentFeed component → context provider → mentions plugin → API call.


View job |

@SylvainChevalier
Copy link
Contributor Author

@claude I know that, I'm asking who receives notifications when @ members is used.

@claude
Copy link

claude bot commented Feb 13, 2026

Claude finished @SylvainChevalier's task in 1m 36s —— View job


Who receives notifications for @members?

  • Gather context: find group mention and notification code
  • Determine who receives notifications for @members
  • Provide answer

Result

@members is shown in the frontend dropdown but is NOT actually implemented as a group mention in the backend. It will not notify anyone as a group.

Here's what happens when you type @members in a comment:

  1. The frontend allows selecting @members from the mention dropdown (front_end/src/components/markdown_editor/plugins/mentions/utils.ts:13-17)
  2. When the comment is saved, the backend processes mentions in comments/utils.py:35-64
  3. The backend only recognizes these group mentions:
    • @admins → notifies all users with ADMIN permission on the post's project
    • @moderators (or @curators) → notifies all users with CURATOR permission on the post's project
    • @predictors → notifies all users who have forecasted on the question (only if the comment author is a curator or admin)
  4. @members is not handled — it falls through to the username lookup fallback (comments/utils.py:67), where it tries to find a user literally named "members". If no such user exists, nobody is notified.

In short: @members currently notifies nobody (unless there's a user with the username "members"). It's a frontend option without a backend implementation.

The relevant code paths:

  • Group mention extraction: comments/utils.py:15-69
  • Notification dispatch: comments/services/notifications.py:17-28
  • Email sending: notifications/services.py:720-752

View job

@SylvainChevalier
Copy link
Contributor Author

@claude ok thanks. Two more refinements then:

  1. Remove the @ members tag from the front end.
  2. When making the list of all other users, only keep users who're active, and have a non-deleted comment in the last year.

@claude
Copy link

claude bot commented Feb 13, 2026

Claude finished @SylvainChevalier's task in 3m 51s —— View job


Implementing refinements to smart search

  • Gather context: read relevant files
  • Remove @members tag from frontend
  • Filter "all other users" to active users with a non-deleted comment in the last year
  • Update tests for new filtering behavior
  • Commit and push changes

Summary

Both refinements have been implemented in commit 7848daf:

1. Removed @members from frontend (utils.ts:13-16)

  • Removed { value: "members" } from the usersGroupMentions array — it had no backend implementation and notified nobody.

2. Filtered non-priority users to recently active only (users/services/common.py:43-53)

  • Added a recently_active_user_ids subquery that finds users with at least one non-deleted comment (is_soft_deleted=False) created in the last 365 days.
  • When post_id is provided with search: non-priority users (those who aren't commenters, authors, or project members) must be in the recently-active set to appear.
  • When searching without post_id: all results are filtered to recently-active users only.
  • Priority users (commenters on the post, authors/coauthors, project permission holders) still always appear regardless of recent activity.

3. Updated tests — added 3 new test cases:

  • test_inactive_users_excluded_from_search — users without recent comments don't appear in non-priority results
  • test_old_comments_dont_count_as_recent — comments older than a year don't qualify
  • test_deleted_comments_dont_count_as_recent — soft-deleted comments don't qualify

Existing tests updated to give "other" users a recent comment via _make_recently_active() helper so they pass the new filter.
·

@SylvainChevalier
Copy link
Contributor Author

@claude functionality looks good, now fix the issues from the unit tests.

@claude
Copy link

claude bot commented Feb 13, 2026

Claude finished @SylvainChevalier's task in 22m 52s —— View job


Fixing unit test issues

  • Read CI logs and identify failures
  • Fix Prettier formatting in utils.ts
  • Fix Flake8 linting errors in test_search.py (unused imports, unused variable)
  • Fix Black formatting in test_search.py and users/services/common.py
  • Commit and push fixes
  • Verify CI passes

Result

All CI checks are now passing. Fixed in 2 commits:

5308720 — Prettier, Flake8, and initial Black fixes:

  • utils.ts: Collapsed 2-element array to single line (Prettier)
  • test_search.py: Removed unused imports (pytest, User), fixed unused variable inactive_user, added trailing commas on multi-line factory_project() calls
  • common.py: Collapsed author_ids.extend() to single line

2b72ee7 — Black formatting cleanup:

  • Collapsed function signatures that fit within 88-char limit to single lines
  • Collapsed anon_client.get() and assert expressions to single lines where they fit
  • Converted long docstring to multi-line format
    ·

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.

Smart search for tagging

2 participants