@rigour-labs/core 6.12.2 → 6.12.3-rc.1
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.
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* - contextFindings: deep findings elsewhere in a changed file; returned so
|
|
9
9
|
* nothing the model found disappears, never blocking.
|
|
10
10
|
* - unlocated: no file at all; counted, never shown as a changed-line finding.
|
|
11
|
-
* - outside: any other finding on an unchanged line; counted
|
|
11
|
+
* - outside: any other finding on an unchanged line; counted, and kept in
|
|
12
|
+
* outsideFindings so a check whose findings are all here can say so.
|
|
12
13
|
*
|
|
13
14
|
* The CLI, the MCP tool and the GitHub integration all use this, so the same
|
|
14
15
|
* change gets the same verdict everywhere.
|
|
@@ -22,5 +23,6 @@ export interface ChangedLineSplit {
|
|
|
22
23
|
contextFindings: Failure[];
|
|
23
24
|
unlocated: number;
|
|
24
25
|
outside: number;
|
|
26
|
+
outsideFindings: Failure[];
|
|
25
27
|
}
|
|
26
28
|
export declare function splitByChangedLines(failures: Failure[], changedLines: Record<string, Set<number>>, spans?: Record<string, LineSpan[]>, removed?: Record<string, RemovedBlock[]>): ChangedLineSplit;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { anchorInChangedFunction } from './changed-function-spans.js';
|
|
2
2
|
export function splitByChangedLines(failures, changedLines, spans = {}, removed = {}) {
|
|
3
|
-
const split = { findings: [], fileFindings: [], contextFindings: [], unlocated: 0, outside: 0 };
|
|
3
|
+
const split = { findings: [], fileFindings: [], contextFindings: [], unlocated: 0, outside: 0, outsideFindings: [] };
|
|
4
4
|
for (const failure of failures) {
|
|
5
5
|
const files = failure.files ?? [];
|
|
6
6
|
if (files.length === 0) {
|
|
@@ -10,7 +10,7 @@ export function splitByChangedLines(failures, changedLines, spans = {}, removed
|
|
|
10
10
|
if (files.some(file => changedLines[file]))
|
|
11
11
|
split.fileFindings.push(failure);
|
|
12
12
|
else
|
|
13
|
-
split
|
|
13
|
+
leftOutside(split, failure);
|
|
14
14
|
}
|
|
15
15
|
else if (files.some(file => changedLines[file]?.has(failure.line) || removedInside(failure, removed[file]))) {
|
|
16
16
|
split.findings.push(failure);
|
|
@@ -19,11 +19,15 @@ export function splitByChangedLines(failures, changedLines, spans = {}, removed
|
|
|
19
19
|
placeDeepFinding(failure, files, changedLines, spans, split);
|
|
20
20
|
}
|
|
21
21
|
else {
|
|
22
|
-
split
|
|
22
|
+
leftOutside(split, failure);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return split;
|
|
26
26
|
}
|
|
27
|
+
function leftOutside(split, failure) {
|
|
28
|
+
split.outside++;
|
|
29
|
+
split.outsideFindings.push(failure);
|
|
30
|
+
}
|
|
27
31
|
function placeDeepFinding(failure, files, changedLines, spans, split) {
|
|
28
32
|
for (const file of files) {
|
|
29
33
|
const anchorLine = anchorInChangedFunction(failure.line, changedLines[file], spans[file]);
|
package/dist/review/review.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface ReviewResult {
|
|
|
40
40
|
preexisting: number;
|
|
41
41
|
/** The same, by check. A check whose findings were all the base's reads PASS in the report's summary. */
|
|
42
42
|
preexistingByCheck: Record<string, number>;
|
|
43
|
+
/** By check, findings only on lines the change did not touch. A check whose findings were all such reads PASS in the report's summary. */
|
|
44
|
+
outsideChangeByCheck: Record<string, number>;
|
|
43
45
|
/** A diff given with no base whose change HEAD already holds (committed work): nothing was compared, so nothing was dropped as the base's. */
|
|
44
46
|
baseUnknown?: boolean;
|
|
45
47
|
changedLines: Record<string, Set<number>>;
|
package/dist/review/review.js
CHANGED
|
@@ -39,7 +39,7 @@ export async function reviewChange(input) {
|
|
|
39
39
|
const changedLines = withoutGenerated(input.cwd, parseDiff(diff));
|
|
40
40
|
const targets = input.files?.length ? input.files : Object.keys(changedLines);
|
|
41
41
|
if (targets.length === 0) {
|
|
42
|
-
return { status: 'PASS', findings: [], fileFindings: [], contextFindings: [], advisory: [], muted: 0, dismissed: 0, dismissedByGate: {}, unlocated: 0, excludedOutsideChangedLines: 0, preexisting: 0, preexistingByCheck: {}, changedLines, report: null, gateErrors: [], controlFilesChanged: controlFiles(diff), hints: [], covered: [] };
|
|
42
|
+
return { status: 'PASS', findings: [], fileFindings: [], contextFindings: [], advisory: [], muted: 0, dismissed: 0, dismissedByGate: {}, unlocated: 0, excludedOutsideChangedLines: 0, preexisting: 0, preexistingByCheck: {}, outsideChangeByCheck: {}, changedLines, report: null, gateErrors: [], controlFilesChanged: controlFiles(diff), hints: [], covered: [] };
|
|
43
43
|
}
|
|
44
44
|
// The team's compiled checks run before the deep review, so it is told what they found and which lessons they covered.
|
|
45
45
|
const compiled = compiledChecksOn(input.cwd, changedLines, input.config);
|
|
@@ -73,6 +73,8 @@ export async function reviewChange(input) {
|
|
|
73
73
|
else if (input.typed)
|
|
74
74
|
reviewCheck('redundancy', 'redundancy', typed.failures);
|
|
75
75
|
const split = splitByChangedLines(report.failures, changedLines, deep ? changedFunctionSpans(input.cwd, changedLines) : {}, removedByFile(diff));
|
|
76
|
+
const outside = new Set(split.outsideFindings);
|
|
77
|
+
const outsideChangeByCheck = passChecksOnlyLeftOut(report, split.outsideFindings, report.failures.filter(f => !outside.has(f)));
|
|
76
78
|
const deepError = deepAnalysisError(report);
|
|
77
79
|
// The goal's findings are about the change as a whole (a file it should not touch, an item it never did), not a line, so they skip the changed-line split.
|
|
78
80
|
const goal = input.goalDescription !== undefined ? parseGoal(input.goalDescription, fileNames(input.cwd, diff)) : undefined;
|
|
@@ -97,6 +99,7 @@ export async function reviewChange(input) {
|
|
|
97
99
|
excludedOutsideChangedLines: split.outside,
|
|
98
100
|
preexisting,
|
|
99
101
|
preexistingByCheck,
|
|
102
|
+
outsideChangeByCheck,
|
|
100
103
|
...(baseUnknown ? { baseUnknown } : {}),
|
|
101
104
|
changedLines,
|
|
102
105
|
report,
|
|
@@ -110,15 +113,16 @@ export async function reviewChange(input) {
|
|
|
110
113
|
};
|
|
111
114
|
}
|
|
112
115
|
/**
|
|
113
|
-
* A check
|
|
114
|
-
* count, by check, says what it left out. A check with
|
|
116
|
+
* A check whose findings were all left out of this change's verdict (what the base already had, or lines the change
|
|
117
|
+
* did not touch) passes for it: its summary reads PASS, and the count, by check, says what it left out. A check with
|
|
118
|
+
* any finding still in play keeps FAIL.
|
|
115
119
|
*/
|
|
116
|
-
function
|
|
120
|
+
function passChecksOnlyLeftOut(report, leftOut, kept) {
|
|
117
121
|
const byCheck = {};
|
|
118
122
|
const check = (f) => gateOf(f) ?? f.id;
|
|
119
|
-
for (const f of
|
|
123
|
+
for (const f of leftOut)
|
|
120
124
|
byCheck[check(f)] = (byCheck[check(f)] ?? 0) + 1;
|
|
121
|
-
const remaining = new Set(
|
|
125
|
+
const remaining = new Set(kept.map(check));
|
|
122
126
|
for (const id of Object.keys(byCheck))
|
|
123
127
|
if (report.summary[id] === 'FAIL' && !remaining.has(id))
|
|
124
128
|
report.summary[id] = 'PASS';
|
|
@@ -143,7 +147,7 @@ async function dropPreexisting(input, report, targets) {
|
|
|
143
147
|
const { preexisting } = splitIntroduced(rules, await baseFindings(input.cwd, input.config, commit, targets));
|
|
144
148
|
const old = new Set(preexisting);
|
|
145
149
|
report.failures = report.failures.filter(f => !old.has(f));
|
|
146
|
-
return { preexisting: old.size, byCheck:
|
|
150
|
+
return { preexisting: old.size, byCheck: passChecksOnlyLeftOut(report, preexisting, report.failures) };
|
|
147
151
|
}
|
|
148
152
|
catch {
|
|
149
153
|
return { preexisting: 0 }; // the comparison is a courtesy; it never fails a review
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "6.12.
|
|
3
|
+
"version": "6.12.3-rc.1",
|
|
4
4
|
"description": "Rigour's review engine: deterministic gates on changed lines, rules and lessons learned from your team's fixes, and per-check precision from what you fix versus dismiss, across TypeScript, JavaScript, Python, Go, Ruby and C#.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.13"
|
|
@@ -75,11 +75,11 @@
|
|
|
75
75
|
"@anthropic-ai/sdk": "^0.132.1",
|
|
76
76
|
"pg": "^8.16.3",
|
|
77
77
|
"openai": "^5.23.2",
|
|
78
|
-
"@rigour-labs/brain-darwin-arm64": "6.12.
|
|
79
|
-
"@rigour-labs/brain-
|
|
80
|
-
"@rigour-labs/brain-
|
|
81
|
-
"@rigour-labs/brain-win-x64": "6.12.
|
|
82
|
-
"@rigour-labs/brain-linux-
|
|
78
|
+
"@rigour-labs/brain-darwin-arm64": "6.12.3-rc.1",
|
|
79
|
+
"@rigour-labs/brain-darwin-x64": "6.12.3-rc.1",
|
|
80
|
+
"@rigour-labs/brain-linux-x64": "6.12.3-rc.1",
|
|
81
|
+
"@rigour-labs/brain-win-x64": "6.12.3-rc.1",
|
|
82
|
+
"@rigour-labs/brain-linux-arm64": "6.12.3-rc.1"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/fs-extra": "^11.0.4",
|