aislop v0.9.3. We measured the noise. Then we cut it by 38%.
A circulating comment suggested aislop produced too much noise on real-world code. The specific findings it cited didn't actually reproduce on our codebase — but the underlying critique was fair: a quality gate that cries wolf gets ignored. So we put numbers on it. 70 popular open-source repos, seven languages, eight iteration rounds, 35 new regression tests, and a 38% reduction in cohort-wide findings — without disabling a single rule.
For most of aislop's history we tuned rules against our own codebases and a handful of trending projects. That's fine for shipping early, but it leaves blind spots: every language has documentation conventions, intentional code patterns, and ecosystem-level injections that look exactly like the AI slop our rules were built to catch. When the rule can't tell them apart, you get noise. Enough noise and developers learn to scroll past your output.
v0.9.3 is the receipts release. We ran the numbers. We fixed what was wrong. We kept the regression tests.
The experiment
We scanned 70 popular open-source repositories — 10 each across TypeScript/JavaScript, Python, Go, Rust, Ruby, PHP, and Java. Names you know: pytest, pydantic, mypy, vue/core, tailwindcss, guava, rubocop, faker, phpunit, regex, ripgrep, composer, laravel/framework, and 57 more.
Baseline cohort: 32,840 findings.
For every rule that fired heavily, we sampled the actual code being flagged and asked one question: is this AI slop, or is it the language's documentation convention? An interface implementation? A bundler-injected global? A test-helper pattern?
What we found
A handful of false-positive classes kept showing up:
security/evalmatched$obj->eval(...)in PHP — Predis Lua-script calls, not PHP'seval()language construct. 28 of 29 PHP hits were this pattern.ai-slop/thin-wrappermatchedpublic function valid(): bool { return isset(...); }. The JS function-shape regex didn't require anexport, so PHP interface implementations (Countable::count,Iterator::valid) and Java methods got swept in. 325 hits across the cohort.ai-slop/hallucinated-importflaggedfrom _pytest.runner import x835 times in pytest alone. Pytest's own internalsrc/_pytest/package wasn't declared inpyproject.toml, so the rule treated it as a missing dependency.ai-slop/narrative-commentflagged every Javadoc, PHPDoc, and YARD block above a declaration. 1,230 hits in Guava alone — all on standard Javadoc.eslint/no-undefflaggedDEV/BROWSER/VERSIONin Vue 777 times. These are conventionaldefineinjections every modern bundler does.ai-slop/rust-non-test-unwrapflagged.unwrap()inside/*! ... */doc comments in theregexcrate. Those are```rustexample blocks — teaching shorthand, not production code.
These aren't quirks. They're the language conventions developers expect their linter to understand.
Precision, not suppression
The lazy fix when you find a noisy rule is to turn it off. We didn't.
Every change in v0.9.3 tightens detection. The slop-signal paths still fire — // Matches X, // This function does N things, // First it ... then it ... finally it are all still caught, because those are the patterns the rule was designed for. What changed is that the rule now distinguishes those AI-style restatements from the genuine documentation around them.
| Pattern | Before | After |
|---|---|---|
| Javadoc above a class, no slop signal | flagged | exempt |
Javadoc starting with Represents X / Wraps Y | flagged | still flagged |
catch (Exception ignored) | flagged | exempt |
catch (Exception e) { } (empty) | flagged | still flagged |
from X import Y as Y (PEP 484 re-export) | flagged | exempt |
from X import Y where Y is never used | flagged | still flagged |
$obj->eval(...) (Redis Lua) | flagged | exempt |
Top-level eval($code) | flagged | still flagged |
How we got here
This wasn't one diff. We iterated eight rounds — each round sampled the new top-of-list false-positive class, traced it back to the specific regex or heuristic that was misfiring, and tightened the rule. After every round we re-scanned all 70 repos to confirm the change moved the needle without breaking the cases the rule was supposed to catch.
Every fix landed with regression tests. The suite grew from 800 → 835 cases, all green.
The numbers
Same 70 repos, same commits, before and after the full v0.9.3 change set:
| Rule | Before | After | Δ |
|---|---|---|---|
| ai-slop/narrative-comment | 13,817 | 6,250 | −55% |
| ai-slop/hallucinated-import | 2,161 | 900 | −58% |
| eslint/no-undef | 926 | 314 | −66% |
| ai-slop/thin-wrapper | 569 | 244 | −57% |
| ai-slop/trivial-comment | 4,035 | 3,190 | −21% |
| ai-slop/swallowed-exception | 694 | 497 | −28% |
| security/eval (Ruby) | 87 | 26 | −70% |
| security/eval (PHP) | 29 | 12 | −59% |
| Total cohort findings | 32,840 | 20,366 | −38% |
Several popular projects moved from unranked (score 0) to honest scores. A few highlights:
And four more popular projects moved from score 0 to a positive score for the first time: vuejs/core, pytest, tailwindcss, and rust-lang/regex.
What ships
- Comment rules recognize Javadoc, PHPDoc, JSDoc, YARD, RDoc, and Go struct-field docs as documentation. The catch-all "long narrative" rule no longer fires above declarations; explicit slop signals (
^This function/method/class,^It does/handles/...,^First/Then/Finally it) replace the length-only heuristic. - Hallucinated-import discovers local Python packages via
__init__.pyscanning and honors PEP 484 re-exports. - Security/eval has a proper lookbehind for method-call forms.
- Thin-wrapper patterns are language-gated to JS/TS and Python.
- Swallowed-exception allows
tolerated/ignored/expectedcatch parameters. - Rust non-test-unwrap skips
/*! ... */doc-comment example blocks;xxx_test.rs(singular) recognized as test file. - Oxlint registers conventional bundler globals (
__DEV__and friends) for every project, plus discovers ambient.d.tsdeclarations and SST globals automatically. - Source-file walker filters
*.min.js,*.bundle.js, honors Biome'sfiles.includes, and ignores.pnpm-store/. - Dangerous innerHTML respects
aislop-ignore/biome-ignore/eslint-disabledirectives and JSON-LD structured data.
What's next
A 38% drop is meaningful, but it isn't the finish line. The remaining findings include real slop, real complexity issues, and a long tail of cases where the rule is right but the call is debatable. We'll keep iterating — and we'll keep posting the receipts when we do.
The whole point of a quality gate is that it tells you the truth. v0.9.3 makes aislop a little more honest.
Install
Full changelog on GitHub. Star the repo to get the next release in your feed.