@rigour-labs/core 6.11.0-rc.1 → 6.11.0-rc.2
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/review/reviewer/settings.d.ts +2 -0
- package/dist/review/reviewer/settings.js +2 -1
- package/dist/review/reviewer/store.d.ts +2 -0
- package/dist/review/reviewer/tiering.d.ts +38 -0
- package/dist/review/reviewer/tiering.js +43 -0
- package/dist/review/reviewer/triage.d.ts +2 -0
- package/dist/review/reviewer/triage.js +4 -0
- package/dist/review/reviewer/usage.js +1 -0
- package/dist/review/reviewer.d.ts +3 -0
- package/dist/review/reviewer.js +19 -3
- package/dist/switches.d.ts +9 -0
- package/dist/templates/universal-config.js +1 -0
- package/dist/types/index.d.ts +29 -0
- package/dist/types/index.js +5 -0
- package/package.json +6 -6
|
@@ -35,6 +35,8 @@ export interface ResolvedReviewer {
|
|
|
35
35
|
judges: 2 | 3;
|
|
36
36
|
escalate: 'always' | 'risk';
|
|
37
37
|
cross_models: Record<string, string>;
|
|
38
|
+
/** The cheap model per reviewer name for cheap-model-first tiering; empty when it is off (team only). */
|
|
39
|
+
tiers: Record<string, string>;
|
|
38
40
|
/** Reasoning effort per reviewer name (codex, api). */
|
|
39
41
|
reasoning: Record<string, 'low' | 'medium' | 'high'>;
|
|
40
42
|
/** The API judge, when the team configured one (review.reviewer.api). */
|
|
@@ -13,7 +13,7 @@ const RANK = { single: 0, cross: 1, full: 2 };
|
|
|
13
13
|
/** How near a layer is to this run: the nearer wins. */
|
|
14
14
|
const NEAR = { flag: 0, env: 1, user: 2, team: 3 };
|
|
15
15
|
export function resolveReviewer(config, choice = {}, user = loadSettings().reviewer, env = process.env) {
|
|
16
|
-
const team = config.review?.reviewer ?? { enabled: false, on_push: 'background', reviewers: ['claude'], mode: 'single', models: {}, timeout_ms: 15 * 60_000, panel: 'off', mode_required: false, panel_max_items: 20, dismissals: false, orchestrator: 'off', judges: 2, escalate: 'always', cross_models: {}, judge_env: {}, reasoning: {} };
|
|
16
|
+
const team = config.review?.reviewer ?? { enabled: false, on_push: 'background', reviewers: ['claude'], mode: 'single', models: {}, timeout_ms: 15 * 60_000, panel: 'off', mode_required: false, panel_max_items: 20, dismissals: false, orchestrator: 'off', judges: 2, escalate: 'always', cross_models: {}, tiers: { cheap: {} }, judge_env: {}, reasoning: {} };
|
|
17
17
|
const refused = [];
|
|
18
18
|
const envMode = parseMode(env.RIGOUR_REVIEWER_MODE);
|
|
19
19
|
const envPanel = parseSwitch(env.RIGOUR_REVIEWER_PANEL);
|
|
@@ -78,6 +78,7 @@ export function resolveReviewer(config, choice = {}, user = loadSettings().revie
|
|
|
78
78
|
judges: floor ? Math.max(team.judges, user?.judges ?? team.judges) : user?.judges ?? team.judges,
|
|
79
79
|
escalate: requiredEscalation(team, user, refused),
|
|
80
80
|
cross_models: team.cross_models,
|
|
81
|
+
tiers: team.tiers?.cheap ?? {},
|
|
81
82
|
judge_env: team.judge_env ?? {},
|
|
82
83
|
reasoning: team.reasoning ?? {},
|
|
83
84
|
...(team.api ? { api: team.api } : {}),
|
|
@@ -43,6 +43,8 @@ export interface ReviewCost {
|
|
|
43
43
|
runs: number;
|
|
44
44
|
/** A verdict reused instead of run: for the same content on another commit (`content`). Runs and actual cost are 0. */
|
|
45
45
|
cache?: 'content';
|
|
46
|
+
/** The tier the review ran at, when cheap-model-first tiering is on (reviewer/tiering.ts). */
|
|
47
|
+
tier?: 'cheap' | 'strong';
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
48
50
|
* A verdict, findable by the content it reviewed rather than its commit: a rebase, an amend, a cherry-pick or the same
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cheap-model-first tiering (off by default; review.reviewer.tiers.cheap names a cheaper model per judge). Which model
|
|
3
|
+
* reviews a change is decided BEFORE any run, from facts about the change only: never by a model, and never from a
|
|
4
|
+
* model's findings. A change with something a cheaper model may miss gets the team's model:
|
|
5
|
+
*
|
|
6
|
+
* a required floor, human reviews to check, open items carried from the last verdict, a migration, a security
|
|
7
|
+
* finding from the checks, a declared goal, or a risky changed function (the router's score)
|
|
8
|
+
*
|
|
9
|
+
* Anything else gets the cheap model. After the run, the only escalation is an answer that is not a valid verdict: the
|
|
10
|
+
* one retry the reviewer already makes uses the team's model. What blocks is unchanged: the same evidence contract.
|
|
11
|
+
*
|
|
12
|
+
* The rule a tier must keep: on average, a review costs no more than one judge would have. Over the last
|
|
13
|
+
* TIER_WINDOW reviews tiering ran on, actual cost against what one judge would have been given (the frozen baseline's
|
|
14
|
+
* dollars per character, else characters); above it, tiering turns itself off and the review record says so.
|
|
15
|
+
*/
|
|
16
|
+
import type { CostBaseline, ReviewCost } from './store.js';
|
|
17
|
+
export interface TierDecision {
|
|
18
|
+
tier: 'cheap' | 'strong';
|
|
19
|
+
/** The cheap model, when the tier is cheap. */
|
|
20
|
+
model?: string;
|
|
21
|
+
why: string;
|
|
22
|
+
/** Why tiering turned itself off, when it did. */
|
|
23
|
+
disabled?: string;
|
|
24
|
+
/** Why the cheap model's run was retried on the team's model: its answer was not a valid verdict. */
|
|
25
|
+
escalated?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface TierFacts {
|
|
28
|
+
required: boolean;
|
|
29
|
+
humanReviews: number;
|
|
30
|
+
carried: number;
|
|
31
|
+
migration: boolean;
|
|
32
|
+
securityChecks: number;
|
|
33
|
+
goal: boolean;
|
|
34
|
+
/** Risky changed functions (the router's score); undefined when it could not score the change. */
|
|
35
|
+
risky: number | undefined;
|
|
36
|
+
}
|
|
37
|
+
/** The tier for one judge's review; undefined when no cheap model is set for it (tiering is off). */
|
|
38
|
+
export declare function chooseTier(cheap: Record<string, string>, judge: string, facts: TierFacts, costs: ReviewCost[], baseline: CostBaseline | undefined): TierDecision | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Recent tiered reviews the self-disable rule reads. */
|
|
2
|
+
const TIER_WINDOW = 20;
|
|
3
|
+
/** Tiered reviews needed before the rule can turn tiering off. */
|
|
4
|
+
const TIER_MIN = 5;
|
|
5
|
+
/** The tier for one judge's review; undefined when no cheap model is set for it (tiering is off). */
|
|
6
|
+
export function chooseTier(cheap, judge, facts, costs, baseline) {
|
|
7
|
+
const model = cheap[judge];
|
|
8
|
+
if (!model)
|
|
9
|
+
return undefined;
|
|
10
|
+
const disabled = overBudget(costs, baseline);
|
|
11
|
+
if (disabled)
|
|
12
|
+
return { tier: 'strong', why: 'tiering turned itself off', disabled };
|
|
13
|
+
const strong = (why) => ({ tier: 'strong', why });
|
|
14
|
+
if (facts.required)
|
|
15
|
+
return strong('a required floor');
|
|
16
|
+
if (facts.humanReviews > 0)
|
|
17
|
+
return strong(`${facts.humanReviews} human review(s) to check`);
|
|
18
|
+
if (facts.carried > 0)
|
|
19
|
+
return strong(`${facts.carried} open item(s) carried from the last verdict`);
|
|
20
|
+
if (facts.migration)
|
|
21
|
+
return strong('the change adds or edits a migration');
|
|
22
|
+
if (facts.securityChecks > 0)
|
|
23
|
+
return strong(`${facts.securityChecks} security finding(s) from the checks`);
|
|
24
|
+
if (facts.goal)
|
|
25
|
+
return strong('the description declares a goal to check');
|
|
26
|
+
if (facts.risky === undefined)
|
|
27
|
+
return strong('the risk router could not score the change');
|
|
28
|
+
if (facts.risky > 0)
|
|
29
|
+
return strong(`${facts.risky} risky changed function(s)`);
|
|
30
|
+
return { tier: 'cheap', model, why: 'no risk signal: the cheap model' };
|
|
31
|
+
}
|
|
32
|
+
/** Why tiering must turn itself off: its recent reviews cost more, on average, than one judge would have. */
|
|
33
|
+
function overBudget(costs, baseline) {
|
|
34
|
+
const tiered = costs.filter(c => c.tier).slice(-TIER_WINDOW);
|
|
35
|
+
if (tiered.length < TIER_MIN)
|
|
36
|
+
return undefined;
|
|
37
|
+
const rate = baseline?.usdPerChar ?? null;
|
|
38
|
+
const single = tiered.reduce((sum, c) => sum + c.projectedSingleChars * (rate ?? 1), 0);
|
|
39
|
+
const actual = tiered.reduce((sum, c) => sum + (rate === null ? c.actualChars : c.actualUsd > 0 ? c.actualUsd : c.actualChars * rate), 0);
|
|
40
|
+
if (single <= 0 || actual <= single)
|
|
41
|
+
return undefined;
|
|
42
|
+
return `the last ${tiered.length} tiered reviews cost ${(actual / single).toFixed(2)}x what one judge would have (${rate === null ? 'characters' : 'dollars'})`;
|
|
43
|
+
}
|
|
@@ -31,6 +31,8 @@ export interface TriageContext {
|
|
|
31
31
|
}
|
|
32
32
|
/** Per specialist, the hunks it is for (by index); a specialist absent from the map is not needed. Prior points take the whole change. */
|
|
33
33
|
export declare function triage(hunks: Hunk[], context: TriageContext): Map<string, number[]>;
|
|
34
|
+
/** Whether a file is a migration or a schema (a change a cheaper model may miss the cost of). */
|
|
35
|
+
export declare function isMigration(file: string): boolean;
|
|
34
36
|
/** Whether no model reviews this file (SKIP). */
|
|
35
37
|
export declare function skipped(file: string): boolean;
|
|
36
38
|
export interface Pass {
|
|
@@ -79,6 +79,10 @@ export function triage(hunks, context) {
|
|
|
79
79
|
picked.set('prior-points', hunks.map((_, i) => i).filter(i => !skipped(hunks[i].file)));
|
|
80
80
|
return picked;
|
|
81
81
|
}
|
|
82
|
+
/** Whether a file is a migration or a schema (a change a cheaper model may miss the cost of). */
|
|
83
|
+
export function isMigration(file) {
|
|
84
|
+
return MIGRATION.test(file);
|
|
85
|
+
}
|
|
82
86
|
/** Whether no model reviews this file (SKIP). */
|
|
83
87
|
export function skipped(file) {
|
|
84
88
|
return SKIP.some(pattern => pattern.test(file));
|
|
@@ -18,6 +18,7 @@ export function reviewerUsage(result, trigger) {
|
|
|
18
18
|
judges: result.reviewers.length,
|
|
19
19
|
cached: result.cached,
|
|
20
20
|
...(result.cache ? { cache: result.cache } : {}),
|
|
21
|
+
...(mode?.tier ? { tier: mode.tier.tier, tier_disabled: !!mode.tier.disabled, tier_escalated: !!mode.tier.escalated } : {}),
|
|
21
22
|
confirmed: result.items.length,
|
|
22
23
|
disputed: result.disputed.length,
|
|
23
24
|
dropped: result.dropped.length,
|
|
@@ -2,6 +2,7 @@ import type { Config } from '../types/index.js';
|
|
|
2
2
|
import { type ReviewerName, type Tokens } from './reviewer/adapters.js';
|
|
3
3
|
import { type Exec, type Progress } from './reviewer/exec.js';
|
|
4
4
|
import { type PanelItem } from './reviewer/panel.js';
|
|
5
|
+
import { type TierDecision } from './reviewer/tiering.js';
|
|
5
6
|
import { type RunChoice, type Source } from './reviewer/settings.js';
|
|
6
7
|
import { type ReviewRecord } from './reviewer/record.js';
|
|
7
8
|
import { type Accounting, type OpenItem, type PriorPoint } from './reviewer/verdict.js';
|
|
@@ -136,6 +137,8 @@ export interface ModeRecord {
|
|
|
136
137
|
refused?: string[];
|
|
137
138
|
/** With escalate: risk, why this review got one judge or all of them. */
|
|
138
139
|
escalation?: string;
|
|
140
|
+
/** With cheap-model-first tiering on: the tier, why, and whether it turned itself off or escalated (reviewer/tiering.ts). */
|
|
141
|
+
tier?: TierDecision;
|
|
139
142
|
}
|
|
140
143
|
/** Findings and no verdict stop a push; a skipped review does not, and is reported as owed. */
|
|
141
144
|
export declare function reviewerBlocks(result: ReviewerResult): boolean;
|
package/dist/review/reviewer.js
CHANGED
|
@@ -29,7 +29,8 @@ import { mergeImpact } from './reviewer/merge-impact.js';
|
|
|
29
29
|
import { applyPanel, parseAnswers, runPanel } from './reviewer/panel.js';
|
|
30
30
|
import { crossExamPrompt, deltaBlock, goalStep, mergeBlock, PROMPT_VERSION, renderPrompt } from './reviewer/prompt.js';
|
|
31
31
|
import { BASELINE_MIN_SINGLES, focusBlock, formatLedger, ledger, passLimit, runPasses, SPECIALISTS, SPECIALISTS_KEY, splitNeeds } from './reviewer/orchestrator.js';
|
|
32
|
-
import { MAX_PARTS, parseHunks, planPasses, reviewable, skipped, triage } from './reviewer/triage.js';
|
|
32
|
+
import { isMigration, MAX_PARTS, parseHunks, planPasses, reviewable, skipped, triage } from './reviewer/triage.js';
|
|
33
|
+
import { chooseTier } from './reviewer/tiering.js';
|
|
33
34
|
import { modelGoalItems, parseGoal } from '../goal/goal.js';
|
|
34
35
|
import { resolveSwitch } from '../switches.js';
|
|
35
36
|
import { resolveReviewer } from './reviewer/settings.js';
|
|
@@ -224,7 +225,17 @@ async function review(cwd, base, config, exec, progress, options) {
|
|
|
224
225
|
const previousOpen = scope === 'delta' ? store.readJson(store.openPath(previous.verdict)) ?? [] : undefined;
|
|
225
226
|
const verify = checkoutVerifier(cwd);
|
|
226
227
|
const prior = { approvals: reviews.approvals, inCheckout: checkoutSearch(cwd), changed: changedLinesOf(fullDiff), labels: reviews.labels };
|
|
227
|
-
|
|
228
|
+
// Cheap-model-first (reviewer/tiering.ts): decided before any run, from facts about the change only, for one judge.
|
|
229
|
+
let tier = reviewers.length === 1 && (modeRecord.ran === 'single' || modeRecord.ran === 'orchestrator')
|
|
230
|
+
? chooseTier(settings.tiers, reviewers[0], {
|
|
231
|
+
required: settings.required.mode || settings.required.panel || orchestrator.required, humanReviews: reviews.count, carried: previousOpen?.length ?? 0,
|
|
232
|
+
migration: changedFiles.some(isMigration), securityChecks: (options.checks ?? []).filter(c => /\bsecurity\b/i.test(c)).length, goal: goalItems.length > 0, risky: context.risky,
|
|
233
|
+
}, store.costs(), store.baseline())
|
|
234
|
+
: undefined;
|
|
235
|
+
if (tier)
|
|
236
|
+
modeRecord = { ...modeRecord, tier };
|
|
237
|
+
const cheapModel = () => (tier?.tier === 'cheap' && !tier.escalated ? tier.model : undefined);
|
|
238
|
+
const modelFor = (name) => (name === reviewers[0] ? cheapModel() : undefined) ?? settings.models[name] ?? (name === 'claude' ? settings.model : undefined);
|
|
228
239
|
// The record of the review, written beside the verdict once and rebuilt from the same verdict on a cached read.
|
|
229
240
|
// What a judge reads besides the repository and Rigour's inputs, on this machine: on the record, so "the same judge" is a claim it can check.
|
|
230
241
|
const outsideOf = (reviewer) => {
|
|
@@ -323,7 +334,7 @@ async function review(cwd, base, config, exec, progress, options) {
|
|
|
323
334
|
store.recordCost({
|
|
324
335
|
at: new Date().toISOString(), mode: orchestrated ? 'orchestrator' : 'single', lines: size.lines, projectedSingleChars: projectedSingle,
|
|
325
336
|
...(orchestrated ? { projectedChars: passes.reduce((sum, pass) => sum + shared + pass.diff.length, 0) } : {}),
|
|
326
|
-
actualChars: tally.chars, actualUsd: spentUsd(), runs: tally.runs,
|
|
337
|
+
actualChars: tally.chars, actualUsd: spentUsd(), runs: tally.runs, ...(tier ? { tier: tier.tier } : {}),
|
|
327
338
|
});
|
|
328
339
|
};
|
|
329
340
|
// One judge run, by CLI or by API: the same prompt, the same cost accounting, the same trace.
|
|
@@ -438,6 +449,11 @@ async function review(cwd, base, config, exec, progress, options) {
|
|
|
438
449
|
// No verdict, whether a malformed answer or a run that died, is a slip, not a decision: asked once more, inside the caps.
|
|
439
450
|
if (!once && (!first.verdict || 'error' in first.verdict) && !overBudget(store.spend(), settings, 1)) {
|
|
440
451
|
progress(`Rigour reviewer: ${name} gave no ${first.verdict ? 'valid verdict' : 'answer'}; asking once more`);
|
|
452
|
+
// The cheap model's slip is the one escalation: the retry runs on the team's model.
|
|
453
|
+
if (cheapModel()) {
|
|
454
|
+
tier = { ...tier, escalated: 'no valid verdict from the cheap model: retried on the team\'s model' };
|
|
455
|
+
modeRecord = { ...modeRecord, tier };
|
|
456
|
+
}
|
|
441
457
|
first = await ask();
|
|
442
458
|
}
|
|
443
459
|
return first.verdict ?? { error: `${name}: no answer (exit ${first.run.exitCode}): ${first.run.stderr.trim().slice(-200)}` };
|
package/dist/switches.d.ts
CHANGED
|
@@ -301,6 +301,9 @@ export declare const SWITCHES: {
|
|
|
301
301
|
judges: 2 | 3;
|
|
302
302
|
escalate: "always" | "risk";
|
|
303
303
|
cross_models: Record<string, string>;
|
|
304
|
+
tiers: {
|
|
305
|
+
cheap: Record<string, string>;
|
|
306
|
+
};
|
|
304
307
|
reasoning: Record<string, "high" | "medium" | "low">;
|
|
305
308
|
judge_env: Record<string, {
|
|
306
309
|
unset: string[];
|
|
@@ -614,6 +617,9 @@ export declare const SWITCHES: {
|
|
|
614
617
|
judges: 2 | 3;
|
|
615
618
|
escalate: "always" | "risk";
|
|
616
619
|
cross_models: Record<string, string>;
|
|
620
|
+
tiers: {
|
|
621
|
+
cheap: Record<string, string>;
|
|
622
|
+
};
|
|
617
623
|
reasoning: Record<string, "high" | "medium" | "low">;
|
|
618
624
|
judge_env: Record<string, {
|
|
619
625
|
unset: string[];
|
|
@@ -927,6 +933,9 @@ export declare const SWITCHES: {
|
|
|
927
933
|
judges: 2 | 3;
|
|
928
934
|
escalate: "always" | "risk";
|
|
929
935
|
cross_models: Record<string, string>;
|
|
936
|
+
tiers: {
|
|
937
|
+
cheap: Record<string, string>;
|
|
938
|
+
};
|
|
930
939
|
reasoning: Record<string, "high" | "medium" | "low">;
|
|
931
940
|
judge_env: Record<string, {
|
|
932
941
|
unset: string[];
|
package/dist/types/index.d.ts
CHANGED
|
@@ -2551,6 +2551,17 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2551
2551
|
escalate: z.ZodDefault<z.ZodOptional<z.ZodEnum<["always", "risk"]>>>;
|
|
2552
2552
|
/** A model per reviewer name for cross-examination (a narrow verification task), e.g. { claude: "haiku" }. */
|
|
2553
2553
|
cross_models: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
|
|
2554
|
+
/**
|
|
2555
|
+
* Cheap-model-first (reviewer/tiering.ts), off unless set: a cheaper model per reviewer name for a change with no
|
|
2556
|
+
* risk signal. Experimental: not to be recommended until a backtest shows what the cheap model misses.
|
|
2557
|
+
*/
|
|
2558
|
+
tiers: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
2559
|
+
cheap: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>>;
|
|
2560
|
+
}, "strip", z.ZodTypeAny, {
|
|
2561
|
+
cheap: Record<string, string>;
|
|
2562
|
+
}, {
|
|
2563
|
+
cheap?: Record<string, string> | undefined;
|
|
2564
|
+
}>>>;
|
|
2554
2565
|
/** Reasoning effort per reviewer name where the CLI or API takes one (codex, api): low, medium or high. */
|
|
2555
2566
|
reasoning: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<["low", "medium", "high"]>>>>;
|
|
2556
2567
|
/**
|
|
@@ -2603,6 +2614,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2603
2614
|
judges: 2 | 3;
|
|
2604
2615
|
escalate: "always" | "risk";
|
|
2605
2616
|
cross_models: Record<string, string>;
|
|
2617
|
+
tiers: {
|
|
2618
|
+
cheap: Record<string, string>;
|
|
2619
|
+
};
|
|
2606
2620
|
reasoning: Record<string, "high" | "medium" | "low">;
|
|
2607
2621
|
judge_env: Record<string, {
|
|
2608
2622
|
unset: string[];
|
|
@@ -2635,6 +2649,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2635
2649
|
judges?: 2 | 3 | undefined;
|
|
2636
2650
|
escalate?: "always" | "risk" | undefined;
|
|
2637
2651
|
cross_models?: Record<string, string> | undefined;
|
|
2652
|
+
tiers?: {
|
|
2653
|
+
cheap?: Record<string, string> | undefined;
|
|
2654
|
+
} | undefined;
|
|
2638
2655
|
reasoning?: Record<string, "high" | "medium" | "low"> | undefined;
|
|
2639
2656
|
api?: {
|
|
2640
2657
|
model: string;
|
|
@@ -2666,6 +2683,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2666
2683
|
judges: 2 | 3;
|
|
2667
2684
|
escalate: "always" | "risk";
|
|
2668
2685
|
cross_models: Record<string, string>;
|
|
2686
|
+
tiers: {
|
|
2687
|
+
cheap: Record<string, string>;
|
|
2688
|
+
};
|
|
2669
2689
|
reasoning: Record<string, "high" | "medium" | "low">;
|
|
2670
2690
|
judge_env: Record<string, {
|
|
2671
2691
|
unset: string[];
|
|
@@ -2705,6 +2725,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
2705
2725
|
judges?: 2 | 3 | undefined;
|
|
2706
2726
|
escalate?: "always" | "risk" | undefined;
|
|
2707
2727
|
cross_models?: Record<string, string> | undefined;
|
|
2728
|
+
tiers?: {
|
|
2729
|
+
cheap?: Record<string, string> | undefined;
|
|
2730
|
+
} | undefined;
|
|
2708
2731
|
reasoning?: Record<string, "high" | "medium" | "low"> | undefined;
|
|
2709
2732
|
api?: {
|
|
2710
2733
|
model: string;
|
|
@@ -3007,6 +3030,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
3007
3030
|
judges: 2 | 3;
|
|
3008
3031
|
escalate: "always" | "risk";
|
|
3009
3032
|
cross_models: Record<string, string>;
|
|
3033
|
+
tiers: {
|
|
3034
|
+
cheap: Record<string, string>;
|
|
3035
|
+
};
|
|
3010
3036
|
reasoning: Record<string, "high" | "medium" | "low">;
|
|
3011
3037
|
judge_env: Record<string, {
|
|
3012
3038
|
unset: string[];
|
|
@@ -3320,6 +3346,9 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
3320
3346
|
judges?: 2 | 3 | undefined;
|
|
3321
3347
|
escalate?: "always" | "risk" | undefined;
|
|
3322
3348
|
cross_models?: Record<string, string> | undefined;
|
|
3349
|
+
tiers?: {
|
|
3350
|
+
cheap?: Record<string, string> | undefined;
|
|
3351
|
+
} | undefined;
|
|
3323
3352
|
reasoning?: Record<string, "high" | "medium" | "low"> | undefined;
|
|
3324
3353
|
api?: {
|
|
3325
3354
|
model: string;
|
package/dist/types/index.js
CHANGED
|
@@ -458,6 +458,11 @@ export const ConfigSchema = z.object({
|
|
|
458
458
|
escalate: z.enum(['always', 'risk']).optional().default('always'),
|
|
459
459
|
/** A model per reviewer name for cross-examination (a narrow verification task), e.g. { claude: "haiku" }. */
|
|
460
460
|
cross_models: z.record(ModelName).optional().default({}),
|
|
461
|
+
/**
|
|
462
|
+
* Cheap-model-first (reviewer/tiering.ts), off unless set: a cheaper model per reviewer name for a change with no
|
|
463
|
+
* risk signal. Experimental: not to be recommended until a backtest shows what the cheap model misses.
|
|
464
|
+
*/
|
|
465
|
+
tiers: z.object({ cheap: z.record(ModelName).optional().default({}) }).optional().default({}),
|
|
461
466
|
/** Reasoning effort per reviewer name where the CLI or API takes one (codex, api): low, medium or high. */
|
|
462
467
|
reasoning: z.record(z.enum(['low', 'medium', 'high'])).optional().default({}),
|
|
463
468
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/core",
|
|
3
|
-
"version": "6.11.0-rc.
|
|
3
|
+
"version": "6.11.0-rc.2",
|
|
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-linux-
|
|
80
|
-
"@rigour-labs/brain-linux-
|
|
81
|
-
"@rigour-labs/brain-
|
|
82
|
-
"@rigour-labs/brain-
|
|
78
|
+
"@rigour-labs/brain-darwin-arm64": "6.11.0-rc.2",
|
|
79
|
+
"@rigour-labs/brain-linux-x64": "6.11.0-rc.2",
|
|
80
|
+
"@rigour-labs/brain-linux-arm64": "6.11.0-rc.2",
|
|
81
|
+
"@rigour-labs/brain-win-x64": "6.11.0-rc.2",
|
|
82
|
+
"@rigour-labs/brain-darwin-x64": "6.11.0-rc.2"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/fs-extra": "^11.0.4",
|