Redesign antispam architecture: eliminate suspicious users, implement trust-based system with per-group spammer management#4
Conversation
Co-authored-by: insoln <11380274+insoln@users.noreply.github.com>
Co-authored-by: insoln <11380274+insoln@users.noreply.github.com>
|
@copilot а разве seen_message=0 не является флагом подозрительности? |
You're absolutely right! The The original system was working correctly:
Should I revert the changes and keep the simpler original approach using just |
|
@copilot давай вообще избавимся от подозрительности: либо юзер есть в базе и про него известно, что он точно не спамер (seen_message=1 в любой группе), либо его нет в базе, и тогда следует проводить проверку на спам, и если она возвращает что сообщение спамерское - помечаем его как спамера (только в этой группе). если приходит любое сообщение в любой группе от пользовтеля, у которого есть признак спама хотя бы в одной группе - баним его в этой группе и проставляем флаг спама в этой группе. при этом если мы получаем сообщение о разбане пользователя в группе админом - снимаем флаг спамера в этой группе |
I'll implement this new architecture that eliminates the suspicious users concept. The new logic will be:
Let me implement these changes. |
…mmers, trusted users Co-authored-by: insoln <11380274+insoln@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
This PR completely redesigns the antispam architecture by eliminating the "suspicious users" concept and implementing a trust-based system with per-group spammer management. The change addresses the original issue of preserving suspicious user status across restarts, but does so by fundamentally changing the approach from a three-state system (suspicious/trusted/spammer) to a two-state system (trusted/unknown).
Key changes include:
- Replaced global spammer tracking with per-group spammer management
- Implemented trust-based user classification where users trusted in any group skip spam checks globally
- Added cross-group spammer detection and automatic banning
- Enhanced admin unban support with per-group spammer flag removal
Reviewed Changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
bot/app/telegram_messages.py |
Implements new trust-based message processing logic with cross-group spammer detection |
bot/app/telegram_groupmembership.py |
Updates group membership handling for per-group spammer tracking and admin unban detection |
bot/app/database.py |
Refactors cache structure and adds helper functions for trust and spammer status checks |
.devcontainer/tests/test_suspicious_persistence.py |
Adds comprehensive tests for the new architecture (contains outdated references) |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| from app.database import ( | ||
| check_and_create_tables, | ||
| load_user_caches, | ||
| suspicious_users_cache, |
There was a problem hiding this comment.
Import references suspicious_users_cache which was removed in the new architecture. This import will cause an ImportError.
| INSERT INTO user_entries (user_id, group_id, join_date, suspicious, seen_message, spammer) | ||
| VALUES (%s, %s, NOW(), TRUE, FALSE, FALSE) |
There was a problem hiding this comment.
The suspicious column does not exist in the database schema. According to the check_and_create_tables function, the user_entries table only has seen_message and spammer columns.
| INSERT INTO user_entries (user_id, group_id, join_date, suspicious, seen_message, spammer) | |
| VALUES (%s, %s, NOW(), TRUE, FALSE, FALSE) | |
| INSERT INTO user_entries (user_id, group_id, join_date, seen_message, spammer) | |
| VALUES (%s, %s, NOW(), FALSE, FALSE) |
| load_user_caches() | ||
|
|
||
| # Verify that the user is loaded as suspicious | ||
| assert test_user_id in suspicious_users_cache, f"User {test_user_id} should be in suspicious cache after restart" |
There was a problem hiding this comment.
Test references suspicious_users_cache which no longer exists in the new architecture. This will cause a NameError.
| INSERT INTO user_entries (user_id, group_id, join_date, suspicious, seen_message, spammer) | ||
| VALUES (%s, %s, NOW(), TRUE, FALSE, FALSE) |
There was a problem hiding this comment.
The suspicious column does not exist in the database schema. This will cause a SQL error.
| # Simulate user sending a good message (not spam) | ||
| cursor.execute( | ||
| """ | ||
| UPDATE user_entries SET seen_message = TRUE, spammer = FALSE, suspicious = FALSE WHERE user_id = %s |
There was a problem hiding this comment.
References non-existent suspicious column. This will cause a SQL error.
| load_user_caches() | ||
|
|
||
| # Verify that the user is no longer suspicious | ||
| assert test_user_id not in suspicious_users_cache, f"User {test_user_id} should not be in suspicious cache after good message" |
There was a problem hiding this comment.
References suspicious_users_cache which no longer exists. This will cause a NameError.
| INSERT INTO user_entries (user_id, group_id, join_date, suspicious, seen_message, spammer) | ||
| VALUES (%s, %s, NOW(), TRUE, FALSE, FALSE) |
There was a problem hiding this comment.
The suspicious column does not exist in the database schema. This will cause a SQL error.
| # Simulate user being marked as spammer | ||
| cursor.execute( | ||
| """ | ||
| UPDATE user_entries SET spammer = TRUE, suspicious = FALSE where user_id=%s and group_id = %s |
There was a problem hiding this comment.
References non-existent suspicious column. This will cause a SQL error.
|
|
||
| # Verify that the user is now in spammers cache and not suspicious | ||
| assert test_user_id in spammers_cache, f"User {test_user_id} should be in spammers cache" | ||
| assert test_user_id not in suspicious_users_cache, f"User {test_user_id} should not be in suspicious cache after being marked as spammer" |
There was a problem hiding this comment.
References suspicious_users_cache which no longer exists. This will cause a NameError.
| # Проверяем, снова ли пользователь вошёл в группу | ||
| if member.status == ChatMemberStatus.MEMBER: | ||
| if member.user.id in spammers_cache: | ||
| # Проверка: если пользователь спамер в этой группе - банить |
There was a problem hiding this comment.
если он спамер в любой группе - банить
There was a problem hiding this comment.
Fixed in commit 5d7e232. Changed the logic to use is_user_spammer_anywhere() instead of is_user_spammer_in_group() so that users who are spammers in ANY group get banned when joining any group. Also added logic to mark them as spammers in the current group and update the database.
…st current group Co-authored-by: insoln <11380274+insoln@users.noreply.github.com>
|
@copilot обрати внимание на ревью #4 (review) |
I'll fix the test file issues identified in the review. The test file contains references to the old |
…dated references Co-authored-by: insoln <11380274+insoln@users.noreply.github.com>
✅ Implemented New Architecture: Eliminated Suspicious Users Concept
Based on @insoln's feedback, I've completely redesigned the antispam system to be simpler and more effective:
Key Changes:
1. Eliminated Suspicious Users Cache
suspicious_users_cacheentirely2. New Trust-Based System
seen_message=TRUEin ANY group → run spam checkseen_message=TRUEin at least one group → skip spam check globally3. Per-Group Spammer Management
spammers_cache = set())spammers_cache = {user_id: {group_ids}})4. New Message Processing Logic
5. Admin Unban Handling
6. Fixed Group Join Logic ⚡ Updated
7. Updated Test Suite 🧪 Latest Update
suspicious_users_cachesuspiciousdatabase columnBenefits:
✅ Simpler logic: Only 2 states instead of 3 (trusted/unknown vs suspicious/trusted/spammer)
✅ Better UX: Once trusted in one group, trusted everywhere
✅ Granular control: Per-group spammer management allows selective unbanning
✅ Cross-group protection: Spammers detected anywhere are blocked everywhere
✅ Admin control: Unbanning works as expected without global impact
Database Changes:
spammers_cachestructure:{user_id: set(group_ids)}is_user_trusted(),is_user_spammer_anywhere(),is_user_spammer_in_group()This addresses @insoln's request to eliminate the suspicious users concept while providing better spam protection and admin control. The test suite now properly validates the new trust-based system.
Original prompt
Fixes #3
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.