Skip to content

Commit f004607

Browse files
committed
fix(ci): keep slop hotspot matching stable
1 parent 2bc4b81 commit f004607

2 files changed

Lines changed: 68 additions & 13 deletions

File tree

scripts/slop-review.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,43 @@ describe("slop review helpers", () => {
9191
]);
9292
});
9393

94+
test("delta comparison treats existing directory fan-out hotspots as existing findings", () => {
95+
const baseHotspot: SlopReport = {
96+
summary: { findingCount: 1 },
97+
findings: [
98+
{
99+
ruleId: "structure.directory-fanout-hotspot",
100+
family: "structure",
101+
severity: "medium",
102+
scope: "directory",
103+
message: "Directory fan-out is a repo hotspot (9 files vs baseline 3.0)",
104+
evidence: ["baseline=3.00", "threshold=7", "fileCount=9"],
105+
score: 9,
106+
path: "scripts",
107+
locations: [{ path: "scripts", line: 1, column: 1 }],
108+
},
109+
],
110+
};
111+
const headHotspot: SlopReport = {
112+
summary: { findingCount: 1 },
113+
findings: [
114+
{
115+
ruleId: "structure.directory-fanout-hotspot",
116+
family: "structure",
117+
severity: "medium",
118+
scope: "directory",
119+
message: "Directory fan-out is a repo hotspot (11 files vs baseline 3.0)",
120+
evidence: ["baseline=3.00", "threshold=7", "fileCount=11"],
121+
score: 11,
122+
path: "scripts",
123+
locations: [{ path: "scripts", line: 1, column: 1 }],
124+
},
125+
],
126+
};
127+
128+
expect(buildDeltaOccurrences(baseHotspot, headHotspot)).toHaveLength(0);
129+
});
130+
94131
test("agent context groups new findings by file and emits hunk-friendly annotations", () => {
95132
const context = buildAgentContext(baseReport, headReport);
96133

scripts/slop-review.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,36 @@ function uniqueSortedLocations(finding: SlopFinding): SlopFindingLocation[] {
127127
});
128128
}
129129

130+
/** Builds stable identity fields for matching findings across base/head reports. */
131+
function signaturePayloadForFinding(
132+
finding: SlopFinding,
133+
path: string,
134+
locations: SlopFindingLocation[],
135+
) {
136+
const basePayload = {
137+
ruleId: finding.ruleId,
138+
family: finding.family,
139+
severity: finding.severity,
140+
scope: finding.scope,
141+
path,
142+
locations: locations.map((location) => ({
143+
line: location.line,
144+
column: location.column ?? 1,
145+
})),
146+
};
147+
148+
if (finding.ruleId === "structure.directory-fanout-hotspot") {
149+
// The analyzer embeds repo-wide baseline/threshold values in this rule's text.
150+
return basePayload;
151+
}
152+
153+
return {
154+
...basePayload,
155+
message: finding.message,
156+
evidence: finding.evidence,
157+
};
158+
}
159+
130160
export function buildFileFindingOccurrences(report: SlopReport | null | undefined) {
131161
const occurrences: FileFindingOccurrence[] = [];
132162

@@ -147,19 +177,7 @@ export function buildFileFindingOccurrences(report: SlopReport | null | undefine
147177
continue;
148178
}
149179

150-
const signature = JSON.stringify({
151-
ruleId: finding.ruleId,
152-
family: finding.family,
153-
severity: finding.severity,
154-
scope: finding.scope,
155-
message: finding.message,
156-
path,
157-
evidence: finding.evidence,
158-
locations: locations.map((location) => ({
159-
line: location.line,
160-
column: location.column ?? 1,
161-
})),
162-
});
180+
const signature = JSON.stringify(signaturePayloadForFinding(finding, path, locations));
163181

164182
occurrences.push({
165183
signature,

0 commit comments

Comments
 (0)