@rigour-labs/core 6.12.1-rc.1 → 6.12.2-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.
|
@@ -77,6 +77,8 @@ export interface ReviewLesson {
|
|
|
77
77
|
* evidence, never a promotion. A record from before evidence kinds keeps the state it had.
|
|
78
78
|
*/
|
|
79
79
|
export declare function lessonState(lesson: ReviewLesson): Pick<ReviewLesson, 'state' | 'promotedBy'>;
|
|
80
|
+
/** Every point on the lesson came from a review bot: it is recorded, but never verified or served until a person decides. */
|
|
81
|
+
export declare function raisedOnlyByBots(lesson: ReviewLesson): boolean;
|
|
80
82
|
/**
|
|
81
83
|
* The point of a review comment: its bold title, else its first sentence and, when that only says what is
|
|
82
84
|
* wrong, the first later sentence that says what to do. Without tool output or markup.
|
|
@@ -62,6 +62,9 @@ export function lessonState(lesson) {
|
|
|
62
62
|
// real history, it was most often unrelated work. It is shown in Studio for a person to promote.
|
|
63
63
|
if (kinds.has('counter'))
|
|
64
64
|
return { state: 'candidate' };
|
|
65
|
+
// A lesson is never verified without a person: review bots agreeing with each other are not a team's standard.
|
|
66
|
+
if (raisedOnlyByBots(lesson))
|
|
67
|
+
return { state: 'candidate' };
|
|
65
68
|
const points = lesson.evidence.filter(e => (e.kind ?? 'point') === 'point');
|
|
66
69
|
const prs = new Set(points.map(e => e.pr)).size;
|
|
67
70
|
const authors = new Set(points.map(e => e.prAuthor).filter(Boolean)).size;
|
|
@@ -71,6 +74,11 @@ export function lessonState(lesson) {
|
|
|
71
74
|
const independent = reviewers >= 2 || wordings >= 2;
|
|
72
75
|
return prs >= RECUR_PRS && authors >= RECUR_AUTHORS && independent ? { state: 'verified', promotedBy: 'recurrence' } : { state: 'candidate' };
|
|
73
76
|
}
|
|
77
|
+
/** Every point on the lesson came from a review bot: it is recorded, but never verified or served until a person decides. */
|
|
78
|
+
export function raisedOnlyByBots(lesson) {
|
|
79
|
+
const points = lesson.evidence.filter(e => (e.kind ?? 'point') === 'point');
|
|
80
|
+
return points.length > 0 && points.every(e => e.source === 'bot');
|
|
81
|
+
}
|
|
74
82
|
/** A sentence that tells the author what to do, not only what is wrong. */
|
|
75
83
|
const INSTRUCTION = /^(?:please\s+)?(?:use|pick|avoid|don'?t|do not|never|always|make|keep|move|read|filter|check|change|drop|add|remove|pass|split|prefer|replace|rename|derive|select|return|validate|extract|bound|lock)\b|\b(?:should|must|instead)\b/i;
|
|
76
84
|
/**
|
|
@@ -235,7 +243,7 @@ export function matchLessons(lessons, change, options = {}) {
|
|
|
235
243
|
// A lesson whose only evidence is the pull request under review is already in front of the judge as the reviewer's own points.
|
|
236
244
|
if (options.excludePr !== undefined)
|
|
237
245
|
lessons = lessons.filter(l => !l.evidence.length || l.evidence.some(e => e.pr !== options.excludePr));
|
|
238
|
-
const inPlay = (l) => l.state === 'verified' || (!!options.includeCandidates && l.state === 'candidate');
|
|
246
|
+
const inPlay = (l) => l.state === 'verified' || (!!options.includeCandidates && l.state === 'candidate' && !raisedOnlyByBots(l));
|
|
239
247
|
// A person made these the repository's standards: every change gets them, whatever its files or words; most-raised first.
|
|
240
248
|
const repo = lessons
|
|
241
249
|
.filter(l => l.scope === 'repo' && inPlay(l))
|
|
@@ -329,20 +337,24 @@ export function pendingDecision(lesson) {
|
|
|
329
337
|
}
|
|
330
338
|
/** Why a lesson an outcome alone had promoted is a candidate again. */
|
|
331
339
|
const RECLASSIFIED = 'promoted by the exact-line rule, which no longer promotes on its own';
|
|
340
|
+
/** Why a lesson recurrence had promoted on review bots' points alone is a candidate again. */
|
|
341
|
+
const BOTS_ONLY = 'only review bots raised it (no person)';
|
|
332
342
|
/**
|
|
333
|
-
* A lesson stored as verified by
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* already has the record is left as it is. Recurrence
|
|
343
|
+
* A lesson stored as verified by a rule that no longer promotes on its own, as every reader sees it now: an outcome
|
|
344
|
+
* (a later fix on its lines, or a revert), or recurrence on review bots' points alone. Its state is worked out again
|
|
345
|
+
* from its evidence, and, when that leaves it a candidate, one `reclassified` record says why. Never deleted, nothing
|
|
346
|
+
* else changed; the next write keeps it, and a lesson that already has the record is left as it is. Recurrence with a
|
|
347
|
+
* person's point, a correction or a person's decision keeps a lesson verified.
|
|
337
348
|
*/
|
|
338
349
|
function reclassified(lesson) {
|
|
339
|
-
|
|
350
|
+
const byBots = lesson.promotedBy === 'recurrence' && raisedOnlyByBots(lesson);
|
|
351
|
+
if (lesson.state !== 'verified' || !(lesson.promotedBy === 'outcome' || byBots) || lesson.evidence.some(e => e.kind === 'reclassified'))
|
|
340
352
|
return lesson;
|
|
341
353
|
const next = lessonState(lesson);
|
|
342
354
|
if (next.state === 'verified')
|
|
343
355
|
return { ...lesson, ...next };
|
|
344
356
|
const at = new Date().toISOString();
|
|
345
|
-
return { ...lesson, state: 'candidate', promotedBy: undefined, evidence: [...lesson.evidence, { kind: 'reclassified', pr: lesson.evidence[0]?.pr ?? 0, comment: `reclassified-${lesson.id}`, author: '', detail: RECLASSIFIED, at }] };
|
|
357
|
+
return { ...lesson, state: 'candidate', promotedBy: undefined, evidence: [...lesson.evidence, { kind: 'reclassified', pr: lesson.evidence[0]?.pr ?? 0, comment: `reclassified-${lesson.id}`, author: '', detail: byBots ? BOTS_ONLY : RECLASSIFIED, at }] };
|
|
346
358
|
}
|
|
347
359
|
export function writeLessons(cwd, lessons) {
|
|
348
360
|
const file = lessonsPath(cwd);
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { parseDiff } from '../utils/diff.js';
|
|
8
|
-
import { matchLessons, readLessons } from './lessons.js';
|
|
8
|
+
import { matchLessons, raisedOnlyByBots, readLessons } from './lessons.js';
|
|
9
9
|
/** Lessons a person or repeated evidence verified reach the reviewer unless a team turns them off. */
|
|
10
10
|
export const DEFAULT_LESSON_MODE = 'verified';
|
|
11
11
|
/** The team's review lessons in play for this mode: none when off, verified ones by default. */
|
|
12
12
|
export function activeLessons(cwd, mode = DEFAULT_LESSON_MODE) {
|
|
13
13
|
if (mode === 'off')
|
|
14
14
|
return [];
|
|
15
|
-
return readLessons(cwd).filter(l => mode === 'all'
|
|
15
|
+
return readLessons(cwd).filter(l => mode === 'all' ? !(l.state === 'candidate' && raisedOnlyByBots(l)) : l.state === 'verified');
|
|
16
16
|
}
|
|
17
17
|
/** `standards`, `limit`, `perFile`: how many team standards and file lessons may come, and how many per file (a judge reading a whole pull request takes more than an agent's one question). */
|
|
18
18
|
export function lessonsForDiff(cwd, diff, mode = DEFAULT_LESSON_MODE, standards, limit, perFile, excludePr) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "6.12.
|
|
3
|
+
"version": "6.12.2-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-
|
|
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.2-rc.1",
|
|
79
|
+
"@rigour-labs/brain-linux-arm64": "6.12.2-rc.1",
|
|
80
|
+
"@rigour-labs/brain-darwin-x64": "6.12.2-rc.1",
|
|
81
|
+
"@rigour-labs/brain-win-x64": "6.12.2-rc.1",
|
|
82
|
+
"@rigour-labs/brain-linux-x64": "6.12.2-rc.1"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/fs-extra": "^11.0.4",
|