Skip to content

Commit 326869c

Browse files
authored
Remove last weak AI-signal rules from default pack (#26)
1 parent 043417f commit 326869c

5 files changed

Lines changed: 9 additions & 210 deletions

File tree

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,7 @@ Current checks focus on patterns that often show up in unreviewed generated code
138138
- [generic status envelopes](src/rules/generic-status-envelopes/README.md)
139139
- [generic record casts](src/rules/generic-record-casts/README.md)
140140
- [stringified unknown errors](src/rules/stringified-unknown-errors/README.md)
141-
- [async wrapper / `return await` noise](src/rules/async-noise/README.md)
142141
- [pass-through wrappers](src/rules/pass-through-wrappers/README.md)
143-
- [duplicate helper/function signatures across source files](src/rules/duplicate-function-signatures/README.md)
144142
- [duplicated test mock/setup patterns](src/rules/duplicate-mock-setup/README.md)
145143

146144
`scan` reports raw + normalized scores, hotspot tables, and grouped findings. Use `--json` when you want the full evidence payload.

src/default-registry.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@ import { javascriptLikeLanguage } from "./languages/javascript-like";
1212
import { jsonReporter } from "./reporters/json";
1313
import { lintReporter } from "./reporters/lint";
1414
import { textReporter } from "./reporters/text";
15-
import { asyncNoiseRule } from "./rules/async-noise";
1615
import { emptyCatchRule } from "./rules/empty-catch";
1716
import { errorObscuringRule } from "./rules/error-obscuring";
1817
import { errorSwallowingRule } from "./rules/error-swallowing";
1918
import { promiseDefaultFallbacksRule } from "./rules/promise-default-fallbacks";
2019
import { genericStatusEnvelopesRule } from "./rules/generic-status-envelopes";
2120
import { genericRecordCastsRule } from "./rules/generic-record-casts";
2221
import { stringifiedUnknownErrorsRule } from "./rules/stringified-unknown-errors";
23-
import { duplicateFunctionSignaturesRule } from "./rules/duplicate-function-signatures";
2422
import { passThroughWrappersRule } from "./rules/pass-through-wrappers";
2523
import { duplicateMockSetupRule } from "./rules/duplicate-mock-setup";
2624

@@ -38,7 +36,6 @@ export function createDefaultRegistry(): Registry {
3836
registry.registerFactProvider(directoryMetricsFactProvider);
3937
registry.registerFactProvider(testDuplicationFactProvider);
4038

41-
registry.registerRule(asyncNoiseRule);
4239
registry.registerRule(errorSwallowingRule);
4340
registry.registerRule(errorObscuringRule);
4441
registry.registerRule(emptyCatchRule);
@@ -47,7 +44,6 @@ export function createDefaultRegistry(): Registry {
4744
registry.registerRule(genericRecordCastsRule);
4845
registry.registerRule(stringifiedUnknownErrorsRule);
4946
registry.registerRule(passThroughWrappersRule);
50-
registry.registerRule(duplicateFunctionSignaturesRule);
5147
registry.registerRule(duplicateMockSetupRule);
5248

5349
registry.registerReporter(textReporter);

tests/config.test.ts

Lines changed: 3 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test";
22
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
33
import os from "node:os";
44
import path from "node:path";
5-
import { analyzeRepository } from "../src/core/engine";
6-
import type { AnalyzerConfig } from "../src/config";
7-
import { DEFAULT_CONFIG, loadConfig } from "../src/config";
8-
import { createDefaultRegistry } from "../src/default-registry";
5+
import { loadConfig } from "../src/config";
96

107
const tempDirs: string[] = [];
118

@@ -24,64 +21,7 @@ async function createTempRepo(): Promise<string> {
2421
return rootDir;
2522
}
2623

27-
function withRuleConfig(
28-
ruleId: string,
29-
config: { enabled?: boolean; weight?: number },
30-
): AnalyzerConfig {
31-
return {
32-
...DEFAULT_CONFIG,
33-
rules: {
34-
...DEFAULT_CONFIG.rules,
35-
[ruleId]: config,
36-
},
37-
};
38-
}
39-
40-
function withPathOverride(
41-
files: string[],
42-
rules: Record<string, { enabled?: boolean; weight?: number }>,
43-
): AnalyzerConfig {
44-
return {
45-
...DEFAULT_CONFIG,
46-
overrides: [{ files, rules }],
47-
};
48-
}
49-
5024
describe("rule config support", () => {
51-
test("can disable a rule via config", async () => {
52-
const rootDir = await createTempRepo();
53-
const result = await analyzeRepository(
54-
rootDir,
55-
withRuleConfig("defensive.async-noise", { enabled: false }),
56-
createDefaultRegistry(),
57-
);
58-
59-
expect(
60-
result.findings.filter((finding) => finding.ruleId === "defensive.async-noise"),
61-
).toHaveLength(0);
62-
});
63-
64-
test("can weight a rule via config", async () => {
65-
const rootDir = await createTempRepo();
66-
const baseline = await analyzeRepository(rootDir, DEFAULT_CONFIG, createDefaultRegistry());
67-
const weighted = await analyzeRepository(
68-
rootDir,
69-
withRuleConfig("defensive.async-noise", { weight: 2 }),
70-
createDefaultRegistry(),
71-
);
72-
73-
const baselineAsyncNoise = baseline.findings.find(
74-
(finding) => finding.ruleId === "defensive.async-noise",
75-
);
76-
const weightedAsyncNoise = weighted.findings.find(
77-
(finding) => finding.ruleId === "defensive.async-noise",
78-
);
79-
80-
expect(baselineAsyncNoise).toBeDefined();
81-
expect(weightedAsyncNoise).toBeDefined();
82-
expect(weightedAsyncNoise?.score).toBeCloseTo((baselineAsyncNoise?.score ?? 0) * 2, 6);
83-
});
84-
8525
test("loadConfig reads slop-scan.config.json", async () => {
8626
const rootDir = await createTempRepo();
8727
await writeFile(
@@ -109,62 +49,6 @@ describe("rule config support", () => {
10949
expect(second.ignores).toEqual(["src/nested.ts"]);
11050
});
11151

112-
test("can apply a path-scoped file override", async () => {
113-
const rootDir = await createTempRepo();
114-
await writeFile(
115-
path.join(rootDir, "src", "nested.ts"),
116-
"function fetchRemote(input: string) {\n return Promise.resolve(input);\n}\n\nexport async function loadValue(id: string) {\n return await fetchRemote(id);\n}\n",
117-
);
118-
119-
const result = await analyzeRepository(
120-
rootDir,
121-
withPathOverride(["src/comments.ts"], {
122-
"defensive.async-noise": { enabled: false },
123-
}),
124-
createDefaultRegistry(),
125-
);
126-
127-
const asyncNoiseFindings = result.findings.filter(
128-
(finding) => finding.ruleId === "defensive.async-noise",
129-
);
130-
131-
expect(asyncNoiseFindings).toHaveLength(1);
132-
expect(asyncNoiseFindings[0]?.path).toBe("src/nested.ts");
133-
});
134-
135-
test("can apply a path-scoped directory override", async () => {
136-
const rootDir = await createTempRepo();
137-
138-
await mkdir(path.join(rootDir, "src/rules/defensive"), { recursive: true });
139-
await writeFile(
140-
path.join(rootDir, "src/rules/defensive/service.ts"),
141-
"function fetchRule(input: string) {\n return Promise.resolve(input);\n}\n\nexport async function loadRule(id: string) {\n return await fetchRule(id);\n}\n",
142-
);
143-
144-
await mkdir(path.join(rootDir, "src/other/defensive"), { recursive: true });
145-
await writeFile(
146-
path.join(rootDir, "src/other/defensive/service.ts"),
147-
"function fetchOther(input: string) {\n return Promise.resolve(input);\n}\n\nexport async function loadOther(id: string) {\n return await fetchOther(id);\n}\n",
148-
);
149-
150-
const result = await analyzeRepository(
151-
rootDir,
152-
withPathOverride(["src/rules/**"], {
153-
"defensive.async-noise": { enabled: false },
154-
}),
155-
createDefaultRegistry(),
156-
);
157-
158-
const asyncNoiseFindings = result.findings.filter(
159-
(finding) => finding.ruleId === "defensive.async-noise",
160-
);
161-
162-
expect(asyncNoiseFindings.map((finding) => finding.path).sort()).toEqual([
163-
"src/comments.ts",
164-
"src/other/defensive/service.ts",
165-
]);
166-
});
167-
16852
test("loadConfig reads path-scoped overrides", async () => {
16953
const rootDir = await createTempRepo();
17054
await writeFile(
@@ -174,7 +58,7 @@ describe("rule config support", () => {
17458
{
17559
files: ["src/comments.ts"],
17660
rules: {
177-
"defensive.async-noise": { enabled: false },
61+
"defensive.error-obscuring": { enabled: false },
17862
},
17963
},
18064
],
@@ -187,7 +71,7 @@ describe("rule config support", () => {
18771
{
18872
files: ["src/comments.ts"],
18973
rules: {
190-
"defensive.async-noise": { enabled: false },
74+
"defensive.error-obscuring": { enabled: false },
19175
},
19276
},
19377
]);

tests/fixtures-regression.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@ describe("fixture regression suite", () => {
2828
createDefaultRegistry(),
2929
);
3030

31-
expect(result.repoScore).toBeCloseTo(7.7, 6);
32-
expect(result.findings).toHaveLength(3);
31+
expect(result.repoScore).toBeCloseTo(6.2, 6);
32+
expect(result.findings).toHaveLength(2);
3333
expect([...new Set(result.findings.map((finding) => finding.ruleId))].sort()).toEqual([
34-
"defensive.async-noise",
3534
"defensive.error-obscuring",
3635
"structure.pass-through-wrappers",
3736
]);
@@ -49,7 +48,7 @@ describe("fixture regression suite", () => {
4948
createDefaultRegistry(),
5049
);
5150

52-
expect(result.repoScore).toBeCloseTo(6.7, 6);
51+
expect(result.repoScore).toBeCloseTo(5.2, 6);
5352
expect(result.fileScores[0]?.path).toBe("src/slop/service.ts");
5453
expect(result.directoryScores).toHaveLength(0);
5554
expect(result.fileScores.every((score) => score.path.startsWith("src/slop/"))).toBe(true);
@@ -67,8 +66,8 @@ describe("fixture regression suite", () => {
6766
expect(output.status).toBe(0);
6867

6968
const report = JSON.parse(output.stdout);
70-
expect(report.summary.repoScore).toBeCloseTo(7.7, 6);
71-
expect(report.summary.findingCount).toBe(3);
69+
expect(report.summary.repoScore).toBeCloseTo(6.2, 6);
70+
expect(report.summary.findingCount).toBe(2);
7271
expect(report.directoryScores).toHaveLength(0);
7372
expect(report.fileScores[0].path).toBe("src/service.ts");
7473
});
@@ -87,7 +86,7 @@ describe("fixture regression suite", () => {
8786
"strong Found 1 error-obscuring catch block defensive.error-obscuring",
8887
);
8988
expect(output.stdout).toContain(" at src/error.ts:2:1");
90-
expect(output.stdout).toContain("3 findings");
89+
expect(output.stdout).toContain("2 findings");
9190
expect(output.stdout).not.toContain("slop-scan report");
9291
});
9392

tests/heuristics.test.ts

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ describe("heuristic rule pack", () => {
9696
expect(ruleIds.has("api.generic-status-envelopes")).toBe(true);
9797
expect(ruleIds.has("types.generic-record-casts")).toBe(true);
9898
expect(ruleIds.has("defensive.stringified-unknown-errors")).toBe(true);
99-
expect(ruleIds.has("defensive.async-noise")).toBe(true);
10099
expect(ruleIds.has("structure.pass-through-wrappers")).toBe(true);
101100

102101
expect(result.fileScores.some((score) => score.path === "src/service.ts")).toBe(true);
@@ -537,83 +536,6 @@ describe("heuristic rule pack", () => {
537536
).toBe(false);
538537
});
539538

540-
test("flags duplicated helper signatures across source files", async () => {
541-
const rootDir = await createTempRepo({
542-
"src/users/normalize.ts": [
543-
"export function normalizeUserId(input: string) {",
544-
" const trimmed = input.trim().toLowerCase();",
545-
" if (!trimmed.startsWith('usr_')) {",
546-
" return `usr_${trimmed}`;",
547-
" }",
548-
"",
549-
" return trimmed;",
550-
"}",
551-
"",
552-
].join("\n"),
553-
"src/teams/normalize.ts": [
554-
"export function normalizeTeamId(value: string) {",
555-
" const cleaned = value.trim().toLowerCase();",
556-
" if (!cleaned.startsWith('team_')) {",
557-
" return `team_${cleaned}`;",
558-
" }",
559-
"",
560-
" return cleaned;",
561-
"}",
562-
"",
563-
].join("\n"),
564-
"src/accounts/normalize.ts": [
565-
"export function normalizeAccountId(raw: string) {",
566-
" const normalized = raw.trim().toLowerCase();",
567-
" if (!normalized.startsWith('acct_')) {",
568-
" return `acct_${normalized}`;",
569-
" }",
570-
"",
571-
" return normalized;",
572-
"}",
573-
"",
574-
].join("\n"),
575-
"tests/helpers.test.ts": [
576-
"function normalizeTestId(input: string) {",
577-
" const trimmed = input.trim().toLowerCase();",
578-
" if (!trimmed.startsWith('test_')) {",
579-
" return `test_${trimmed}`;",
580-
" }",
581-
"",
582-
" return trimmed;",
583-
"}",
584-
"",
585-
"export { normalizeTestId };",
586-
"",
587-
].join("\n"),
588-
});
589-
590-
const result = await analyzeRepository(rootDir, DEFAULT_CONFIG, createDefaultRegistry());
591-
const duplicateFindings = result.findings.filter(
592-
(finding) => finding.ruleId === "structure.duplicate-function-signatures",
593-
);
594-
595-
expect(duplicateFindings).toHaveLength(3);
596-
expect(duplicateFindings.every((finding) => finding.path?.startsWith("src/"))).toBe(true);
597-
expect(
598-
duplicateFindings[0]?.evidence.some((entry) => entry.includes("repeated in 3 files")),
599-
).toBe(true);
600-
expect(
601-
duplicateFindings[0]?.locations.some(
602-
(location) => location.path === "src/users/normalize.ts",
603-
),
604-
).toBe(true);
605-
expect(
606-
duplicateFindings[0]?.locations.some(
607-
(location) => location.path === "src/teams/normalize.ts",
608-
),
609-
).toBe(true);
610-
expect(
611-
duplicateFindings[0]?.locations.some(
612-
(location) => location.path === "src/accounts/normalize.ts",
613-
),
614-
).toBe(true);
615-
});
616-
617539
test("stays quiet on a small clean repo", async () => {
618540
const rootDir = await createTempRepo({
619541
"src/index.ts": [

0 commit comments

Comments
 (0)