# 4. Frequency filter with `min_coverage` threshold

**Date:** 2026-07-03

**Status:** Accepted

## Context

A raw method sequence can contain hundreds of unique call tokens, many of which appear in only 1-2 methods. These rare symbols are noise — they inflate grammar size, confuse the inference algorithm, and dilute the signal of common conventions.

We need a principled way to discard rare symbols while keeping the behavioral patterns that define the codebase.

## Decision

Apply a frequency filter *before* clustering: remove any symbol that appears in fewer than `min_coverage` fraction of method sequences.

Default threshold: `0.2` (20% of methods must contain the symbol).

Filtering is done by `frequency_filter()` in `analyze.py`:
```python
n_files = len(sequences)
threshold = max(1, int(n_files * min_coverage))
symbol_file_count = Counter()
for seq in sequences:
    seen = set()
    for _, text, _ in seq:
        symbol_file_count[text] += 1 if text not in seen else 0
        seen.add(text)
keep = {text for text, count in symbol_file_count.items() if count >= threshold}
```

A symbol is counted once per file (not once per occurrence) to avoid skew from files that repeat the same symbol many times.

## Consequences

**Positive:**
- Removes noise before clustering, improving cluster quality.
- Prevents rare one-off function calls from creating spurious n-gram matches.
- The `common` vs `other` cluster distinction is sharper because the filter removes tokens that would appear in neither.

**Negative:**
- With large codebases (600+ methods), 20% threshold may be too aggressive — a symbol needs 120+ occurrences to survive.
  - Mitigation: `--min-coverage` flag lets users tune per codebase.
  - Production code often needs lower values (`0.05`) because methods are more diverse than tests.
- The threshold is relative, not absolute. A 3-file project keeps anything in 1+ files (`max(1, 3*0.2)` = 1).

## Alternatives Considered

- **No filter**: CRX produces `(a+b+c+d+e+f+g+h+i+j+...)+` — the vocabulary is too large to be informative.
- **Absolute threshold**: `min_occurrences=5`. Doesn't scale — works for small projects, wrong for large ones.
- **TF-IDF style weighting**: More sophisticated but adds complexity. The simple coverage filter works well in practice.
