Skip to content

feat(python): regex hit suppression (--suppress-hit-regex/-file) — closes #53#183

Merged
devdanzin merged 1 commit into
mainfrom
hit-suppression-regex
Jul 4, 2026
Merged

feat(python): regex hit suppression (--suppress-hit-regex/-file) — closes #53#183
devdanzin merged 1 commit into
mainfrom
hit-suppression-regex

Conversation

@devdanzin

Copy link
Copy Markdown
Owner

Closes #53.

What

Adds regex-based hit suppression: drop known/uninteresting crashing sessions by matching a regex against their captured stdout — the automated version of the by-hand dedup a triager does ("filter out hits that mention source code lines and abort/segfault messages"). This is the general/non-OOM analogue of the OOM catalog dedupe (--oom-dedup-catalog), and needs no catalog.

How to use

# repeatable inline regexes
fusil-python-threaded --suppress-hit-regex 'Objects/dictobject\.c:205' --suppress-hit-regex 'known message'

# and/or a suppression file (repeatable): one regex per line, '#' comments,
# an optional reason after ' ## ' (recorded in the logs when the rule fires)
fusil-python-threaded --suppress-hit-file known_sites.txt

# case-insensitive matching
fusil-python-threaded --suppress-hit-regex ASSERTION --suppress-hit-ignore-case

Suppression-file example:

# Known crash sites to drop
Objects/dictobject\.c:205 ## known FT set_keys OOM assert (benign on release)
Fatal Python error

Rules union three composable sources: --suppress-hit-regex, --suppress-hit-file, and plugins via PluginManager.add_suppression_entry(pattern, reason) — the extensible suppression store called for in #52. On a match the session dir is pruned and the reason logged; an end-of-run summary reports how many hits each rule dropped.

Design

  • Enginefusil/python/hit_suppression.py: pure-Python (no runtime stack), mirroring oom_dedup.py's split so it unit-tests in isolation. build_suppressor()HitSuppressor.decide(text) -> (keep, rule).
  • WiringFuzzer._suppression_keep_policy reads the crash stdout (bounded via read_crash_stdout, to avoid catastrophic regex backtracking on huge/OOM-verbose spew) and returns (False, None) on a match through the same application.session_keep_policy hook SessionDirectory.checkKeepDirectory already consults for OOM dedupe.
  • Composes with --oom-dedup-catalog: suppression runs first (a matched hit is pruned even if the OOM deduper would keep it); otherwise it defers to the previously-installed policy. Absent any --suppress-hit-* option, nothing is installed and behaviour is unchanged. Any failure falls back to keep, so a crash is never lost to a suppression error.

Tests

Mirror the oom_dedup split — all green (python -m unittest discover -s tests, 420 tests), ruff check + ruff format --check clean:

  • tests/python/test_hit_suppression.py — pure engine (compile / parse-file / decide / report / build_suppressor), no skip guard.
  • tests/python/test_hit_suppression_wiring.py — skip-guarded keep-policy glue: prune+log, keep, defer-to-prev, suppression-wins-over-prev, and read-error → keep.
  • tests/test_plugin_manager.pyadd_suppression_entry / get_suppression_entries.

Also smoke-tested end-to-end (--suppress-hit-regex/-file/-ignore-case on a live 1-session run): the startup log reports the rule count and the run exits cleanly.

Docs

doc/python-fuzzer.md (new Hit suppression subsection + Where to look row) and CLAUDE.md (options block + architecture subsection).

🤖 Generated with Claude Code

…oses #53

Drop known/uninteresting *crashing sessions* by regex-matching their captured
stdout — the automated version of the by-hand dedup a triager does. This is the
general/non-OOM analogue of the OOM catalog dedupe (--oom-dedup-catalog).

Engine: fusil/python/hit_suppression.py — pure-Python (no runtime stack),
mirroring oom_dedup.py's split so it unit-tests in isolation. Rules union three
composable sources:
  * repeatable --suppress-hit-regex,
  * one or more --suppress-hit-file files (one regex/line; '#' comments; optional
    reason after ' ## '), and
  * plugins via PluginManager.add_suppression_entry (the extensible store #52
    asked for).
--suppress-hit-ignore-case toggles case-insensitive matching.

Wiring: Fuzzer._suppression_keep_policy reads the crash stdout (bounded via
read_crash_stdout) and, on a match, prunes the session dir (reason logged),
returning (False, None) through the same application.session_keep_policy hook
SessionDirectory.checkKeepDirectory already consults. It composes with the OOM
dedupe: suppression runs first (a matched hit is pruned even if the OOM deduper
would keep it), otherwise it defers to the previously-installed policy. Absent
any --suppress-hit-* option nothing is installed and behaviour is unchanged.
Failures fall back to keep so a crash is never lost.

Tests (mirror the oom_dedup split):
  * tests/python/test_hit_suppression.py — pure engine (compile/parse/decide/
    report/build_suppressor), no skip guard.
  * tests/python/test_hit_suppression_wiring.py — skip-guarded keep-policy glue
    (prune+log, keep, defer-to-prev, suppression-wins-over-prev, read-error).
  * tests/test_plugin_manager.py — add_suppression_entry / get_suppression_entries.

Docs: doc/python-fuzzer.md (new Hit-suppression subsection + Where-to-look row),
CLAUDE.md (options block + architecture subsection).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@devdanzin devdanzin merged commit 1e5fb79 into main Jul 4, 2026
2 checks passed
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.

Improve how we suppress hits

1 participant