@humanbased/crosscheck 1.2.0-beta.79 → 1.2.0-beta.81

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.
Files changed (64) hide show
  1. package/README.md +51 -5
  2. package/crosscheck.config.example.yml +39 -8
  3. package/dist/__tests__/board.test.js +11 -0
  4. package/dist/__tests__/board.test.js.map +1 -1
  5. package/dist/__tests__/onboard-preservation.test.js +54 -3
  6. package/dist/__tests__/onboard-preservation.test.js.map +1 -1
  7. package/dist/__tests__/repository-guidance.test.js +1 -1
  8. package/dist/__tests__/repository-guidance.test.js.map +1 -1
  9. package/dist/__tests__/review-models.test.js +5 -2
  10. package/dist/__tests__/review-models.test.js.map +1 -1
  11. package/dist/__tests__/review-strategy.test.d.ts +2 -0
  12. package/dist/__tests__/review-strategy.test.d.ts.map +1 -0
  13. package/dist/__tests__/review-strategy.test.js +397 -0
  14. package/dist/__tests__/review-strategy.test.js.map +1 -0
  15. package/dist/commands/onboard.d.ts +25 -3
  16. package/dist/commands/onboard.d.ts.map +1 -1
  17. package/dist/commands/onboard.js +151 -46
  18. package/dist/commands/onboard.js.map +1 -1
  19. package/dist/commands/run.d.ts.map +1 -1
  20. package/dist/commands/run.js +22 -4
  21. package/dist/commands/run.js.map +1 -1
  22. package/dist/commands/watch.d.ts.map +1 -1
  23. package/dist/commands/watch.js +38 -6
  24. package/dist/commands/watch.js.map +1 -1
  25. package/dist/config/review-model-tiers.json +3 -3
  26. package/dist/config/review-strategy.json +204 -0
  27. package/dist/config/schema.d.ts +7 -5
  28. package/dist/config/schema.d.ts.map +1 -1
  29. package/dist/config/schema.js +29 -7
  30. package/dist/config/schema.js.map +1 -1
  31. package/dist/github/client.d.ts +16 -1
  32. package/dist/github/client.d.ts.map +1 -1
  33. package/dist/github/client.js +32 -1
  34. package/dist/github/client.js.map +1 -1
  35. package/dist/github/webhook.d.ts +4 -0
  36. package/dist/github/webhook.d.ts.map +1 -1
  37. package/dist/github/webhook.js.map +1 -1
  38. package/dist/lib/annotation.d.ts +7 -0
  39. package/dist/lib/annotation.d.ts.map +1 -1
  40. package/dist/lib/annotation.js +11 -1
  41. package/dist/lib/annotation.js.map +1 -1
  42. package/dist/lib/board.d.ts +3 -0
  43. package/dist/lib/board.d.ts.map +1 -1
  44. package/dist/lib/board.js +4 -2
  45. package/dist/lib/board.js.map +1 -1
  46. package/dist/lib/comment-bodies.d.ts +2 -0
  47. package/dist/lib/comment-bodies.d.ts.map +1 -1
  48. package/dist/lib/comment-bodies.js +5 -1
  49. package/dist/lib/comment-bodies.js.map +1 -1
  50. package/dist/lib/review-models.d.ts +15 -2
  51. package/dist/lib/review-models.d.ts.map +1 -1
  52. package/dist/lib/review-models.js +19 -6
  53. package/dist/lib/review-models.js.map +1 -1
  54. package/dist/lib/review-strategy.d.ts +92 -0
  55. package/dist/lib/review-strategy.d.ts.map +1 -0
  56. package/dist/lib/review-strategy.js +282 -0
  57. package/dist/lib/review-strategy.js.map +1 -0
  58. package/dist/lib/runner.d.ts +80 -0
  59. package/dist/lib/runner.d.ts.map +1 -1
  60. package/dist/lib/runner.js +289 -17
  61. package/dist/lib/runner.js.map +1 -1
  62. package/docs/dynamic-thoroughness.md +738 -0
  63. package/get-started.md +68 -7
  64. package/package.json +4 -3
@@ -14,25 +14,38 @@ const rawReviewModelTierConfig = require('../config/review-model-tiers.json');
14
14
  const reviewModelTierConfig = ReviewModelTierConfigSchema.parse(rawReviewModelTierConfig);
15
15
  export const CLAUDE_TIER_MODELS = reviewModelTierConfig.claude;
16
16
  export const CODEX_TIER_MODELS_API = reviewModelTierConfig.codex_api;
17
- export function resolveClaudeModel(quality, vendor) {
17
+ /**
18
+ * The tier in force for one call. Under `quality.mode: 'smart'` the per-PR
19
+ * strategy wins; otherwise the single configured tier applies. Falls back to the
20
+ * configured tier whenever no strategy resolved — one-shot commands, or a PR
21
+ * whose file list could not be read.
22
+ */
23
+ export function effectiveTier(quality, strategy) {
24
+ if (quality.mode === 'smart' && strategy?.tier)
25
+ return strategy.tier;
26
+ return quality.tier;
27
+ }
28
+ export function resolveClaudeModel(quality, vendor, strategy) {
18
29
  // An explicit vendors.claude.model wins over the tier mapping. The claude CLI
19
30
  // accepts --model under both subscription and api-key auth, so we honor it
20
31
  // regardless of auth instead of silently dropping it.
21
32
  if (vendor?.model)
22
33
  return vendor.model;
23
- return CLAUDE_TIER_MODELS[quality.tier] ?? CLAUDE_TIER_MODELS.balanced;
34
+ return CLAUDE_TIER_MODELS[effectiveTier(quality, strategy)] ?? CLAUDE_TIER_MODELS.balanced;
24
35
  }
25
- export function resolveCodexModel(quality, vendor) {
36
+ export function resolveCodexModel(quality, vendor, strategy) {
37
+ const tier = effectiveTier(quality, strategy);
26
38
  // An explicitly configured model wins under either auth — the codex CLI
27
39
  // accepts -c model= with subscription (ChatGPT) auth too. Only the built-in
28
40
  // tier mapping stays api-key-only: with nothing configured, subscription
29
- // users keep the CLI's own default model.
30
- const explicit = vendor.model || vendor.model_tiers?.[quality.tier];
41
+ // users keep the CLI's own default model, because the gpt-5.6-* IDs need
42
+ // codex >= 0.147.0 and would 400 on an older CLI.
43
+ const explicit = vendor.model || vendor.model_tiers?.[tier];
31
44
  if (explicit)
32
45
  return explicit;
33
46
  if (vendor.auth !== 'api-key')
34
47
  return 'default';
35
- return CODEX_TIER_MODELS_API[quality.tier] || CODEX_TIER_MODELS_API.balanced;
48
+ return CODEX_TIER_MODELS_API[tier] || CODEX_TIER_MODELS_API.balanced;
36
49
  }
37
50
  // Derives a display name from the regular claude model ID shape:
38
51
  // claude-{family}-{major}[-{minor}][-YYYYMMDD]. New models then render
@@ -1 +1 @@
1
- {"version":3,"file":"review-models.js","sourceRoot":"","sources":["../../src/lib/review-models.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-models.js","sourceRoot":"","sources":["../../src/lib/review-models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import type { QualityConfig } from '../config/schema.js';
2
+ export type Tier = QualityConfig['tier'];
3
+ export type Domain = 'frontend' | 'backend';
4
+ export interface PRContext {
5
+ files: string[];
6
+ additions: number;
7
+ deletions: number;
8
+ labels?: string[];
9
+ title?: string;
10
+ baseRef?: string;
11
+ defaultBranch?: string;
12
+ }
13
+ export interface ResolvedStrategy {
14
+ /** Strategy file version, stamped into every comment so a past review stays explicable. */
15
+ version: string;
16
+ classId: string;
17
+ classLabel: string;
18
+ /** Human-readable rationale, quoted verbatim in the PR comment. */
19
+ reason: string;
20
+ /** null = skip this PR entirely. */
21
+ tier: Tier | null;
22
+ effort: string | null;
23
+ steps: string[];
24
+ focus?: string;
25
+ domain: Domain;
26
+ }
27
+ /**
28
+ * Frontend vs backend, by file-extension majority. `mixed` and `unknown` both
29
+ * fall back to backend — the conservative default, because the backend
30
+ * preference list is `measured` while the frontend list is still a hypothesis.
31
+ */
32
+ export declare function detectDomain(files: string[]): Domain;
33
+ /** Classifies a PR against the strategy's ordered class list. First match wins. */
34
+ export declare function resolveReviewStrategy(pr: PRContext): ResolvedStrategy;
35
+ /** Effort levels a model accepts. Empty array = the model has no effort control. */
36
+ export declare function effortLevelsFor(model: string): string[];
37
+ export declare function isModelBanned(model: string): boolean;
38
+ export declare function strategyModelFor(vendor: string, tier: Tier): string | null;
39
+ export declare function strategyVersion(): string;
40
+ export declare function ladderLimits(): {
41
+ maxRounds: number;
42
+ maxBlocking: number;
43
+ maxWallClockMin: number;
44
+ };
45
+ /** One vendor that may review this round. */
46
+ export interface EscalationLane {
47
+ /** The model that would run for this vendor at the class tier. */
48
+ model: string;
49
+ /** The vendor CLI's effort flags. Omitted = judge on model capability alone. */
50
+ accepted?: readonly string[];
51
+ }
52
+ /**
53
+ * Escalation for round N. Raises effort where the vendor that will actually run
54
+ * can deliver a higher one; where it cannot, degrades to a tier promotion
55
+ * instead — `ladder.effort_fallback`.
56
+ *
57
+ * `lanes` are the vendors in play, not claude alone. Collapsing them produced
58
+ * two separate no-ops:
59
+ * - judging by the claude tier model on a codex-only install promoted a tier
60
+ * every round (haiku exposes no effort ladder) while codex — which accepts
61
+ * none…max — sat at the effort it started on;
62
+ * - judging by MODEL capability alone made round 3 identical to round 2 on
63
+ * claude: claude-opus-5 reasons at `xhigh`, the claude CLI has no flag for
64
+ * it, so the wire effort clamped straight back down to round 2's `high`.
65
+ *
66
+ * So each lane is judged post-clamp, at the wire, and effort rises only when
67
+ * EVERY lane rises there. Otherwise the tier is promoted, which every lane can
68
+ * express.
69
+ *
70
+ * The model never weakens across rounds. Scope narrows instead: a recheck
71
+ * examines the delta plus the open findings, not the whole PR again.
72
+ */
73
+ export declare function escalate(base: {
74
+ tier: Tier;
75
+ effort: string | null;
76
+ }, round: number, lanes: string | readonly EscalationLane[]): {
77
+ tier: Tier;
78
+ effort: string | null;
79
+ };
80
+ /** Clamps a requested effort to what the model actually accepts. */
81
+ export declare function clampEffort(model: string, effort: string | null): string | null;
82
+ /**
83
+ * Clamps a requested effort to an accepted vocabulary.
84
+ *
85
+ * Applied twice on the way to a CLI, against two different sets: what the MODEL
86
+ * can reason at (`models[].effort_levels` here) and what the VENDOR CLI has a
87
+ * flag for (CLAUDE_EFFORT_LEVELS / CODEX_EFFORT_LEVELS in the config schema).
88
+ * They are not the same — claude-opus-5 reasons at `xhigh` and the claude CLI
89
+ * cannot ask for it — and only the second reaches the wire.
90
+ */
91
+ export declare function clampToLevels(effort: string | null, levels: readonly string[]): string | null;
92
+ //# sourceMappingURL=review-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-strategy.d.ts","sourceRoot":"","sources":["../../src/lib/review-strategy.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAIxD,MAAM,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;AACxC,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;AA2E3C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,2FAA2F;IAC3F,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAA;IACd,oCAAoC;IACpC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAUD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAIpD;AAsDD,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,SAAS,GAAG,gBAAgB,CAerE;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAE1E;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,YAAY,IAAI;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAMlG;AAYD,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC3C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE,GACxC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAkCvC;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAE/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAW7F"}
@@ -0,0 +1,282 @@
1
+ // Resolves the per-PR review strategy: which class a PR falls into, which tier
2
+ // and effort that class earns, and which steps run. Reads the versioned policy
3
+ // in config/review-strategy.json so the routing decision and the explanation
4
+ // posted on the PR come from one place and cannot drift apart.
5
+ //
6
+ // Two rules constrain what classification may conclude (see
7
+ // docs/dynamic-thoroughness.md §6.8):
8
+ // - it may set a FLOOR, or promote on CONSEQUENCE (a security path is
9
+ // reviewed thoroughly because a miss there is expensive);
10
+ // - it may NOT predict that a PR will be hard. Static features do not support
11
+ // that inference — difficulty is discovered by reviewing, so escalation is
12
+ // driven by measured non-convergence instead (see escalate()).
13
+ import { createRequire } from 'module';
14
+ import { z } from 'zod';
15
+ const require = createRequire(import.meta.url);
16
+ /** Ordered effort ladder. Index-based so escalation is a step, not a lookup. */
17
+ const EFFORT_LADDER = ['none', 'low', 'medium', 'high', 'xhigh', 'max'];
18
+ const MatchSchema = z.object({
19
+ all_files_match: z.array(z.string()).optional(),
20
+ any_path_matches: z.array(z.string()).optional(),
21
+ or_labels: z.array(z.string()).optional(),
22
+ or_hotfix_to_default_branch: z.boolean().optional(),
23
+ additions_max: z.number().optional(),
24
+ deletions_min: z.number().optional(),
25
+ doc_fraction_min: z.number().optional(),
26
+ config_fraction_min: z.number().optional(),
27
+ source_files_max: z.number().optional(),
28
+ files_max: z.number().optional(),
29
+ src_churn_max: z.number().optional(),
30
+ });
31
+ const PRClassSchema = z.object({
32
+ id: z.string(),
33
+ label: z.string(),
34
+ match: MatchSchema,
35
+ tier: z.enum(['fast', 'balanced', 'thorough']).nullable(),
36
+ // Not z.string(): a typo ("higgh") would validate, then read as -1 in
37
+ // clampEffort and silently drop the whole class to the model's lowest level.
38
+ effort: z.enum(EFFORT_LADDER).nullable(),
39
+ steps: z.array(z.string()),
40
+ focus: z.string().optional(),
41
+ reason: z.string(),
42
+ });
43
+ const StrategySchema = z.object({
44
+ version: z.string(),
45
+ updated: z.string(),
46
+ models: z.record(z.string(), z.object({
47
+ vendor: z.string(),
48
+ effort_levels: z.array(z.string()),
49
+ }).passthrough()),
50
+ banned_models: z.array(z.object({ model: z.string(), reason: z.string() })).default([]),
51
+ vendors: z.record(z.string(), z.object({
52
+ tiers: z.record(z.string(), z.string()),
53
+ }).passthrough()),
54
+ domains: z.record(z.string(), z.unknown()),
55
+ // .min(1): resolveReviewStrategy falls back to the last entry, which is
56
+ // undefined — and throws on `cls.id` — for an empty list.
57
+ pr_classes: z.array(PRClassSchema).min(1),
58
+ ladder: z.object({
59
+ max_blocking_findings: z.number(),
60
+ max_rounds: z.number(),
61
+ max_wall_clock_min: z.number(),
62
+ effort_fallback: z.string(),
63
+ }).passthrough(),
64
+ }).passthrough();
65
+ const raw = require('../config/review-strategy.json');
66
+ const STRATEGY = StrategySchema.parse(raw);
67
+ const TIER_LADDER = ['fast', 'balanced', 'thorough'];
68
+ /** Position on EFFORT_LADDER; -1 for null or an unrecognised level. */
69
+ function effortIndex(effort) {
70
+ return effort === null ? -1 : EFFORT_LADDER.indexOf(effort);
71
+ }
72
+ const FRONTEND_EXT = /\.(tsx|jsx|vue|svelte|css|scss|less|html)$/i;
73
+ const BACKEND_EXT = /\.(py|go|rs|java|rb|php|sql|ts)$/i;
74
+ const DOC_EXT = /\.(md|mdx|rst|adoc)$/i;
75
+ const CONFIG_EXT = /(\.(json|ya?ml|toml|ini|lock|txt|csv|svg|png|jpe?g)$|^\.github\/)/i;
76
+ // Anchored on path segments and extensions. Unanchored, `spec` matched
77
+ // src/lib/pr-spec.ts and `test` matched any latest.ts, routing ordinary source
78
+ // PRs to test_only with a test-focused prompt.
79
+ const TEST_PATH = /((^|\/)(__tests__|tests?|e2e|fixtures?)(\/|$)|\.(test|spec)\.)/i;
80
+ const GENERATED = /((^|\/)(dist|build|node_modules)\/|\.(lock|sum)$|package-lock|pnpm-lock|yarn\.lock|\.(pb|_pb2)\.[a-z]+$|(^|\/)generated\/)/i;
81
+ function srcChurnFraction(files) {
82
+ if (files.length === 0)
83
+ return { doc: 0, config: 0, source: 0 };
84
+ const doc = files.filter(f => DOC_EXT.test(f)).length / files.length;
85
+ const config = files.filter(f => CONFIG_EXT.test(f)).length / files.length;
86
+ const source = files.filter(f => !DOC_EXT.test(f) && !CONFIG_EXT.test(f) && !GENERATED.test(f) && !TEST_PATH.test(f)).length;
87
+ return { doc, config, source };
88
+ }
89
+ /**
90
+ * Frontend vs backend, by file-extension majority. `mixed` and `unknown` both
91
+ * fall back to backend — the conservative default, because the backend
92
+ * preference list is `measured` while the frontend list is still a hypothesis.
93
+ */
94
+ export function detectDomain(files) {
95
+ const fe = files.filter(f => FRONTEND_EXT.test(f)).length;
96
+ const be = files.filter(f => BACKEND_EXT.test(f)).length;
97
+ return fe > be ? 'frontend' : 'backend';
98
+ }
99
+ function matches(cls, pr) {
100
+ const m = cls.match;
101
+ const { files, additions, deletions } = pr;
102
+ // An empty match object is the fallthrough class.
103
+ if (Object.keys(m).length === 0)
104
+ return true;
105
+ // Never classify an empty file list as anything but the fallthrough.
106
+ if (files.length === 0)
107
+ return false;
108
+ if (m.all_files_match) {
109
+ const res = m.all_files_match.map(p => new RegExp(p, 'i'));
110
+ if (!files.every(f => res.some(r => r.test(f))))
111
+ return false;
112
+ }
113
+ // `any_path_matches` is an OR-group with labels and the hotfix rule: any one
114
+ // of the three promotes. Only evaluated when the class declares them.
115
+ if (m.any_path_matches || m.or_labels || m.or_hotfix_to_default_branch) {
116
+ const pathHit = m.any_path_matches
117
+ ? files.some(f => m.any_path_matches.some(p => new RegExp(p, 'i').test(f)))
118
+ : false;
119
+ const labelHit = m.or_labels ? (pr.labels ?? []).some(l => m.or_labels.includes(l)) : false;
120
+ const hotfixHit = m.or_hotfix_to_default_branch === true
121
+ && /^hotfix/i.test(pr.title ?? '')
122
+ && pr.baseRef !== undefined
123
+ && pr.baseRef === pr.defaultBranch;
124
+ if (!pathHit && !labelHit && !hotfixHit)
125
+ return false;
126
+ }
127
+ if (m.additions_max !== undefined && additions > m.additions_max)
128
+ return false;
129
+ // A floor on deletions, not merely "some deletions": a +2/-2 typo fix has
130
+ // near-zero additions too, and is a modification rather than a removal.
131
+ if (m.deletions_min !== undefined && deletions < m.deletions_min)
132
+ return false;
133
+ const frac = srcChurnFraction(files);
134
+ if (m.doc_fraction_min !== undefined && frac.doc < m.doc_fraction_min)
135
+ return false;
136
+ if (m.config_fraction_min !== undefined && frac.config < m.config_fraction_min)
137
+ return false;
138
+ if (m.source_files_max !== undefined && frac.source > m.source_files_max)
139
+ return false;
140
+ if (m.files_max !== undefined && files.length > m.files_max)
141
+ return false;
142
+ if (m.src_churn_max !== undefined) {
143
+ const srcFiles = files.filter(f => !GENERATED.test(f) && !CONFIG_EXT.test(f));
144
+ // Churn is only attributable per-file with a full diff; approximate with the
145
+ // PR total when the change is entirely source, which is the case that matters.
146
+ // Fails CLOSED when churn cannot be attributed: falling back to 0 passed
147
+ // every cap, so one stray config file routed a 5,000-line change to the
148
+ // core runner into `trivial` — fast tier, no recheck.
149
+ const churn = srcFiles.length === files.length ? additions + deletions : Infinity;
150
+ if (churn > m.src_churn_max)
151
+ return false;
152
+ }
153
+ return true;
154
+ }
155
+ /** Classifies a PR against the strategy's ordered class list. First match wins. */
156
+ export function resolveReviewStrategy(pr) {
157
+ const cls = STRATEGY.pr_classes.find(c => matches(c, pr))
158
+ ?? STRATEGY.pr_classes[STRATEGY.pr_classes.length - 1];
159
+ return {
160
+ version: STRATEGY.version,
161
+ classId: cls.id,
162
+ classLabel: cls.label,
163
+ reason: cls.reason,
164
+ tier: cls.tier,
165
+ effort: cls.effort,
166
+ steps: cls.steps,
167
+ ...(cls.focus !== undefined && { focus: cls.focus }),
168
+ domain: detectDomain(pr.files),
169
+ };
170
+ }
171
+ /** Effort levels a model accepts. Empty array = the model has no effort control. */
172
+ export function effortLevelsFor(model) {
173
+ return STRATEGY.models[model]?.effort_levels ?? [];
174
+ }
175
+ export function isModelBanned(model) {
176
+ return STRATEGY.banned_models.some(b => b.model === model);
177
+ }
178
+ export function strategyModelFor(vendor, tier) {
179
+ return STRATEGY.vendors[vendor]?.tiers[tier] ?? null;
180
+ }
181
+ export function strategyVersion() {
182
+ return STRATEGY.version;
183
+ }
184
+ export function ladderLimits() {
185
+ return {
186
+ maxRounds: STRATEGY.ladder.max_rounds,
187
+ maxBlocking: STRATEGY.ladder.max_blocking_findings,
188
+ maxWallClockMin: STRATEGY.ladder.max_wall_clock_min,
189
+ };
190
+ }
191
+ /**
192
+ * True when the strategy's model map has an entry for this ID — i.e. its effort
193
+ * ladder is known at all. Distinct from an entry whose ladder is empty: haiku's
194
+ * `[]` means "no effort control", while a pinned ID or codex under subscription
195
+ * auth (where the CLI picks the model) means "capability unknown".
196
+ */
197
+ function modelIsKnown(model) {
198
+ return Object.prototype.hasOwnProperty.call(STRATEGY.models, model);
199
+ }
200
+ /**
201
+ * Escalation for round N. Raises effort where the vendor that will actually run
202
+ * can deliver a higher one; where it cannot, degrades to a tier promotion
203
+ * instead — `ladder.effort_fallback`.
204
+ *
205
+ * `lanes` are the vendors in play, not claude alone. Collapsing them produced
206
+ * two separate no-ops:
207
+ * - judging by the claude tier model on a codex-only install promoted a tier
208
+ * every round (haiku exposes no effort ladder) while codex — which accepts
209
+ * none…max — sat at the effort it started on;
210
+ * - judging by MODEL capability alone made round 3 identical to round 2 on
211
+ * claude: claude-opus-5 reasons at `xhigh`, the claude CLI has no flag for
212
+ * it, so the wire effort clamped straight back down to round 2's `high`.
213
+ *
214
+ * So each lane is judged post-clamp, at the wire, and effort rises only when
215
+ * EVERY lane rises there. Otherwise the tier is promoted, which every lane can
216
+ * express.
217
+ *
218
+ * The model never weakens across rounds. Scope narrows instead: a recheck
219
+ * examines the delta plus the open findings, not the whole PR again.
220
+ */
221
+ export function escalate(base, round, lanes) {
222
+ if (round <= 1)
223
+ return base;
224
+ const list = typeof lanes === 'string' ? [{ model: lanes }] : lanes;
225
+ // Both clamps, in order: what the MODEL can reason at, then what the CLI has a
226
+ // flag for. Only the second reaches the wire.
227
+ const wire = (lane, effort) => {
228
+ const atModel = modelIsKnown(lane.model) ? clampToLevels(effort, effortLevelsFor(lane.model)) : effort;
229
+ return lane.accepted ? clampToLevels(atModel, lane.accepted) : atModel;
230
+ };
231
+ // Compare the target against what the round before already asked for. An exact
232
+ // `levels.includes(target)` test made round 3 miss on any model whose ladder
233
+ // tops out below xhigh (deepseek: none/high/max) and return base.effort —
234
+ // weaker than round 2.
235
+ const target = round >= 3 ? 'xhigh' : 'high';
236
+ const previousTarget = round >= 3 ? 'high' : base.effort;
237
+ const clamped = list.map(lane => wire(lane, target));
238
+ const rises = list.length > 0 && list.every((lane, i) => {
239
+ const now = clamped[i];
240
+ return now !== null && effortIndex(now) > effortIndex(wire(lane, previousTarget) ?? base.effort);
241
+ });
242
+ // The strongest level any lane accepts; each vendor config is clamped back down
243
+ // to its own vocabulary downstream (strategyVendor), so a lane that cannot
244
+ // reach it is not sent it.
245
+ const best = clamped.reduce((a, b) => (effortIndex(b) > effortIndex(a) ? b : a), null);
246
+ if (rises)
247
+ return { tier: base.tier, effort: best };
248
+ // Effort cannot rise on at least one lane — promote a tier instead (the
249
+ // strategy's ladder.effort_fallback), capped at thorough.
250
+ const idx = TIER_LADDER.indexOf(base.tier);
251
+ const promoted = TIER_LADDER[Math.min(idx + 1, TIER_LADDER.length - 1)];
252
+ return { tier: promoted, effort: best ?? base.effort };
253
+ }
254
+ /** Clamps a requested effort to what the model actually accepts. */
255
+ export function clampEffort(model, effort) {
256
+ return clampToLevels(effort, effortLevelsFor(model));
257
+ }
258
+ /**
259
+ * Clamps a requested effort to an accepted vocabulary.
260
+ *
261
+ * Applied twice on the way to a CLI, against two different sets: what the MODEL
262
+ * can reason at (`models[].effort_levels` here) and what the VENDOR CLI has a
263
+ * flag for (CLAUDE_EFFORT_LEVELS / CODEX_EFFORT_LEVELS in the config schema).
264
+ * They are not the same — claude-opus-5 reasons at `xhigh` and the claude CLI
265
+ * cannot ask for it — and only the second reaches the wire.
266
+ */
267
+ export function clampToLevels(effort, levels) {
268
+ if (effort === null || levels.length === 0)
269
+ return null;
270
+ if (levels.includes(effort))
271
+ return effort;
272
+ // Snap down to the nearest supported level rather than failing the call. When
273
+ // the vocabulary has nothing at or below the request, snap UP to its lowest
274
+ // level instead — sending an effort that is rejected fails the call outright.
275
+ const want = EFFORT_LADDER.indexOf(effort);
276
+ for (let i = want; i >= 0; i--) {
277
+ if (levels.includes(EFFORT_LADDER[i]))
278
+ return EFFORT_LADDER[i];
279
+ }
280
+ return levels[0] ?? null;
281
+ }
282
+ //# sourceMappingURL=review-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-strategy.js","sourceRoot":"","sources":["../../src/lib/review-strategy.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import type { PREvent } from '../github/webhook.js';
3
3
  import type { PROrigin } from '../github/detector.js';
4
4
  import type { Vendor } from '../lib/vendor.js';
5
5
  import { type ResolvedLinearAuth } from '../linear/identity.js';
6
+ import { type PRContext, type ResolvedStrategy } from './review-strategy.js';
6
7
  import { type StepResult } from '../lib/workflow.js';
7
8
  import type { PRPhase } from '../lib/board.js';
8
9
  export declare function isRetryableFixError(err: unknown): boolean;
@@ -85,6 +86,9 @@ export interface WorkflowContext {
85
86
  }
86
87
  export interface WorkflowResult {
87
88
  verdict: string | null;
89
+ /** Set when the review strategy classified the PR as not worth reviewing
90
+ * (e.g. a lockfile-only change). Carries the matched class id. */
91
+ strategySkipped?: string;
88
92
  fixAppliedCount?: number;
89
93
  fixSkipReason?: string;
90
94
  latestReviewComment?: {
@@ -96,5 +100,81 @@ export declare function resolveFixVendor(stepReviewer: string, origin: PROrigin,
96
100
  vendor: 'claude' | 'codex' | null;
97
101
  usedHumanFallback: boolean;
98
102
  };
103
+ /**
104
+ * Builds the input the review strategy classifies on, from the already-cloned
105
+ * working copy rather than the API — the runner has the repo on disk, so this
106
+ * costs one `git diff` instead of a round trip.
107
+ *
108
+ * Returns null when the diff can't be read. Callers then fall back to the
109
+ * configured tier, which is why `quality.tier` stays meaningful under smart mode.
110
+ */
111
+ export declare function buildPRContext(ctx: WorkflowContext): PRContext | null;
112
+ /**
113
+ * Folds a resolved strategy into the quality config the reviewers receive, so
114
+ * every downstream `quality.tier` read picks up the per-PR decision without
115
+ * threading a new parameter through each vendor signature.
116
+ *
117
+ * A null strategy — fixed mode, or an unreadable diff — returns the config
118
+ * untouched, which is why `quality.tier` remains the documented fallback.
119
+ */
120
+ export declare function strategyQuality(quality: WorkflowContext['config']['quality'], strategy: ResolvedStrategy | null): WorkflowContext['config']['quality'];
121
+ /**
122
+ * Applies the class's effort alongside its tier. Without this the strategy's
123
+ * effort was resolved and logged but never sent, so the run line named a level
124
+ * the CLI was never given.
125
+ *
126
+ * `accepted` is the vendor CLI's vocabulary, which is narrower than the model's:
127
+ * the strategy escalates to `xhigh` on round 3 and claude-opus-5 reasons at that
128
+ * level, but the claude CLI has no flag for it, so claudeEffort() mapped the
129
+ * unknown value to `medium` — a round 3 weaker than round 2. Clamp here, where
130
+ * the strategy meets the config, rather than at each CLI.
131
+ */
132
+ export declare function strategyVendor<T extends {
133
+ effort?: string;
134
+ }>(vendor: T, strategy: ResolvedStrategy | null, accepted: readonly string[]): T;
135
+ /**
136
+ * True when the strategy actually determined the model that ran.
137
+ *
138
+ * Judged from the resolved model rather than from config shape, because two
139
+ * different configs defeat the tier map:
140
+ * - an explicit `vendors.*.model` outranks it, and
141
+ * - codex under subscription auth with no `model`/`model_tiers` resolves every
142
+ * tier to the CLI's own `default`, so fast/balanced/thorough are the same run.
143
+ * In both cases the strategy's tier is not what happened, and citing it would
144
+ * assert a routing decision that never took place — the exact auditability
145
+ * property this feature exists to provide.
146
+ */
147
+ export declare function strategyDeterminedModel(vendor: {
148
+ model?: string | null;
149
+ }, strategy: ResolvedStrategy | null, resolvedModel?: string): boolean;
150
+ /**
151
+ * Classifies the PR and resolves the strategy, or returns null under
152
+ * `quality.mode: fixed` so the single configured tier applies unchanged.
153
+ */
154
+ export declare function resolveStrategyForPR(ctx: WorkflowContext): ResolvedStrategy | null;
155
+ export interface RoundExecution {
156
+ /** The class as escalated for this round; null under fixed mode. */
157
+ strategy: ResolvedStrategy | null;
158
+ quality: Config['quality'];
159
+ claudeVendor: Config['vendors']['claude'];
160
+ codexVendor: Config['vendors']['codex'];
161
+ /** `config` with the above folded in, for callees that take the whole config. */
162
+ roundConfig: Config;
163
+ escalated: boolean;
164
+ }
165
+ /**
166
+ * The tier, effort, and vendor configs every step of one round runs under.
167
+ *
168
+ * One function rather than a fold at each use site: the review step ran the
169
+ * escalated strategy while the fix step re-folded the base class, so a promoted
170
+ * round reviewed with the stronger model and then fixed with the weaker one —
171
+ * and took the weaker tier's subprocess timeout with it.
172
+ *
173
+ * Rounds beyond the first escalate: the class tier was already tried and did not
174
+ * resolve the PR, so difficulty is now measured rather than predicted. escalate()
175
+ * raises effort where the model supports it and promotes a tier where it does
176
+ * not, and never weakens the model.
177
+ */
178
+ export declare function resolveRoundExecution(config: Config, strategy: ResolvedStrategy | null, round: number): RoundExecution;
99
179
  export declare function runWorkflow(ctx: WorkflowContext): Promise<WorkflowResult>;
100
180
  //# sourceMappingURL=runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/lib/runner.ts"],"names":[],"mappings":"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"}