@mmnto/cli 1.15.7 → 1.15.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/parsers/triage-dedup.d.ts +42 -2
- package/dist/parsers/triage-dedup.d.ts.map +1 -1
- package/dist/parsers/triage-dedup.js +73 -58
- package/dist/parsers/triage-dedup.js.map +1 -1
- package/dist/parsers/triage-dedup.test.js +163 -103
- package/dist/parsers/triage-dedup.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,8 +1,48 @@
|
|
|
1
1
|
import type { NormalizedBotFinding } from './bot-review-parser.js';
|
|
2
2
|
import type { CategorizedFinding } from './triage-types.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Extract significant words from text (strip stopwords, lowercase).
|
|
5
|
+
*
|
|
6
|
+
* Retained as a public helper for downstream tooling (e.g., the deferred
|
|
7
|
+
* `--no-dedup` debug flag, ad-hoc analysis scripts) even though
|
|
8
|
+
* `deduplicateFindings` no longer uses it after mmnto-ai/totem#1666.
|
|
9
|
+
*/
|
|
4
10
|
export declare function extractKeywords(text: string): Set<string>;
|
|
5
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Jaccard similarity between two keyword sets.
|
|
13
|
+
*
|
|
14
|
+
* Retained alongside `extractKeywords` for the same reason — see that
|
|
15
|
+
* function's note.
|
|
16
|
+
*/
|
|
6
17
|
export declare function jaccardSimilarity(a: Set<string>, b: Set<string>): number;
|
|
18
|
+
/**
|
|
19
|
+
* Deduplicate bot findings using deterministic comment-id identity
|
|
20
|
+
* (mmnto-ai/totem#1666; strategy upstream-feedback item 024).
|
|
21
|
+
*
|
|
22
|
+
* Two findings with different `rootCommentId` are ALWAYS distinct, even
|
|
23
|
+
* when their bodies are byte-identical and they anchor at the same
|
|
24
|
+
* `(file, line)`. This forecloses the LC#80 R3 failure mode where six
|
|
25
|
+
* GCA findings on `compiled-rules.json:598` (each anchored at the rule-
|
|
26
|
+
* section start line) collapsed into one entry under the prior
|
|
27
|
+
* proximity + Jaccard fuzzy-merge semantics.
|
|
28
|
+
*
|
|
29
|
+
* Cross-bot independence is now a feature, not a bug: when CR and GCA
|
|
30
|
+
* independently flag the same `(file, line)`, both findings surface so
|
|
31
|
+
* the consumer can read the cross-bot agreement as elevated-confidence
|
|
32
|
+
* signal (per the strategy bot-nuance pattern). Today's previous
|
|
33
|
+
* cross-bot merge silently masked exactly that signal.
|
|
34
|
+
*
|
|
35
|
+
* Synthesized review-body findings (`file === '(review body)'`, no
|
|
36
|
+
* `rootCommentId`) fall back to a `(file, body)` Map key. Body-hash
|
|
37
|
+
* collisions are negligible at this scale: the input space is per-
|
|
38
|
+
* review-body line items only, and identical-body findings on that
|
|
39
|
+
* pseudo-path are themselves duplicates.
|
|
40
|
+
*
|
|
41
|
+
* The `mergedWith` field on the output is left undefined under strict-
|
|
42
|
+
* by-id semantics. Keeping the field on the schema (rather than
|
|
43
|
+
* removing it) avoids forcing downstream display consumers into a
|
|
44
|
+
* coordinated update; readers naturally skip the empty/undefined
|
|
45
|
+
* surface.
|
|
46
|
+
*/
|
|
7
47
|
export declare function deduplicateFindings(findings: NormalizedBotFinding[]): CategorizedFinding[];
|
|
8
48
|
//# sourceMappingURL=triage-dedup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage-dedup.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-dedup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"triage-dedup.d.ts","sourceRoot":"","sources":["../../src/parsers/triage-dedup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAyD5D;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAQzD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAKxE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,GAAG,kBAAkB,EAAE,CAoC1F"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { mapToTriageCategory } from './triage-severity-mapper.js';
|
|
2
|
-
const PROXIMITY_THRESHOLD = 3; // lines
|
|
3
|
-
const KEYWORD_OVERLAP_THRESHOLD = 0.3; // 30% Jaccard similarity
|
|
4
2
|
const STOPWORDS = new Set([
|
|
5
3
|
'the',
|
|
6
4
|
'a',
|
|
@@ -55,7 +53,13 @@ const STOPWORDS = new Set([
|
|
|
55
53
|
'not',
|
|
56
54
|
'no',
|
|
57
55
|
]);
|
|
58
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Extract significant words from text (strip stopwords, lowercase).
|
|
58
|
+
*
|
|
59
|
+
* Retained as a public helper for downstream tooling (e.g., the deferred
|
|
60
|
+
* `--no-dedup` debug flag, ad-hoc analysis scripts) even though
|
|
61
|
+
* `deduplicateFindings` no longer uses it after mmnto-ai/totem#1666.
|
|
62
|
+
*/
|
|
59
63
|
export function extractKeywords(text) {
|
|
60
64
|
return new Set(text
|
|
61
65
|
.toLowerCase()
|
|
@@ -63,7 +67,12 @@ export function extractKeywords(text) {
|
|
|
63
67
|
.split(/\s+/)
|
|
64
68
|
.filter((w) => w.length > 2 && !STOPWORDS.has(w)));
|
|
65
69
|
}
|
|
66
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Jaccard similarity between two keyword sets.
|
|
72
|
+
*
|
|
73
|
+
* Retained alongside `extractKeywords` for the same reason — see that
|
|
74
|
+
* function's note.
|
|
75
|
+
*/
|
|
67
76
|
export function jaccardSimilarity(a, b) {
|
|
68
77
|
if (a.size === 0 && b.size === 0)
|
|
69
78
|
return 0;
|
|
@@ -71,64 +80,70 @@ export function jaccardSimilarity(a, b) {
|
|
|
71
80
|
const union = new Set([...a, ...b]);
|
|
72
81
|
return intersection.size / union.size;
|
|
73
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Deduplicate bot findings using deterministic comment-id identity
|
|
85
|
+
* (mmnto-ai/totem#1666; strategy upstream-feedback item 024).
|
|
86
|
+
*
|
|
87
|
+
* Two findings with different `rootCommentId` are ALWAYS distinct, even
|
|
88
|
+
* when their bodies are byte-identical and they anchor at the same
|
|
89
|
+
* `(file, line)`. This forecloses the LC#80 R3 failure mode where six
|
|
90
|
+
* GCA findings on `compiled-rules.json:598` (each anchored at the rule-
|
|
91
|
+
* section start line) collapsed into one entry under the prior
|
|
92
|
+
* proximity + Jaccard fuzzy-merge semantics.
|
|
93
|
+
*
|
|
94
|
+
* Cross-bot independence is now a feature, not a bug: when CR and GCA
|
|
95
|
+
* independently flag the same `(file, line)`, both findings surface so
|
|
96
|
+
* the consumer can read the cross-bot agreement as elevated-confidence
|
|
97
|
+
* signal (per the strategy bot-nuance pattern). Today's previous
|
|
98
|
+
* cross-bot merge silently masked exactly that signal.
|
|
99
|
+
*
|
|
100
|
+
* Synthesized review-body findings (`file === '(review body)'`, no
|
|
101
|
+
* `rootCommentId`) fall back to a `(file, body)` Map key. Body-hash
|
|
102
|
+
* collisions are negligible at this scale: the input space is per-
|
|
103
|
+
* review-body line items only, and identical-body findings on that
|
|
104
|
+
* pseudo-path are themselves duplicates.
|
|
105
|
+
*
|
|
106
|
+
* The `mergedWith` field on the output is left undefined under strict-
|
|
107
|
+
* by-id semantics. Keeping the field on the schema (rather than
|
|
108
|
+
* removing it) avoids forcing downstream display consumers into a
|
|
109
|
+
* coordinated update; readers naturally skip the empty/undefined
|
|
110
|
+
* surface.
|
|
111
|
+
*/
|
|
74
112
|
export function deduplicateFindings(findings) {
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
dedupKey
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const primary = categorized[i];
|
|
87
|
-
const primaryKw = extractKeywords(primary.body);
|
|
88
|
-
const group = [];
|
|
89
|
-
for (let j = i + 1; j < categorized.length; j++) {
|
|
90
|
-
if (consumed.has(j))
|
|
113
|
+
const result = [];
|
|
114
|
+
const seenIds = new Set();
|
|
115
|
+
const seenBodyKeys = new Set();
|
|
116
|
+
for (const finding of findings) {
|
|
117
|
+
let dedupKey;
|
|
118
|
+
if (finding.rootCommentId !== undefined) {
|
|
119
|
+
// Strict-by-id path: GitHub-assigned comment IDs are unique per
|
|
120
|
+
// inline review comment. Two findings with different IDs are always
|
|
121
|
+
// distinct, regardless of file/line/body similarity or which bot
|
|
122
|
+
// emitted them.
|
|
123
|
+
if (seenIds.has(finding.rootCommentId))
|
|
91
124
|
continue;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (candidate.triageCategory !== primary.triageCategory)
|
|
95
|
-
continue;
|
|
96
|
-
// Must be same file
|
|
97
|
-
if (candidate.file !== primary.file)
|
|
98
|
-
continue;
|
|
99
|
-
// Check line proximity
|
|
100
|
-
if (primary.line != null && candidate.line != null) {
|
|
101
|
-
if (Math.abs(primary.line - candidate.line) > PROXIMITY_THRESHOLD)
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
else if (primary.line == null && candidate.line == null) {
|
|
105
|
-
// Both file-level — require high similarity to merge
|
|
106
|
-
const sim = jaccardSimilarity(primaryKw, extractKeywords(candidate.body));
|
|
107
|
-
if (sim < 0.8)
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
// One has a line, one doesn't — require high similarity
|
|
112
|
-
const sim = jaccardSimilarity(primaryKw, extractKeywords(candidate.body));
|
|
113
|
-
if (sim < 0.8)
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
// Check keyword overlap
|
|
117
|
-
const candidateKw = extractKeywords(candidate.body);
|
|
118
|
-
const similarity = jaccardSimilarity(primaryKw, candidateKw);
|
|
119
|
-
if (similarity < KEYWORD_OVERLAP_THRESHOLD)
|
|
120
|
-
continue;
|
|
121
|
-
// Merge
|
|
122
|
-
group.push(candidate);
|
|
123
|
-
consumed.add(j);
|
|
125
|
+
seenIds.add(finding.rootCommentId);
|
|
126
|
+
dedupKey = `id:${finding.rootCommentId}`;
|
|
124
127
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
//
|
|
128
|
-
|
|
128
|
+
else {
|
|
129
|
+
// Body-hash fallback for synthesized findings without an upstream
|
|
130
|
+
// comment ID (today: extractReviewBodyFindings produces these with
|
|
131
|
+
// `file: '(review body)'`). Map key includes `tool` so two
|
|
132
|
+
// synthesized findings from different bots with identical bodies
|
|
133
|
+
// stay distinct — preserves the cross-bot-independence symmetry
|
|
134
|
+
// the strict-by-id path provides for inline findings.
|
|
135
|
+
const key = `${finding.tool}|${finding.file}|${finding.body}`;
|
|
136
|
+
if (seenBodyKeys.has(key))
|
|
137
|
+
continue;
|
|
138
|
+
seenBodyKeys.add(key);
|
|
139
|
+
dedupKey = `body:${finding.tool}|${finding.file}|${finding.body}`;
|
|
129
140
|
}
|
|
130
|
-
|
|
141
|
+
result.push({
|
|
142
|
+
...finding,
|
|
143
|
+
triageCategory: mapToTriageCategory(finding),
|
|
144
|
+
dedupKey,
|
|
145
|
+
});
|
|
131
146
|
}
|
|
132
|
-
return
|
|
147
|
+
return result;
|
|
133
148
|
}
|
|
134
149
|
//# sourceMappingURL=triage-dedup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage-dedup.js","sourceRoot":"","sources":["../../src/parsers/triage-dedup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGlE,MAAM,
|
|
1
|
+
{"version":3,"file":"triage-dedup.js","sourceRoot":"","sources":["../../src/parsers/triage-dedup.ts"],"names":[],"mappings":"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"}
|
|
@@ -47,163 +47,223 @@ describe('jaccardSimilarity', () => {
|
|
|
47
47
|
expect(jaccardSimilarity(a, b)).toBeCloseTo(0.5);
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
|
-
// ─── deduplicateFindings
|
|
50
|
+
// ─── deduplicateFindings (mmnto-ai/totem#1666 — strict-by-id) ──────────
|
|
51
51
|
describe('deduplicateFindings', () => {
|
|
52
|
-
|
|
52
|
+
// ─── Strict-by-id semantics ─────────────────────────
|
|
53
|
+
it('reproduces the LC#80 R3 exhibit: 6 distinct rootCommentIds on the same file:line surface as 6 entries', () => {
|
|
54
|
+
// Pre-#1666 the proximity + Jaccard fuzzy merge collapsed all 6 into
|
|
55
|
+
// one entry. Strict-by-id keeps them distinct because each comment
|
|
56
|
+
// carries a unique GitHub-assigned ID, regardless of how similar
|
|
57
|
+
// the bodies look or how identical the (file, line) anchor is.
|
|
58
|
+
const findings = [
|
|
59
|
+
{
|
|
60
|
+
tool: 'gca',
|
|
61
|
+
severity: 'high',
|
|
62
|
+
file: '.totem/compiled-rules.json',
|
|
63
|
+
line: 598,
|
|
64
|
+
body: 'SystemParam rule severity should be `error` not `warning`',
|
|
65
|
+
rootCommentId: 1001,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
tool: 'gca',
|
|
69
|
+
severity: 'high',
|
|
70
|
+
file: '.totem/compiled-rules.json',
|
|
71
|
+
line: 598,
|
|
72
|
+
body: 'SystemParam rule fileGlobs missing test/spec exclusions',
|
|
73
|
+
rootCommentId: 1002,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
tool: 'gca',
|
|
77
|
+
severity: 'high',
|
|
78
|
+
file: '.totem/compiled-rules.json',
|
|
79
|
+
line: 598,
|
|
80
|
+
body: 'init_resource rule fileGlobs missing test/spec exclusions',
|
|
81
|
+
rootCommentId: 1003,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
tool: 'gca',
|
|
85
|
+
severity: 'high',
|
|
86
|
+
file: '.totem/compiled-rules.json',
|
|
87
|
+
line: 598,
|
|
88
|
+
body: 'SystemParam rule goodExample non-compilable Rust lifetimes',
|
|
89
|
+
rootCommentId: 1004,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
tool: 'gca',
|
|
93
|
+
severity: 'high',
|
|
94
|
+
file: '.totem/compiled-rules.json',
|
|
95
|
+
line: 598,
|
|
96
|
+
body: 'archivedReason `\\b` JSON-escape typo',
|
|
97
|
+
rootCommentId: 1005,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
tool: 'gca',
|
|
101
|
+
severity: 'high',
|
|
102
|
+
file: '.totem/compiled-rules.json',
|
|
103
|
+
line: 598,
|
|
104
|
+
body: 'lesson-a00d6b65 missing from compiled-rules.json',
|
|
105
|
+
rootCommentId: 1006,
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
const result = deduplicateFindings(findings);
|
|
109
|
+
expect(result).toHaveLength(6);
|
|
110
|
+
expect(result.map((r) => r.rootCommentId)).toEqual([1001, 1002, 1003, 1004, 1005, 1006]);
|
|
111
|
+
});
|
|
112
|
+
it('keeps findings with distinct rootCommentIds even when bodies are byte-identical', () => {
|
|
113
|
+
const findings = [
|
|
114
|
+
makeFinding({ file: 'src/auth.ts', line: 10, body: 'Missing semicolon', rootCommentId: 200 }),
|
|
115
|
+
makeFinding({ file: 'src/auth.ts', line: 10, body: 'Missing semicolon', rootCommentId: 201 }),
|
|
116
|
+
];
|
|
117
|
+
const result = deduplicateFindings(findings);
|
|
118
|
+
expect(result).toHaveLength(2);
|
|
119
|
+
});
|
|
120
|
+
it('drops the second finding when two share the same rootCommentId (API duplicate)', () => {
|
|
121
|
+
const findings = [
|
|
122
|
+
makeFinding({ body: 'first', rootCommentId: 999 }),
|
|
123
|
+
makeFinding({ body: 'second (duplicate id)', rootCommentId: 999 }),
|
|
124
|
+
];
|
|
125
|
+
const result = deduplicateFindings(findings);
|
|
126
|
+
expect(result).toHaveLength(1);
|
|
127
|
+
expect(result[0].body).toBe('first'); // first-seen wins
|
|
128
|
+
});
|
|
129
|
+
// ─── Cross-bot independence (strategy bot-nuance pattern 1) ──────
|
|
130
|
+
it('keeps cross-bot findings distinct on the same file:line — agreement is signal, not noise', () => {
|
|
131
|
+
// Pre-#1666 the fuzzy merge collapsed CR + GCA findings on similar
|
|
132
|
+
// bodies into one entry, masking exactly the cross-bot agreement
|
|
133
|
+
// signal the strategy bot-nuance file documents as elevated-
|
|
134
|
+
// confidence. Strict-by-id surfaces both so the triage agent reads
|
|
135
|
+
// the convergence.
|
|
53
136
|
const findings = [
|
|
54
137
|
makeFinding({
|
|
55
138
|
tool: 'coderabbit',
|
|
56
139
|
file: 'src/auth.ts',
|
|
57
140
|
line: 10,
|
|
58
141
|
body: 'SQL injection risk in query builder',
|
|
142
|
+
rootCommentId: 300,
|
|
59
143
|
}),
|
|
60
144
|
makeFinding({
|
|
61
145
|
tool: 'gca',
|
|
62
146
|
file: 'src/auth.ts',
|
|
63
147
|
line: 10,
|
|
64
148
|
body: 'Potential injection vulnerability in SQL query',
|
|
149
|
+
rootCommentId: 301,
|
|
65
150
|
}),
|
|
66
151
|
];
|
|
67
152
|
const result = deduplicateFindings(findings);
|
|
153
|
+
expect(result).toHaveLength(2);
|
|
154
|
+
expect(result.map((r) => r.tool).sort()).toEqual(['coderabbit', 'gca']);
|
|
155
|
+
});
|
|
156
|
+
// ─── Body-hash fallback (synthesized review-body findings) ──────
|
|
157
|
+
it('dedupes review-body findings with identical (file, body) when rootCommentId is absent', () => {
|
|
158
|
+
// extractReviewBodyFindings emits findings with file === '(review body)'
|
|
159
|
+
// and no rootCommentId. The fallback path uses (file, body) as the
|
|
160
|
+
// dedup primitive.
|
|
161
|
+
const findings = [
|
|
162
|
+
makeFinding({ file: '(review body)', body: 'Outside-diff finding text' }),
|
|
163
|
+
makeFinding({ file: '(review body)', body: 'Outside-diff finding text' }),
|
|
164
|
+
];
|
|
165
|
+
const result = deduplicateFindings(findings);
|
|
68
166
|
expect(result).toHaveLength(1);
|
|
69
|
-
expect(result[0].mergedWith).toHaveLength(1);
|
|
70
|
-
expect(result[0].mergedWith[0].tool).toBe('gca');
|
|
71
167
|
});
|
|
72
|
-
it('
|
|
168
|
+
it('keeps review-body findings distinct when bodies differ', () => {
|
|
73
169
|
const findings = [
|
|
74
|
-
makeFinding({
|
|
75
|
-
|
|
76
|
-
line: 10,
|
|
77
|
-
body: 'SQL injection risk via exec call',
|
|
78
|
-
}),
|
|
79
|
-
makeFinding({
|
|
80
|
-
file: 'src/foo.ts',
|
|
81
|
-
line: 10,
|
|
82
|
-
body: 'Trailing whitespace on this line is a typo',
|
|
83
|
-
}),
|
|
170
|
+
makeFinding({ file: '(review body)', body: 'First synthesized finding' }),
|
|
171
|
+
makeFinding({ file: '(review body)', body: 'Second synthesized finding' }),
|
|
84
172
|
];
|
|
85
173
|
const result = deduplicateFindings(findings);
|
|
86
|
-
// security vs nit — should NOT merge
|
|
87
174
|
expect(result).toHaveLength(2);
|
|
88
|
-
expect(result[0].mergedWith).toBeUndefined();
|
|
89
|
-
expect(result[1].mergedWith).toBeUndefined();
|
|
90
175
|
});
|
|
91
|
-
it('
|
|
176
|
+
it('preserves cross-bot independence on the body-hash fallback path (CR + GCA same body → distinct)', () => {
|
|
177
|
+
// Body-hash key includes `tool` so two synthesized findings from
|
|
178
|
+
// different bots with identical bodies stay distinct. Symmetry with
|
|
179
|
+
// the strict-by-id path's cross-bot independence for inline findings
|
|
180
|
+
// (CR R1 review finding on PR #1690 — fixed in this round).
|
|
92
181
|
const findings = [
|
|
93
182
|
makeFinding({
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
body: '
|
|
183
|
+
tool: 'coderabbit',
|
|
184
|
+
file: '(review body)',
|
|
185
|
+
body: 'Identical synthesized finding text',
|
|
97
186
|
}),
|
|
98
187
|
makeFinding({
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
body: '
|
|
188
|
+
tool: 'gca',
|
|
189
|
+
file: '(review body)',
|
|
190
|
+
body: 'Identical synthesized finding text',
|
|
102
191
|
}),
|
|
103
192
|
];
|
|
104
193
|
const result = deduplicateFindings(findings);
|
|
105
|
-
expect(result).toHaveLength(
|
|
106
|
-
expect(result
|
|
194
|
+
expect(result).toHaveLength(2);
|
|
195
|
+
expect(result.map((r) => r.tool).sort()).toEqual(['coderabbit', 'gca']);
|
|
107
196
|
});
|
|
108
|
-
it('does not merge
|
|
197
|
+
it('does not merge a synthesized finding with an inline finding even when bodies match', () => {
|
|
198
|
+
// No-id × has-id mixed case: the inline path is keyed by id, the
|
|
199
|
+
// synthesized path is keyed by (file, body). Their key spaces don't
|
|
200
|
+
// overlap, so they can't collide.
|
|
109
201
|
const findings = [
|
|
110
|
-
makeFinding({
|
|
111
|
-
|
|
112
|
-
line: 10,
|
|
113
|
-
body: 'Credential leak risk in this function',
|
|
114
|
-
}),
|
|
115
|
-
makeFinding({
|
|
116
|
-
file: 'src/auth.ts',
|
|
117
|
-
line: 14,
|
|
118
|
-
body: 'Secret credential exposed in this block',
|
|
119
|
-
}),
|
|
202
|
+
makeFinding({ file: 'src/auth.ts', line: 10, body: 'Missing semicolon', rootCommentId: 400 }),
|
|
203
|
+
makeFinding({ file: '(review body)', body: 'Missing semicolon' }),
|
|
120
204
|
];
|
|
121
205
|
const result = deduplicateFindings(findings);
|
|
122
206
|
expect(result).toHaveLength(2);
|
|
123
207
|
});
|
|
124
|
-
|
|
208
|
+
// ─── Trivial pass-through cases ─────────────────────
|
|
209
|
+
it('preserves all findings when every rootCommentId is distinct', () => {
|
|
125
210
|
const findings = [
|
|
126
|
-
makeFinding({
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
body: 'SQL injection risk via exec call',
|
|
130
|
-
}),
|
|
131
|
-
makeFinding({
|
|
132
|
-
file: 'src/db.ts',
|
|
133
|
-
line: 10,
|
|
134
|
-
body: 'SQL injection risk via exec call',
|
|
135
|
-
}),
|
|
211
|
+
makeFinding({ file: 'src/auth.ts', line: 10, rootCommentId: 1 }),
|
|
212
|
+
makeFinding({ file: 'src/utils.ts', line: 50, rootCommentId: 2 }),
|
|
213
|
+
makeFinding({ file: 'src/config.ts', line: 5, rootCommentId: 3 }),
|
|
136
214
|
];
|
|
137
215
|
const result = deduplicateFindings(findings);
|
|
138
|
-
expect(result).toHaveLength(
|
|
216
|
+
expect(result).toHaveLength(3);
|
|
139
217
|
});
|
|
140
|
-
it('
|
|
218
|
+
it('does not merge findings in different files (sanity check)', () => {
|
|
141
219
|
const findings = [
|
|
142
|
-
makeFinding({
|
|
143
|
-
|
|
144
|
-
line: undefined,
|
|
145
|
-
body: 'This module has security vulnerabilities in the authentication flow',
|
|
146
|
-
}),
|
|
147
|
-
makeFinding({
|
|
148
|
-
file: 'src/auth.ts',
|
|
149
|
-
line: undefined,
|
|
150
|
-
body: 'Security vulnerabilities detected in the authentication flow of this module',
|
|
151
|
-
}),
|
|
220
|
+
makeFinding({ file: 'src/auth.ts', line: 10, body: 'identical', rootCommentId: 10 }),
|
|
221
|
+
makeFinding({ file: 'src/db.ts', line: 10, body: 'identical', rootCommentId: 11 }),
|
|
152
222
|
];
|
|
153
223
|
const result = deduplicateFindings(findings);
|
|
154
|
-
expect(result).toHaveLength(
|
|
155
|
-
|
|
224
|
+
expect(result).toHaveLength(2);
|
|
225
|
+
});
|
|
226
|
+
it('handles empty input', () => {
|
|
227
|
+
expect(deduplicateFindings([])).toEqual([]);
|
|
156
228
|
});
|
|
157
|
-
|
|
229
|
+
// ─── Output schema invariants ───────────────────────
|
|
230
|
+
it('leaves mergedWith undefined under strict-by-id semantics', () => {
|
|
231
|
+
// mergedWith was the fuzzy-merge audit field. Under strict-by-id
|
|
232
|
+
// it never gets populated; the field stays on the schema for
|
|
233
|
+
// backward-compat with downstream display consumers (per design
|
|
234
|
+
// doc Q1).
|
|
158
235
|
const findings = [
|
|
159
|
-
makeFinding({
|
|
160
|
-
|
|
161
|
-
line: 10,
|
|
162
|
-
body: 'SQL injection risk via exec call',
|
|
163
|
-
}),
|
|
164
|
-
makeFinding({
|
|
165
|
-
file: 'src/utils.ts',
|
|
166
|
-
line: 50,
|
|
167
|
-
body: 'Trailing whitespace is a cosmetic nit',
|
|
168
|
-
}),
|
|
169
|
-
makeFinding({
|
|
170
|
-
file: 'src/config.ts',
|
|
171
|
-
line: 5,
|
|
172
|
-
body: 'Missing null check on boundary parameter',
|
|
173
|
-
}),
|
|
236
|
+
makeFinding({ rootCommentId: 50 }),
|
|
237
|
+
makeFinding({ rootCommentId: 51 }),
|
|
174
238
|
];
|
|
175
239
|
const result = deduplicateFindings(findings);
|
|
176
|
-
expect(result).toHaveLength(3);
|
|
177
240
|
for (const r of result) {
|
|
178
241
|
expect(r.mergedWith).toBeUndefined();
|
|
179
242
|
}
|
|
180
243
|
});
|
|
181
|
-
it('
|
|
244
|
+
it('prefixes dedupKey with `id:` for inline findings and `body:` for fallback findings', () => {
|
|
182
245
|
const findings = [
|
|
183
|
-
makeFinding({
|
|
184
|
-
|
|
185
|
-
file: 'src/auth.ts',
|
|
186
|
-
line: 10,
|
|
187
|
-
body: 'Credential leak risk in secret handling',
|
|
188
|
-
}),
|
|
189
|
-
makeFinding({
|
|
190
|
-
tool: 'gca',
|
|
191
|
-
file: 'src/auth.ts',
|
|
192
|
-
line: 11,
|
|
193
|
-
body: 'Secret credential leak detected here',
|
|
194
|
-
}),
|
|
195
|
-
makeFinding({
|
|
196
|
-
tool: 'unknown',
|
|
197
|
-
file: 'src/auth.ts',
|
|
198
|
-
line: 12,
|
|
199
|
-
body: 'Credential secret leak in this block',
|
|
200
|
-
}),
|
|
246
|
+
makeFinding({ file: 'src/auth.ts', body: 'inline', rootCommentId: 700 }),
|
|
247
|
+
makeFinding({ file: '(review body)', body: 'synthesized' }),
|
|
201
248
|
];
|
|
202
249
|
const result = deduplicateFindings(findings);
|
|
203
|
-
expect(result).
|
|
204
|
-
expect(result[
|
|
205
|
-
expect(result[
|
|
206
|
-
|
|
250
|
+
expect(result[0].dedupKey).toBe('id:700');
|
|
251
|
+
expect(result[1].dedupKey.startsWith('body:')).toBe(true);
|
|
252
|
+
expect(result[1].dedupKey).toContain('synthesized');
|
|
253
|
+
});
|
|
254
|
+
it('preserves input order (first-seen wins on collision)', () => {
|
|
255
|
+
const findings = [
|
|
256
|
+
makeFinding({ tool: 'coderabbit', body: 'first', rootCommentId: 1 }),
|
|
257
|
+
makeFinding({ tool: 'gca', body: 'second', rootCommentId: 2 }),
|
|
258
|
+
makeFinding({ tool: 'coderabbit', body: 'third', rootCommentId: 3 }),
|
|
259
|
+
];
|
|
260
|
+
const result = deduplicateFindings(findings);
|
|
261
|
+
expect(result.map((r) => r.body)).toEqual(['first', 'second', 'third']);
|
|
262
|
+
});
|
|
263
|
+
it('attaches triageCategory on every output finding', () => {
|
|
264
|
+
const findings = [makeFinding({ rootCommentId: 1 })];
|
|
265
|
+
const result = deduplicateFindings(findings);
|
|
266
|
+
expect(result[0].triageCategory).toBeDefined();
|
|
207
267
|
});
|
|
208
268
|
});
|
|
209
269
|
//# sourceMappingURL=triage-dedup.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"triage-dedup.test.js","sourceRoot":"","sources":["../../src/parsers/triage-dedup.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAG9C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE5F,wDAAwD;AAExD,SAAS,WAAW,CAAC,YAA2C,EAAE;IAChE,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,mBAAmB;QACzB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,wDAAwD;AAExD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,EAAE,GAAG,eAAe,CAAC,6CAA6C,CAAC,CAAC;QAC1E,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,oCAAoC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,EAAE,GAAG,eAAe,CAAC,sBAAsB,CAAC,CAAC;QACnD,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,uDAAuD;AAEvD,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,iBAAiB,CAAC,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QACzC,kEAAkE;QAClE,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,
|
|
1
|
+
{"version":3,"file":"triage-dedup.test.js","sourceRoot":"","sources":["../../src/parsers/triage-dedup.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmnto/cli",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.8",
|
|
4
4
|
"description": "CLI for Totem — AI persistent memory and context layer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"smol-toml": "^1.6.1",
|
|
25
25
|
"yaml": "^2.4.0",
|
|
26
26
|
"zod": "^3.24.0",
|
|
27
|
-
"@mmnto/totem": "1.15.
|
|
27
|
+
"@mmnto/totem": "1.15.8"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@anthropic-ai/sdk": "^0.78.0",
|