refactor(filters): снизить сложность match_message_filter F(42)→A + safety-тесты (#922)#928
Conversation
…922) `match_message_filter` was rank F(42): one function evaluating nine independent filter criteria as a linear if-chain with several legacy text-fallback branches. Coverage was thin (two indirect cases via FilterHandler), so this lands a dedicated behavior-locking test suite first, then refactors: - add tests/test_pipeline_filters.py — 40 cases pinning every criterion (message_kinds, service_actions, media_types, sender_kinds, forwarded, has_text, keywords, match_links, regex), the legacy text fallbacks, the None-config normalization, and combined AND semantics, written against the unmodified function - extract `_extract_message_attributes` (+ `_MessageAttrs`) and one `_check_*` predicate per criterion; `match_message_filter` becomes `all(check(...) for check in _MESSAGE_FILTER_CHECKS)` with the checks in the original precedence so short-circuit/AND behavior is identical radon cc: `match_message_filter` F(42) → A(3); largest predicate B(9). No behavior change — tests/test_pipeline_filters.py (40) and tests/test_pipeline_graph.py (24) both pass. Refs #922. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@claude @codex review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production. |
|
Claude finished @axisrow's task in 3m 29s —— View job Code Review
Bottom line: no critical issues. The refactoring is a faithful behavioral translation. I verified each Two findings worth knowing about, neither is a blocker: 1. Unreachable guard in
|
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Триаж ревью (cycle 1/3)Спасибо @claude @codex. Codex — без замечаний. Claude — критичных нет, 2 non-blocking находки. Вердикты (оба проверены по коду): 1. Недостижимый guard 2. Неполная экстракция |
|
Claude finished @axisrow's task in 2m 14s —— View job Cleanup: complete
|
|
Summary
Testing
|
… & forward_from_channel_id Move remaining two getattr(message, ...) calls in _check_media_types and _check_forwarded into _MessageAttrs / _extract_message_attributes so that all nine predicate functions are fully self-contained on the pre-extracted attrs struct. Drop the now-unused `message` parameter from all nine predicates: signature (message, attrs, config) → (attrs, config); update match_message_filter call site accordingly. No behavior change — 40 safety tests in test_pipeline_filters.py confirm. Co-authored-by: axisrow <axisrow@users.noreply.github.com>
|
Finding #2 уже применён в этой ветке коммитом Finding #1 (мёртвый guard) оставлен намеренно как защитный инвариант — см. предыдущий комментарий. |
Что и зачем
PR-5 из #922 (финальная функция раунда).
match_message_filter(src/services/pipeline_filters.py) была radon F(42) — одна функция, оценивающая 9 независимых критериев фильтра линейной if-цепочкой с несколькими legacy text-fallback ветками. Покрытие было слабым (2 непрямых кейса через FilterHandler), поэтому сначала safety-тесты, потом рефактор.1. Safety-тесты (написаны против неизменённой функции)
Новый
tests/test_pipeline_filters.py— 40 кейсов, фиксирующих каждый критерий (message_kinds, service_actions, media_types, sender_kinds, forwarded, has_text, keywords, match_links, regex), legacy text-fallback, нормализацию None-config и комбинированную AND-семантику. Прогон против старого кода — зелёные (зафиксировали реальное поведение; в т.ч. выявили, чтоmatch_message_filter(msg, None)нормализуется в пустой keywords-фильтр и отклоняет всё).2. Рефактор
_extract_message_attributes(+_MessageAttrs) + по одному_check_*-предикату на критерий.match_message_filterсталall(check(...) for check in _MESSAGE_FILTER_CHECKS)— порядок предикатов = исходная precedence, поэтому short-circuit/AND поведение идентично.radon cc:
match_message_filterF(42) → A(3); самый крупный предикат B(9).Проверка
ruff check(src + tests) — cleanpytest tests/test_pipeline_filters.py tests/test_pipeline_graph.py— 64 passed (40 новых safety + 24 существующих)Refs #922. Внешнее поведение фильтров без изменений.
🤖 Generated with Claude Code