Skip to content

add flag to exclude a user from aggregates and scoring#4760

Open
lsabor wants to merge 1 commit into
mainfrom
feat/aggregation-blacklist
Open

add flag to exclude a user from aggregates and scoring#4760
lsabor wants to merge 1 commit into
mainfrom
feat/aggregation-blacklist

Conversation

@lsabor
Copy link
Copy Markdown
Contributor

@lsabor lsabor commented May 21, 2026

Summary by CodeRabbit

  • New Features

    • Added ability to explicitly exclude specific users from aggregations and peer scoring calculations.
    • Admin interface now displays and allows filtering users by exclusion status.
  • Bug Fixes

    • Updated aggregation and scoring logic to properly respect user exclusion settings across all forecasts.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

This PR adds an exclude_from_aggregations boolean field to the User model to explicitly exclude users from forecast aggregations and peer scoring. The field is integrated into the admin interface and applied through QuerySet filters in scoring and aggregation functions.

Changes

User Exclusion from Aggregations

Layer / File(s) Summary
User model field and migration
users/models.py, users/migrations/0021_user_exclude_from_aggregations.py
User model adds indexed exclude_from_aggregations BooleanField with default=False. Migration adds the field with database index and help text.
Admin interface for exclusion field
users/admin.py
UserAdmin extends list_display and list_filter to include exclude_from_aggregations for visibility and filtering in the user management interface.
QuerySet helper for filtering blacklisted users
questions/models.py
ForecastQuerySet adds exclude_blacklisted_users() method that filters forecasts by checking the author's exclude_from_aggregations flag.
Integration into scoring and aggregation paths
scoring/score_math.py, utils/the_math/aggregations.py
Scoring and aggregation functions apply the exclude_blacklisted_users() filter to forecast querysets: evaluate_question filters when only_include_user_ids is set, and aggregation helper functions filter default querysets in both get_aggregations_at_time and get_aggregation_history.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A blacklist now brings peace to the score,
With one field to banish whom we'd ignore,
Admin controls it, filters apply,
Aggregations flow pure as the sky—
No bot nor rogue shall skew totals anymore! ✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding a flag to exclude users from aggregates and scoring, which is the core objective reflected in all file changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/aggregation-blacklist

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.

@lsabor lsabor force-pushed the feat/aggregation-blacklist branch from ab153a7 to 4823924 Compare May 21, 2026 21:28
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scoring/score_math.py (1)

361-369: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Blacklisted users are still eligible for peer score rows.

Line 361 keeps user_forecasts unfiltered, and Lines 496-513 still emit per-user scores from that full set. Also, Line 368 only filters base_forecasts when only_include_user_ids is not set. This allows excluded users to still be peer-scored.

Proposed fix
-    user_forecasts = question.user_forecasts.all()
+    user_forecasts = question.user_forecasts.all().exclude_blacklisted_users()
     if only_include_user_ids:
         user_forecasts = user_forecasts.filter(author__id__in=only_include_user_ids)
     base_forecasts = user_forecasts
     if not only_include_user_ids:
         # only include forecasts by non-primary bots if user ids explicitly specified
         base_forecasts = base_forecasts.exclude_non_primary_bots()
-        base_forecasts = base_forecasts.exclude_blacklisted_users()
         if not question.include_bots_in_aggregates:
             base_forecasts = base_forecasts.exclude(author__is_bot=True)

Also applies to: 496-513

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scoring/score_math.py` around lines 361 - 369, The peer-scoring loop is still
using the unfiltered user_forecasts so blacklisted or excluded users can
generate per-user rows; ensure the set used to emit per-user peer scores is
filtered the same way as aggregates by using base_forecasts (or applying
exclude_blacklisted_users()/exclude_non_primary_bots() to user_forecasts) before
the per-user scoring section (the code around user_forecasts, base_forecasts,
exclude_non_primary_bots, exclude_blacklisted_users, include_bots_in_aggregates
and the per-user score emission in the block around lines 496-513). Update the
logic so that when only_include_user_ids is set we still remove
blacklisted/non-primary-bot users from the dataset used to produce peer score
rows.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scoring/utils.py`:
- Around line 469-471: The QuerySet assigned to candidates currently selects the
exclude_from_aggregations field but never uses it, so users flagged for
exclusion remain rank-eligible; update the retrieval or post-filtering logic to
enforce exclusion (e.g., add exclude_from_aggregations=False to the
User.objects.filter call or immediately .exclude(exclude_from_aggregations=True)
on the candidates QuerySet) and apply the same change where similar
candidate/user QuerySets are built in the 473-499 region so excluded users are
removed before any ranking or aggregation logic runs.

In `@utils/the_math/aggregations.py`:
- Around line 748-755: The current logic in aggregations.py lets
only_include_user_ids bypass blacklist/bot exclusion: when only_include_user_ids
is provided the code uses forecasts.filter(author_id__in=only_include_user_ids)
but does not call forecasts.exclude_non_primary_bots() or
forecasts.exclude_blacklisted_users(); update the aggregation builders so that
after filtering by only_include_user_ids you also apply
exclude_non_primary_bots() and exclude_blacklisted_users() (or filter out
blacklisted/bot IDs from the provided list) to ensure blacklisted users and
primary bots are always excluded; make the same change in the other occurrence
around the 1002-1009 block.

---

Outside diff comments:
In `@scoring/score_math.py`:
- Around line 361-369: The peer-scoring loop is still using the unfiltered
user_forecasts so blacklisted or excluded users can generate per-user rows;
ensure the set used to emit per-user peer scores is filtered the same way as
aggregates by using base_forecasts (or applying
exclude_blacklisted_users()/exclude_non_primary_bots() to user_forecasts) before
the per-user scoring section (the code around user_forecasts, base_forecasts,
exclude_non_primary_bots, exclude_blacklisted_users, include_bots_in_aggregates
and the per-user score emission in the block around lines 496-513). Update the
logic so that when only_include_user_ids is set we still remove
blacklisted/non-primary-bot users from the dataset used to produce peer score
rows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 192190df-8943-414a-8b79-6a153b8810c0

📥 Commits

Reviewing files that changed from the base of the PR and between 5b66f09 and ab153a7.

📒 Files selected for processing (7)
  • questions/models.py
  • scoring/score_math.py
  • scoring/utils.py
  • users/admin.py
  • users/migrations/0021_user_exclude_from_aggregations.py
  • users/models.py
  • utils/the_math/aggregations.py

Comment thread scoring/utils.py Outdated
Comment thread utils/the_math/aggregations.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scoring/score_math.py`:
- Around line 365-369: The blacklist exclusion is currently only applied when
not only_include_user_ids, allowing explicit IDs to bypass
exclude_from_aggregations; always apply base_forecasts =
base_forecasts.exclude_blacklisted_users() regardless of the
only_include_user_ids flag. Modify the logic around only_include_user_ids so
that exclude_blacklisted_users() is invoked unconditionally (either move the
call out of the branch or call it in both branches) while keeping
exclude_non_primary_bots() and the question.include_bots_in_aggregates check
behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b34ccdc0-34a6-47c6-abbc-ba5697e09a7c

📥 Commits

Reviewing files that changed from the base of the PR and between ab153a7 and 4823924.

📒 Files selected for processing (6)
  • questions/models.py
  • scoring/score_math.py
  • users/admin.py
  • users/migrations/0021_user_exclude_from_aggregations.py
  • users/models.py
  • utils/the_math/aggregations.py

Comment thread scoring/score_math.py
@github-actions
Copy link
Copy Markdown
Contributor

🚀 Preview Environment

Your preview environment is ready!

Resource Details
🌐 Preview URL https://metaculus-pr-4760-feat-aggregation-blacklist-preview.mtcl.cc
📦 Docker Image ghcr.io/metaculus/metaculus:feat-aggregation-blacklist-4823924
🗄️ PostgreSQL NeonDB branch preview/pr-4760-feat-aggregation-blacklist
Redis Fly Redis mtc-redis-pr-4760-feat-aggregation-blacklist

Details

  • Commit: 8ca8466030685682e72825c8bbd84f8b37e35193
  • Branch: feat/aggregation-blacklist
  • Fly App: metaculus-pr-4760-feat-aggregation-blacklist

ℹ️ 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

@lsabor lsabor requested review from SylvainChevalier and hlbmtc and removed request for hlbmtc May 21, 2026 22:14
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