fix: stop issues --overview noise suggestions on non-noisy repos#27
Conversation
Gate the "Suggested actions to reduce noise" section behind two absolute floors, AND-ed with the existing relative rules, so it stops firing on repositories that aren't actually noisy: - NOISE_MIN_TOTAL (200): suppress the whole section unless the repo has a substantial issue volume. Kept above the per-pattern floor so it does independent work rather than being subsumed by it. - NOISE_MIN_PATTERN (100): a pattern must produce enough issues on its own. Without it, a long tail of tiny patterns drags the median to ~3, making a 9-issue pattern look "3x the median" and get flagged as noise. Also harden the relative rules: the >=10% share rule now only applies with >=8 distinct patterns (with fewer, an even split already exceeds 10% each), and the >=3x multiple rule measures against the median (new medianOf) instead of the mean, so one huge pattern can't inflate the baseline and mask smaller disproportionate patterns. Co-Authored-By: Claude <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Duplication | 0 |
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Pull Request Overview
This PR successfully implements absolute thresholds and median-based outlier detection to refine noise suggestions, aligning with the technical specifications. Codacy quality results are up to standards, and all required test scenarios are covered in the unit tests.
A logic refinement is suggested for the NOISE_MIN_PATTERNS_FOR_SHARE constant to better achieve the goal of suppressing suggestions in balanced environments. The current threshold of 8 allows repositories with 8-10 patterns to still flag every pattern as noisy despite a balanced distribution.
Test suggestions
- Section is suppressed when total issues are below the 200 floor
- Individual patterns below the 100 floor are ignored despite high relative share
- Share rule (10%) is disabled when there are fewer than 8 patterns
- Median-based calculation identifies secondary noisy patterns that a mean-based baseline would mask
- medianOf correctly calculates values for both odd and even length arrays
TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback
| const NOISE_MIN_TOTAL = 200; | ||
| const NOISE_MIN_PATTERN = 100; | ||
| const NOISE_SHARE = 0.1; | ||
| const NOISE_MIN_PATTERNS_FOR_SHARE = 8; |
There was a problem hiding this comment.
⚪ LOW RISK
Suggestion: To ensure that a perfectly balanced repository does not trigger noise suggestions (where every pattern is suggested for disabling), this threshold should be set to 11. With the current value of 8, a repository with 8, 9, or 10 evenly distributed patterns will still flag every pattern as 'noisy' because their individual share (12.5% down to 10%) meets or exceeds the 10% threshold. Increasing the floor to 11 ensures the 10% share rule only triggers for patterns that are actually disproportionate.
| const NOISE_MIN_PATTERNS_FOR_SHARE = 8; | |
| const NOISE_MIN_PATTERNS_FOR_SHARE = 11; |
There was a problem hiding this comment.
Good catch — this is mathematically right. An even split of N patterns gives each a 1/N share, and 1/N only drops below the 10% threshold once N > 10, so at 8–10 patterns a balanced repo would flag every pattern. Bumped NOISE_MIN_PATTERNS_FOR_SHARE to 11 and added a regression test for the 10-evenly-distributed-patterns case (which would have failed at 8).
🤖 Generated by /pr-fixup command
There was a problem hiding this comment.
Code Review
This pull request refines the noise reduction suggestions in the issues --overview command to prevent false positives on low-volume repositories. It introduces absolute floors for total issues (200) and per-pattern issues (100), limits the 10% share rule to repositories with at least 8 distinct patterns, and switches the multiple rule to measure against the median instead of the mean. The review feedback suggests renaming the NOISE_AVG_MULTIPLE constant to NOISE_MEDIAN_MULTIPLE in the code, tests, and documentation to accurately reflect this transition from mean to median.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // - multiple: it has at least NOISE_AVG_MULTIPLE times the *median* issues-per- | ||
| // pattern. Using the median (not the mean) keeps one huge pattern from inflating | ||
| // the baseline and masking smaller-but-still-disproportionate patterns. | ||
| const NOISE_MIN_TOTAL = 200; | ||
| const NOISE_MIN_PATTERN = 100; | ||
| const NOISE_SHARE = 0.1; | ||
| const NOISE_MIN_PATTERNS_FOR_SHARE = 8; | ||
| const NOISE_AVG_MULTIPLE = 3; |
There was a problem hiding this comment.
Since the noise suggestion logic has been updated to use the median instead of the average (mean), the constant name NOISE_AVG_MULTIPLE is now misleading. Consider renaming it to NOISE_MEDIAN_MULTIPLE to accurately reflect its purpose and improve code maintainability.
| // - multiple: it has at least NOISE_AVG_MULTIPLE times the *median* issues-per- | |
| // pattern. Using the median (not the mean) keeps one huge pattern from inflating | |
| // the baseline and masking smaller-but-still-disproportionate patterns. | |
| const NOISE_MIN_TOTAL = 200; | |
| const NOISE_MIN_PATTERN = 100; | |
| const NOISE_SHARE = 0.1; | |
| const NOISE_MIN_PATTERNS_FOR_SHARE = 8; | |
| const NOISE_AVG_MULTIPLE = 3; | |
| // - multiple: it has at least NOISE_MEDIAN_MULTIPLE times the *median* issues-per- | |
| // pattern. Using the median (not the mean) keeps one huge pattern from inflating | |
| // the baseline and masking smaller-but-still-disproportionate patterns. | |
| const NOISE_MIN_TOTAL = 200; | |
| const NOISE_MIN_PATTERN = 100; | |
| const NOISE_SHARE = 0.1; | |
| const NOISE_MIN_PATTERNS_FOR_SHARE = 8; | |
| const NOISE_MEDIAN_MULTIPLE = 3; |
There was a problem hiding this comment.
Agreed — the name was misleading now that it multiplies the median. Renamed NOISE_AVG_MULTIPLE → NOISE_MEDIAN_MULTIPLE across the declaration, its usage, and the docs.
🤖 Generated by /pr-fixup command
| if (total < NOISE_MIN_TOTAL) return []; | ||
| const shareFloor = NOISE_SHARE * total; | ||
| const avgFloor = NOISE_AVG_MULTIPLE * average; | ||
| const medianFloor = NOISE_AVG_MULTIPLE * medianOf(patterns.map((p) => p.total)); |
There was a problem hiding this comment.
There was a problem hiding this comment.
Done — updated the usage to NOISE_MEDIAN_MULTIPLE along with the declaration.
🤖 Generated by /pr-fixup command
| - **Overview mode** (`-O, --overview`): seven count tables — Category, Severity, Language, Tag, Pattern, Author, False Positives | ||
| - The False Positives table relabels the API's raw bucket names via `FALSE_POSITIVE_LABELS`: `belowThreshold` → "Not a False Positive", `equalOrAboveThreshold` → "Potential False Positive" (the threshold is on FP probability, so at/above = potential FP — matching `printIssueCard`) | ||
| - **Noise suggestions**: after the tables, `detectNoisyPatterns()` flags patterns that account for ≥10% of all issues (`NOISE_SHARE`) **or** have ≥3× the average issues-per-pattern (`NOISE_AVG_MULTIPLE`), sorted by count desc. For each, `resolvePatternTool()` maps the pattern ID to its owning tool by matching `Tool.prefix` (e.g. `Bandit_B101` → prefix `Bandit_`; longest match wins) against the global tool list (`fetchAllTools()` / `ToolsService.listTools`). Resolved ones print a `> codacy pattern <tool> <patternId> --disable` line under "Suggested actions to reduce noise". Patterns whose tool can't be resolved (no/unmatched prefix) are **silently discarded**. The tools fetch only happens when noisy patterns exist; JSON output is unaffected (raw counts only) | ||
| - **Noise suggestions**: after the tables, `detectNoisyPatterns()` flags noisy patterns, sorted by count desc. A pattern must clear **two absolute floors** and show a **relative signal**: (1) the repo must have at least `NOISE_MIN_TOTAL` (200) issues total, else the whole section is suppressed — kept above `NOISE_MIN_PATTERN` so it does independent work (were they equal, any pattern clearing the per-pattern floor would already push the repo past an equal total floor, making it dead code); (2) the individual pattern must have at least `NOISE_MIN_PATTERN` (100) issues — this AND-gate is what stops a long tail of tiny patterns (which drags the median to ~3) from making a 9-issue pattern look "3× the median"; (3) *and* it must either account for ≥`NOISE_SHARE` (10%) of all issues **or** have ≥`NOISE_AVG_MULTIPLE` (3×) the **median** issues-per-pattern. The share rule only applies when there are at least `NOISE_MIN_PATTERNS_FOR_SHARE` (8) distinct patterns — with fewer patterns an even split already exceeds 10% each, so the signal is meaningless. The median (not the mean, via `medianOf()`) is deliberate: a single huge pattern would inflate a mean baseline and mask smaller-but-still-disproportionate patterns. For each noisy pattern, `resolvePatternTool()` maps the pattern ID to its owning tool by matching `Tool.prefix` (e.g. `Bandit_B101` → prefix `Bandit_`; longest match wins) against the global tool list (`fetchAllTools()` / `ToolsService.listTools`). Resolved ones print a `> codacy pattern <tool> <patternId> --disable` line under "Suggested actions to reduce noise". Patterns whose tool can't be resolved (no/unmatched prefix) are **silently discarded**. The tools fetch only happens when noisy patterns exist; JSON output is unaffected (raw counts only) |
There was a problem hiding this comment.
Update the reference to NOISE_AVG_MULTIPLE to NOISE_MEDIAN_MULTIPLE in the documentation to match the renamed constant.
| - **Noise suggestions**: after the tables, `detectNoisyPatterns()` flags noisy patterns, sorted by count desc. A pattern must clear **two absolute floors** and show a **relative signal**: (1) the repo must have at least `NOISE_MIN_TOTAL` (200) issues total, else the whole section is suppressed — kept above `NOISE_MIN_PATTERN` so it does independent work (were they equal, any pattern clearing the per-pattern floor would already push the repo past an equal total floor, making it dead code); (2) the individual pattern must have at least `NOISE_MIN_PATTERN` (100) issues — this AND-gate is what stops a long tail of tiny patterns (which drags the median to ~3) from making a 9-issue pattern look "3× the median"; (3) *and* it must either account for ≥`NOISE_SHARE` (10%) of all issues **or** have ≥`NOISE_AVG_MULTIPLE` (3×) the **median** issues-per-pattern. The share rule only applies when there are at least `NOISE_MIN_PATTERNS_FOR_SHARE` (8) distinct patterns — with fewer patterns an even split already exceeds 10% each, so the signal is meaningless. The median (not the mean, via `medianOf()`) is deliberate: a single huge pattern would inflate a mean baseline and mask smaller-but-still-disproportionate patterns. For each noisy pattern, `resolvePatternTool()` maps the pattern ID to its owning tool by matching `Tool.prefix` (e.g. `Bandit_B101` → prefix `Bandit_`; longest match wins) against the global tool list (`fetchAllTools()` / `ToolsService.listTools`). Resolved ones print a `> codacy pattern <tool> <patternId> --disable` line under "Suggested actions to reduce noise". Patterns whose tool can't be resolved (no/unmatched prefix) are **silently discarded**. The tools fetch only happens when noisy patterns exist; JSON output is unaffected (raw counts only) | |
| - **Noise suggestions**: after the tables, `detectNoisyPatterns()` flags noisy patterns, sorted by count desc. A pattern must clear **two absolute floors** and show a **relative signal**: (1) the repo must have at least `NOISE_MIN_TOTAL` (200) issues total, else the whole section is suppressed — kept above `NOISE_MIN_PATTERN` so it does independent work (were they equal, any pattern clearing the per-pattern floor would already push the repo past an equal total floor, making it dead code); (2) the individual pattern must have at least `NOISE_MIN_PATTERN` (100) issues — this AND-gate is what stops a long tail of tiny patterns (which drags the median to ~3) from making a 9-issue pattern look "3× the median"; (3) *and* it must either account for ≥`NOISE_SHARE` (10%) of all issues **or** have ≥`NOISE_MEDIAN_MULTIPLE` (3×) the **median** issues-per-pattern. The share rule only applies when there are at least `NOISE_MIN_PATTERNS_FOR_SHARE` (8) distinct patterns — with fewer patterns an even split already exceeds 10% each, so the signal is meaningless. The median (not the mean, via `medianOf()`) is deliberate: a single huge pattern would inflate a mean baseline and mask smaller-but-still-disproportionate patterns. For each noisy pattern, `resolvePatternTool()` maps the pattern ID to its owning tool by matching `Tool.prefix` (e.g. `Bandit_B101` → prefix `Bandit_` ; longest match wins) against the global tool list (`fetchAllTools()` / `ToolsService.listTools`). Resolved ones print a `> codacy pattern <tool> <patternId> --disable` line under "Suggested actions to reduce noise". Patterns whose tool can't be resolved (no/unmatched prefix) are **silently discarded**. The tools fetch only happens when noisy patterns exist; JSON output is unaffected (raw counts only) |
There was a problem hiding this comment.
Done — updated the constant name in AGENTS.md, and also in SPECS/commands/issues.md, the changelog, and the changeset for consistency.
🤖 Generated by /pr-fixup command
- Raise NOISE_MIN_PATTERNS_FOR_SHARE 8 -> 11 (Codacy): an even split of N patterns gives each 1/N share, which only drops below the 10% threshold once N > 10, so at 8-10 patterns a perfectly balanced repo would flag every pattern. Add a regression test for the 10-evenly-distributed-patterns case. - Rename NOISE_AVG_MULTIPLE -> NOISE_MEDIAN_MULTIPLE (Gemini): the constant now multiplies the median, not the mean, so the old name was misleading. Renamed across the declaration, its usage, and all docs. Co-Authored-By: Claude <noreply@anthropic.com>
Summary
issues --overviewwas suggesting patterns to disable ("Suggested actions to reduce noise") even on repositories that aren't noisy — e.g. a repo with ~20 issues, orcodacy-website(245 issues) where a long tail of tiny patterns dragged the median to 3, making a 9-issue pattern look "3× the median".NOISE_MIN_TOTAL(200) suppresses the whole section unless the repo has substantial volume, andNOISE_MIN_PATTERN(100) requires a pattern to produce enough issues on its own. The total floor is deliberately kept above the per-pattern floor so it does independent work.medianOf) instead of the mean, so a single huge pattern can't inflate the baseline and mask smaller disproportionate patterns.Test plan
npm test— 464 tests pass (4 new, each isolating one floor/rule)npm run build— type-checks cleannode dist/index.js issues gh codacy codacy-website --overview— no "Suggested actions to reduce noise" section (worst pattern is 55, below the per-pattern floor)🤖 Generated with Claude Code