@humanbased/crosscheck 1.2.0 → 1.3.0-beta.82
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/LICENSE +1 -1
- package/README.md +182 -375
- package/README.zh.md +1 -1
- package/assets/icon-256.png +0 -0
- package/assets/linear-comment.svg +18 -0
- package/assets/linear-onboard.svg +30 -0
- package/assets/linear-status.svg +23 -0
- package/assets/linear-test.svg +34 -0
- package/assets/skills/code-review/.crosscheck-skill.json +9 -0
- package/assets/skills/code-review/LICENSE +21 -0
- package/assets/skills/code-review/SKILL.md +89 -0
- package/assets/skills/code-review/agents/openai.yaml +3 -0
- package/assets/skills/code-review-skill/.crosscheck-skill.json +9 -0
- package/assets/skills/code-review-skill/LICENSE +21 -0
- package/assets/skills/code-review-skill/SKILL.md +231 -0
- package/assets/skills/code-review-skill/assets/pr-review-template.md +137 -0
- package/assets/skills/code-review-skill/assets/review-checklist.md +123 -0
- package/assets/skills/code-review-skill/reference/angular.md +768 -0
- package/assets/skills/code-review-skill/reference/architecture-review-guide.md +472 -0
- package/assets/skills/code-review-skill/reference/c.md +890 -0
- package/assets/skills/code-review-skill/reference/code-quality-universal.md +488 -0
- package/assets/skills/code-review-skill/reference/code-review-best-practices.md +136 -0
- package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +286 -0
- package/assets/skills/code-review-skill/reference/cpp.md +893 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +515 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +492 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +309 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +308 -0
- package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +264 -0
- package/assets/skills/code-review-skill/reference/csharp.md +525 -0
- package/assets/skills/code-review-skill/reference/css-less-sass.md +661 -0
- package/assets/skills/code-review-skill/reference/django.md +985 -0
- package/assets/skills/code-review-skill/reference/fastapi.md +580 -0
- package/assets/skills/code-review-skill/reference/go.md +993 -0
- package/assets/skills/code-review-skill/reference/java.md +409 -0
- package/assets/skills/code-review-skill/reference/java8.md +586 -0
- package/assets/skills/code-review-skill/reference/kotlin.md +1018 -0
- package/assets/skills/code-review-skill/reference/nestjs.md +593 -0
- package/assets/skills/code-review-skill/reference/performance-review-guide.md +816 -0
- package/assets/skills/code-review-skill/reference/php.md +684 -0
- package/assets/skills/code-review-skill/reference/python.md +1073 -0
- package/assets/skills/code-review-skill/reference/qt.md +757 -0
- package/assets/skills/code-review-skill/reference/react.md +871 -0
- package/assets/skills/code-review-skill/reference/ruby.md +964 -0
- package/assets/skills/code-review-skill/reference/rust.md +846 -0
- package/assets/skills/code-review-skill/reference/security-review-guide.md +494 -0
- package/assets/skills/code-review-skill/reference/svelte.md +1064 -0
- package/assets/skills/code-review-skill/reference/swift.md +936 -0
- package/assets/skills/code-review-skill/reference/typescript.md +1016 -0
- package/assets/skills/code-review-skill/reference/vue.md +924 -0
- package/assets/skills/code-review-skill/reference/zig.md +440 -0
- package/assets/skills/code-review-skill/scripts/pr-analyzer.py +435 -0
- package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +380 -0
- package/assets/skills/codebase-design/.crosscheck-skill.json +9 -0
- package/assets/skills/codebase-design/DEEPENING.md +37 -0
- package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/assets/skills/codebase-design/LICENSE +21 -0
- package/assets/skills/codebase-design/SKILL.md +114 -0
- package/assets/skills/codebase-design/agents/openai.yaml +3 -0
- package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +9 -0
- package/assets/skills/diagnosing-bugs/LICENSE +21 -0
- package/assets/skills/diagnosing-bugs/SKILL.md +134 -0
- package/assets/skills/diagnosing-bugs/agents/openai.yaml +3 -0
- package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/crosscheck.config.example.yml +101 -9
- package/dist/__tests__/board.test.js +11 -0
- package/dist/__tests__/board.test.js.map +1 -1
- package/dist/__tests__/can-write-verdict.test.d.ts +2 -0
- package/dist/__tests__/can-write-verdict.test.d.ts.map +1 -0
- package/dist/__tests__/can-write-verdict.test.js +31 -0
- package/dist/__tests__/can-write-verdict.test.js.map +1 -0
- package/dist/__tests__/codex.test.js +14 -27
- package/dist/__tests__/codex.test.js.map +1 -1
- package/dist/__tests__/comment-bodies.test.js +49 -1
- package/dist/__tests__/comment-bodies.test.js.map +1 -1
- package/dist/__tests__/conflict-resolve.test.js +44 -1
- package/dist/__tests__/conflict-resolve.test.js.map +1 -1
- package/dist/__tests__/fix.test.js +33 -0
- package/dist/__tests__/fix.test.js.map +1 -1
- package/dist/__tests__/linear-branding.test.d.ts +2 -0
- package/dist/__tests__/linear-branding.test.d.ts.map +1 -0
- package/dist/__tests__/linear-branding.test.js +156 -0
- package/dist/__tests__/linear-branding.test.js.map +1 -0
- package/dist/__tests__/linear-client.test.d.ts +2 -0
- package/dist/__tests__/linear-client.test.d.ts.map +1 -0
- package/dist/__tests__/linear-client.test.js +120 -0
- package/dist/__tests__/linear-client.test.js.map +1 -0
- package/dist/__tests__/linear-comment.test.d.ts +2 -0
- package/dist/__tests__/linear-comment.test.d.ts.map +1 -0
- package/dist/__tests__/linear-comment.test.js +151 -0
- package/dist/__tests__/linear-comment.test.js.map +1 -0
- package/dist/__tests__/linear-identity.test.d.ts +2 -0
- package/dist/__tests__/linear-identity.test.d.ts.map +1 -0
- package/dist/__tests__/linear-identity.test.js +253 -0
- package/dist/__tests__/linear-identity.test.js.map +1 -0
- package/dist/__tests__/linear-notify.test.d.ts +2 -0
- package/dist/__tests__/linear-notify.test.d.ts.map +1 -0
- package/dist/__tests__/linear-notify.test.js +144 -0
- package/dist/__tests__/linear-notify.test.js.map +1 -0
- package/dist/__tests__/linear-ref.test.d.ts +2 -0
- package/dist/__tests__/linear-ref.test.d.ts.map +1 -0
- package/dist/__tests__/linear-ref.test.js +261 -0
- package/dist/__tests__/linear-ref.test.js.map +1 -0
- package/dist/__tests__/linear-test-ref.test.d.ts +2 -0
- package/dist/__tests__/linear-test-ref.test.d.ts.map +1 -0
- package/dist/__tests__/linear-test-ref.test.js +81 -0
- package/dist/__tests__/linear-test-ref.test.js.map +1 -0
- package/dist/__tests__/linear-verify.test.d.ts +2 -0
- package/dist/__tests__/linear-verify.test.d.ts.map +1 -0
- package/dist/__tests__/linear-verify.test.js +132 -0
- package/dist/__tests__/linear-verify.test.js.map +1 -0
- package/dist/__tests__/linear-worker.test.d.ts +2 -0
- package/dist/__tests__/linear-worker.test.d.ts.map +1 -0
- package/dist/__tests__/linear-worker.test.js +83 -0
- package/dist/__tests__/linear-worker.test.js.map +1 -0
- package/dist/__tests__/linear-write-possible.test.d.ts +2 -0
- package/dist/__tests__/linear-write-possible.test.d.ts.map +1 -0
- package/dist/__tests__/linear-write-possible.test.js +30 -0
- package/dist/__tests__/linear-write-possible.test.js.map +1 -0
- package/dist/__tests__/onboard-preservation.test.js +59 -3
- package/dist/__tests__/onboard-preservation.test.js.map +1 -1
- package/dist/__tests__/optimize.test.js +2 -0
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/__tests__/pr-status.test.js +163 -2
- package/dist/__tests__/pr-status.test.js.map +1 -1
- package/dist/__tests__/pr-workflow-state.test.js +102 -1
- package/dist/__tests__/pr-workflow-state.test.js.map +1 -1
- package/dist/__tests__/repo-picker.test.js +7 -1
- package/dist/__tests__/repo-picker.test.js.map +1 -1
- package/dist/__tests__/repository-guidance.test.d.ts +2 -0
- package/dist/__tests__/repository-guidance.test.d.ts.map +1 -0
- package/dist/__tests__/repository-guidance.test.js +107 -0
- package/dist/__tests__/repository-guidance.test.js.map +1 -0
- package/dist/__tests__/review-comment-body.test.js +35 -0
- package/dist/__tests__/review-comment-body.test.js.map +1 -1
- package/dist/__tests__/review-models.test.js +19 -3
- package/dist/__tests__/review-models.test.js.map +1 -1
- package/dist/__tests__/review-strategy.test.d.ts +2 -0
- package/dist/__tests__/review-strategy.test.d.ts.map +1 -0
- package/dist/__tests__/review-strategy.test.js +397 -0
- package/dist/__tests__/review-strategy.test.js.map +1 -0
- package/dist/__tests__/runner.test.js +29 -1
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/__tests__/skill-attribution.test.d.ts +2 -0
- package/dist/__tests__/skill-attribution.test.d.ts.map +1 -0
- package/dist/__tests__/skill-attribution.test.js +53 -0
- package/dist/__tests__/skill-attribution.test.js.map +1 -0
- package/dist/__tests__/skill-broker.test.d.ts +2 -0
- package/dist/__tests__/skill-broker.test.d.ts.map +1 -0
- package/dist/__tests__/skill-broker.test.js +144 -0
- package/dist/__tests__/skill-broker.test.js.map +1 -0
- package/dist/__tests__/skill-catalog.test.d.ts +2 -0
- package/dist/__tests__/skill-catalog.test.d.ts.map +1 -0
- package/dist/__tests__/skill-catalog.test.js +40 -0
- package/dist/__tests__/skill-catalog.test.js.map +1 -0
- package/dist/__tests__/skill-installer.test.d.ts +2 -0
- package/dist/__tests__/skill-installer.test.d.ts.map +1 -0
- package/dist/__tests__/skill-installer.test.js +96 -0
- package/dist/__tests__/skill-installer.test.js.map +1 -0
- package/dist/__tests__/skills-config.test.d.ts +2 -0
- package/dist/__tests__/skills-config.test.d.ts.map +1 -0
- package/dist/__tests__/skills-config.test.js +12 -0
- package/dist/__tests__/skills-config.test.js.map +1 -0
- package/dist/cli.js +29 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/detect-step.d.ts.map +1 -1
- package/dist/commands/detect-step.js +4 -0
- package/dist/commands/detect-step.js.map +1 -1
- package/dist/commands/kickass.d.ts.map +1 -1
- package/dist/commands/kickass.js +3 -2
- package/dist/commands/kickass.js.map +1 -1
- package/dist/commands/linear-test.d.ts +18 -0
- package/dist/commands/linear-test.d.ts.map +1 -0
- package/dist/commands/linear-test.js +130 -0
- package/dist/commands/linear-test.js.map +1 -0
- package/dist/commands/onboard.d.ts +36 -3
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +233 -42
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +65 -6
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +51 -7
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/skill.d.ts +2 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +16 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +53 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +169 -64
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/loader.d.ts +3 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +13 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/review-model-tiers.json +3 -3
- package/dist/config/review-strategy.json +204 -0
- package/dist/config/schema.d.ts +261 -15
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +90 -8
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.d.ts +21 -1
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +46 -7
- package/dist/github/client.js.map +1 -1
- package/dist/github/webhook.d.ts +4 -0
- package/dist/github/webhook.d.ts.map +1 -1
- package/dist/github/webhook.js.map +1 -1
- package/dist/issues/ticket-ref.d.ts.map +1 -1
- package/dist/issues/ticket-ref.js +6 -5
- package/dist/issues/ticket-ref.js.map +1 -1
- package/dist/lib/annotation.d.ts +7 -0
- package/dist/lib/annotation.d.ts.map +1 -1
- package/dist/lib/annotation.js +11 -1
- package/dist/lib/annotation.js.map +1 -1
- package/dist/lib/board.d.ts +3 -0
- package/dist/lib/board.d.ts.map +1 -1
- package/dist/lib/board.js +4 -2
- package/dist/lib/board.js.map +1 -1
- package/dist/lib/clone.d.ts +1 -0
- package/dist/lib/clone.d.ts.map +1 -1
- package/dist/lib/clone.js +32 -10
- package/dist/lib/clone.js.map +1 -1
- package/dist/lib/comment-bodies.d.ts +37 -0
- package/dist/lib/comment-bodies.d.ts.map +1 -1
- package/dist/lib/comment-bodies.js +47 -9
- package/dist/lib/comment-bodies.js.map +1 -1
- package/dist/lib/pr-status.d.ts.map +1 -1
- package/dist/lib/pr-status.js +36 -2
- package/dist/lib/pr-status.js.map +1 -1
- package/dist/lib/pr-workflow-state.d.ts +5 -0
- package/dist/lib/pr-workflow-state.d.ts.map +1 -1
- package/dist/lib/pr-workflow-state.js +36 -1
- package/dist/lib/pr-workflow-state.js.map +1 -1
- package/dist/lib/repo-picker.d.ts +3 -0
- package/dist/lib/repo-picker.d.ts.map +1 -1
- package/dist/lib/repo-picker.js +45 -9
- package/dist/lib/repo-picker.js.map +1 -1
- package/dist/lib/repository-guidance.d.ts +2 -0
- package/dist/lib/repository-guidance.d.ts.map +1 -0
- package/dist/lib/repository-guidance.js +55 -0
- package/dist/lib/repository-guidance.js.map +1 -0
- package/dist/lib/review-models.d.ts +15 -2
- package/dist/lib/review-models.d.ts.map +1 -1
- package/dist/lib/review-models.js +26 -6
- package/dist/lib/review-models.js.map +1 -1
- package/dist/lib/review-strategy.d.ts +92 -0
- package/dist/lib/review-strategy.d.ts.map +1 -0
- package/dist/lib/review-strategy.js +282 -0
- package/dist/lib/review-strategy.js.map +1 -0
- package/dist/lib/runner.d.ts +92 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +470 -54
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/workflow.d.ts +9 -0
- package/dist/lib/workflow.d.ts.map +1 -1
- package/dist/lib/workflow.js +20 -0
- package/dist/lib/workflow.js.map +1 -1
- package/dist/linear/client.d.ts +18 -0
- package/dist/linear/client.d.ts.map +1 -0
- package/dist/linear/client.js +67 -0
- package/dist/linear/client.js.map +1 -0
- package/dist/linear/comment.d.ts +20 -0
- package/dist/linear/comment.d.ts.map +1 -0
- package/dist/linear/comment.js +57 -0
- package/dist/linear/comment.js.map +1 -0
- package/dist/linear/identity.d.ts +59 -0
- package/dist/linear/identity.d.ts.map +1 -0
- package/dist/linear/identity.js +187 -0
- package/dist/linear/identity.js.map +1 -0
- package/dist/linear/notify.d.ts +35 -0
- package/dist/linear/notify.d.ts.map +1 -0
- package/dist/linear/notify.js +76 -0
- package/dist/linear/notify.js.map +1 -0
- package/dist/linear/ref.d.ts +13 -0
- package/dist/linear/ref.d.ts.map +1 -0
- package/dist/linear/ref.js +90 -0
- package/dist/linear/ref.js.map +1 -0
- package/dist/linear/verify.d.ts +26 -0
- package/dist/linear/verify.d.ts.map +1 -0
- package/dist/linear/verify.js +67 -0
- package/dist/linear/verify.js.map +1 -0
- package/dist/reviewers/claude.d.ts +4 -1
- package/dist/reviewers/claude.d.ts.map +1 -1
- package/dist/reviewers/claude.js +39 -7
- package/dist/reviewers/claude.js.map +1 -1
- package/dist/reviewers/codex.d.ts +3 -1
- package/dist/reviewers/codex.d.ts.map +1 -1
- package/dist/reviewers/codex.js +76 -70
- package/dist/reviewers/codex.js.map +1 -1
- package/dist/reviewers/conflict-resolve.d.ts +3 -1
- package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
- package/dist/reviewers/conflict-resolve.js +21 -6
- package/dist/reviewers/conflict-resolve.js.map +1 -1
- package/dist/reviewers/fix.d.ts +5 -2
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +26 -10
- package/dist/reviewers/fix.js.map +1 -1
- package/dist/skills/attribution.d.ts +4 -0
- package/dist/skills/attribution.d.ts.map +1 -0
- package/dist/skills/attribution.js +14 -0
- package/dist/skills/attribution.js.map +1 -0
- package/dist/skills/broker-server.d.ts +2 -0
- package/dist/skills/broker-server.d.ts.map +1 -0
- package/dist/skills/broker-server.js +17 -0
- package/dist/skills/broker-server.js.map +1 -0
- package/dist/skills/broker.d.ts +42 -0
- package/dist/skills/broker.d.ts.map +1 -0
- package/dist/skills/broker.js +285 -0
- package/dist/skills/broker.js.map +1 -0
- package/dist/skills/catalog.d.ts +28 -0
- package/dist/skills/catalog.d.ts.map +1 -0
- package/dist/skills/catalog.js +104 -0
- package/dist/skills/catalog.js.map +1 -0
- package/dist/skills/installer.d.ts +10 -0
- package/dist/skills/installer.d.ts.map +1 -0
- package/dist/skills/installer.js +138 -0
- package/dist/skills/installer.js.map +1 -0
- package/dist/skills/integrity.d.ts +4 -0
- package/dist/skills/integrity.d.ts.map +1 -0
- package/dist/skills/integrity.js +36 -0
- package/dist/skills/integrity.js.map +1 -0
- package/docs/dynamic-thoroughness.md +738 -0
- package/docs/linear-identity-contract.md +139 -0
- package/docs/linear-identity.md +293 -0
- package/get-started.md +223 -11
- package/package.json +4 -3
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
# Dynamic thoroughness — design & evidence
|
|
2
|
+
|
|
3
|
+
| | |
|
|
4
|
+
|---|---|
|
|
5
|
+
| **Strategy version** | `1.1.0` — [`src/config/review-strategy.json`](../src/config/review-strategy.json) |
|
|
6
|
+
| **Analysis run** | 2026-08-07T05:00:00Z |
|
|
7
|
+
| **Census window** | 2026-07-30 → 2026-08-07 |
|
|
8
|
+
| **Corpus** | 400 merged PRs · 199 crosscheck-engaged · 597 agent calls · 43 locally-logged runs |
|
|
9
|
+
| **Hand-labelled** | 40 BLOCK findings read against cited source |
|
|
10
|
+
| **Next review due** | 2026-10-06 (60-day interval) |
|
|
11
|
+
| **Re-verify** | `npm run verify:strategy` |
|
|
12
|
+
|
|
13
|
+
Status: **adopted and active**. This document is the evidence behind
|
|
14
|
+
[`review-strategy.json`](../src/config/review-strategy.json); the JSON is what
|
|
15
|
+
crosscheck reads at runtime. The runner classifies every PR from its cloned
|
|
16
|
+
working copy, folds the result into the quality config the reviewers receive,
|
|
17
|
+
and stamps the version, class, and tier into each annotation. When they disagree, the JSON wins and this document is
|
|
18
|
+
stale — the weekly `Review Strategy` workflow files an issue when either drifts.
|
|
19
|
+
|
|
20
|
+
**Enforced today:** the `Tier`, `Effort`, and `Steps` columns below all reach the
|
|
21
|
+
run. A class resolving to a null tier (class 1) skips the workflow outright; the
|
|
22
|
+
per-class step set narrows the configured pipeline (never widens it — a repo
|
|
23
|
+
pinned to review-only stays review-only); and rounds past the first escalate via
|
|
24
|
+
`escalate()`, raising effort where the model supports it and promoting the tier
|
|
25
|
+
where it does not.
|
|
26
|
+
|
|
27
|
+
Comments cite only what actually applied — no tier is named when the class
|
|
28
|
+
selects none, or when an explicit `vendors.*.model` outranks the strategy — so
|
|
29
|
+
the citation never claims more than the runtime does.
|
|
30
|
+
|
|
31
|
+
Every crosscheck comment cites the strategy version it ran under, so a review from
|
|
32
|
+
last month can be explained by the policy in force when it ran rather than the policy
|
|
33
|
+
in force today.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 0. The goal, and what it implies
|
|
38
|
+
|
|
39
|
+
The objective is **shipping quality code at a faster pace**. Code review is
|
|
40
|
+
instrumental to that, not an end in itself. So the metric that matters is not cost per
|
|
41
|
+
review, and not findings per review. It is:
|
|
42
|
+
|
|
43
|
+
> **Actioned-finding rate** — the share of real defects that get fixed *inside the
|
|
44
|
+
> merge window*.
|
|
45
|
+
|
|
46
|
+
A finding that arrives after merge is worth nothing. A finding the author declines to
|
|
47
|
+
act on is worth nothing. A correct finding nobody reads is worth nothing. Everything
|
|
48
|
+
below is organized around that.
|
|
49
|
+
|
|
50
|
+
Measured against it, the current system has a specific and non-obvious problem:
|
|
51
|
+
|
|
52
|
+
| | Measured | Reading |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| Review lands before merge | **94%** | Delivery works. |
|
|
55
|
+
| Findings that are real defects | **~85%** (hand-labelled, n=39) | Quality works. Noise is not the bottleneck. |
|
|
56
|
+
| PRs reaching APPROVE | **38%** | Action does not happen. |
|
|
57
|
+
| Median gap, last review → merge | **4 minutes** | **The author was already merging.** |
|
|
58
|
+
|
|
59
|
+
The reviewer is fast and it is right, and 62% of its output is merged past anyway — with
|
|
60
|
+
56% of those merges landing within five minutes of the review, or before it.
|
|
61
|
+
|
|
62
|
+
**The structural reason: crosscheck never publishes a merge-blocking signal.** It reads
|
|
63
|
+
commit statuses and check-runs (`client.ts:555`, `client.ts:684`) but creates neither.
|
|
64
|
+
Its entire output is a comment. Branch protection requires:
|
|
65
|
+
|
|
66
|
+
| Branch | Required checks |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `staging` | `PR size, template, and reviewability`, `ci-gate` |
|
|
69
|
+
| `main` | + `release-guard`, 1 approving review |
|
|
70
|
+
|
|
71
|
+
Crosscheck appears in neither list, so GitHub merges the moment `ci-gate` goes green.
|
|
72
|
+
Nothing stops a merge at minute four. (`enforce_admins` is `false` on both branches, so
|
|
73
|
+
even a required check would be admin-bypassable.)
|
|
74
|
+
|
|
75
|
+
Two distinct failure modes follow, and they need different fixes:
|
|
76
|
+
|
|
77
|
+
1. **The fast majority — no gate.** Merging before the review lands is undisciplined
|
|
78
|
+
practice, not a considered trade-off. No improvement to review quality, latency, or
|
|
79
|
+
phrasing changes it, because the review is not part of the merge decision at all.
|
|
80
|
+
Only a gate does.
|
|
81
|
+
2. **The slow tail — no terminal state.** Findings never stop arriving (§3), so the
|
|
82
|
+
loop is an open-ended commitment. This is what makes the process intolerable *once
|
|
83
|
+
authors are forced to engage with it*.
|
|
84
|
+
|
|
85
|
+
These compose in a specific order. **Gating without first bounding the loop would be
|
|
86
|
+
actively harmful** — it converts "merged past findings in 4 minutes" into "blocked for
|
|
87
|
+
51 hours," which is the opposite of the goal. Bound the loop first, then gate, then
|
|
88
|
+
optimize latency.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 1. Methodology
|
|
93
|
+
|
|
94
|
+
| Input | What it gives | Confidence |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| **A.** Census of all 400 merged PRs | Population-scale cost and outcome | High |
|
|
97
|
+
| **B.** 40 BLOCK findings read against the cited code | Whether findings are real | High — hand-labelled |
|
|
98
|
+
| **C.** Local run logs (43 runs) | Tokens + wall-clock per step | High — measured |
|
|
99
|
+
| **D.** Vendor catalogs + live CLI probe | Price, effort, what actually runs | High — primary |
|
|
100
|
+
| **E.** SWE-bench, CR-Bench | Relative capability by task shape | Medium — see §5 |
|
|
101
|
+
|
|
102
|
+
Two earlier approaches were abandoned, recorded here so they are not re-derived:
|
|
103
|
+
|
|
104
|
+
- **Sampling 30 PRs and fitting a complexity score to agent-call count.** Circular:
|
|
105
|
+
call count is set by whether the loop converged, which is a property of the reviewer
|
|
106
|
+
configuration, not the PR. The census replaces it.
|
|
107
|
+
- **`breadth = dirs × languages` as a complexity metric.** Scored a perfect AUC on the
|
|
108
|
+
30-PR sample; the census falsifies it outright (§4).
|
|
109
|
+
|
|
110
|
+
For the labelling pass, BLOCK findings were extracted from PRs that merged *without*
|
|
111
|
+
reaching APPROVE, deduplicated, sampled 40 (seeded; 20 P1-code / 12 P2-code / 8 docs),
|
|
112
|
+
and each was read against the file it cites at the SHA it was reviewed at.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 2. Finding 1 — the findings are real
|
|
117
|
+
|
|
118
|
+
This was the decisive experiment, and it inverted the design.
|
|
119
|
+
|
|
120
|
+
Of 40 sampled findings: 1 unverifiable (file since deleted), **0 false**. Every
|
|
121
|
+
remaining claim was a true statement about the code it cited.
|
|
122
|
+
|
|
123
|
+
| Label | n | Meaning |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| Real, defect-grade | **33** | Genuine bug, security gap, or documented-convention violation |
|
|
126
|
+
| Real, severity-inflated | 6 | True, but should not have contributed to BLOCK |
|
|
127
|
+
| False | **0** | — |
|
|
128
|
+
| Unverifiable | 1 | Cited file no longer retrievable |
|
|
129
|
+
|
|
130
|
+
Representative confirmed defects, each verified against source:
|
|
131
|
+
|
|
132
|
+
- **#8** — `change_rule_mode` accepts an `expected_mode` parameter and never puts it in
|
|
133
|
+
the POST body. Dual-control bypass. Two lines apart in the same function.
|
|
134
|
+
- **#6** — `body.get("data")` sits *outside* the `try` that catches JSON errors; a
|
|
135
|
+
non-object response raises an uncaught `AttributeError`.
|
|
136
|
+
- **#10** — `_validated_gate` hard-rejects a gate response missing `profile`, so during
|
|
137
|
+
a normal rolling deploy every enroll returns 503 until both services are upgraded.
|
|
138
|
+
- **#13** — the promote payload sends three fields the receiving `extra="forbid"` model
|
|
139
|
+
no longer defines: every promotion and rollback 422s. Feature entirely broken.
|
|
140
|
+
- **#26** — `min_a2_shared_wrong` bounded at `_Bound(int, 0)` while its sibling and the
|
|
141
|
+
request contract require ≥ 1.
|
|
142
|
+
- **#4** — migration named `20260820000000`. `docs/architecture/database-conventions.md`
|
|
143
|
+
says verbatim: *"**Never hand-write a round-number timestamp**"*, and documents a
|
|
144
|
+
prior silent-skip incident. The reviewer cited the correct line range.
|
|
145
|
+
|
|
146
|
+
The reviews also demonstrate project-specific reasoning that a generic linter cannot
|
|
147
|
+
do: they read repo convention docs, cross-reference design ADRs, and trace call paths
|
|
148
|
+
across services.
|
|
149
|
+
|
|
150
|
+
**The six severity-inflated cases are the real defect in the output**, not the
|
|
151
|
+
findings themselves: a webhook-secret hardening that requires operator misconfiguration
|
|
152
|
+
to exploit (#2), a request for validation stricter than the contract claims (#3), and
|
|
153
|
+
screenshot binaries committed to a feature branch (#20) — a process violation, correctly
|
|
154
|
+
identified, that should never gate a merge.
|
|
155
|
+
|
|
156
|
+
> **Calibration note.** CR-Bench reports 3.6–5.1% precision for review agents (§5).
|
|
157
|
+
> This system measures ~85% defect-grade. The gap is real and worth naming: CR-Bench
|
|
158
|
+
> scores against a fixed ground-truth defect list, penalizing any finding outside it,
|
|
159
|
+
> whereas this labelling asked "is the claim true and worth fixing." Those measure
|
|
160
|
+
> different things. The operational conclusion stands regardless — **do not tune this
|
|
161
|
+
> system as though its output were noise.**
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 3. Finding 2 — the loop cannot converge, by construction
|
|
166
|
+
|
|
167
|
+
Findings per review pass, across the census:
|
|
168
|
+
|
|
169
|
+
| Pass # | Passes | Mean findings | Total |
|
|
170
|
+
|---|---|---|---|
|
|
171
|
+
| 1 | 198 | 2.0 | 391 |
|
|
172
|
+
| 2 | 90 | 2.5 | 221 |
|
|
173
|
+
| 3 | 46 | 2.5 | 117 |
|
|
174
|
+
| 4 | 32 | **3.3** | 105 |
|
|
175
|
+
| 5 | 23 | **3.7** | 86 |
|
|
176
|
+
| 6+ | 94 | 2.3 | 216 |
|
|
177
|
+
|
|
178
|
+
**Later passes find more, not fewer.** And the findings do not repeat: across 684 raw
|
|
179
|
+
findings there are 676 distinct ones — a dedup ratio of **1.0**. Nothing recurs.
|
|
180
|
+
|
|
181
|
+
So the fixer *is* fixing (issues do not come back), and each pass mines a fresh seam.
|
|
182
|
+
Two sampled findings are regressions introduced by the *previous* round's fix:
|
|
183
|
+
|
|
184
|
+
- **#15 → #19** — round N flags a dual-control TOCTOU; the fix adds
|
|
185
|
+
`expected_mode=current_mode`; round N+1 correctly observes that this now 409s every
|
|
186
|
+
legitimate retry.
|
|
187
|
+
- **#32 → #33** — round N flags two data streams missing from a legal retention table;
|
|
188
|
+
the fix adds them but describes the device ID as `raw`, contradicting the ADR that
|
|
189
|
+
requires `key_version:HMAC`. Round N+1 catches it.
|
|
190
|
+
|
|
191
|
+
This is legitimate, valuable work. It is also **an unbounded process**: there is no
|
|
192
|
+
round at which the supply is exhausted, so "iterate until APPROVE" has no terminal
|
|
193
|
+
state. PR #1998 ran 12 recheck rounds — 26 agent calls, 4.6 hours — and merged unresolved.
|
|
194
|
+
|
|
195
|
+
The remedy is therefore not a better fixer or a stronger recheck model. It is to
|
|
196
|
+
**stop treating APPROVE as the exit condition** and bound the process explicitly.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 4. Finding 3 — crosscheck is racing the merge, and the race is tight
|
|
201
|
+
|
|
202
|
+
Across the 122 PRs that merged unresolved, time from the **last** review comment to
|
|
203
|
+
merge:
|
|
204
|
+
|
|
205
|
+
| | Share |
|
|
206
|
+
|---|---|
|
|
207
|
+
| Review landed *after* the merge — too late entirely | 12% |
|
|
208
|
+
| Merged within 5 minutes of the review | **44%** |
|
|
209
|
+
| Merged 5–60 minutes after | 25% |
|
|
210
|
+
| Merged > 1 hour after (saw it, chose to ship) | 18% |
|
|
211
|
+
|
|
212
|
+
Median: **4 minutes**. Only ~18% of unresolved merges look like a considered decision.
|
|
213
|
+
|
|
214
|
+
The elapsed-time hypothesis — that authors bail because loops run too long — is **true
|
|
215
|
+
in the tail and insufficient on its own**. Convergence is flat at 33–41% across every
|
|
216
|
+
span and round bucket, including the 108 single-round PRs that resolved in a median of
|
|
217
|
+
11 minutes. Long loops do not predict merging unresolved; the behavior is uniform.
|
|
218
|
+
|
|
219
|
+
The uniformity is the tell. If authors were weighing findings, the rate would vary with
|
|
220
|
+
how painful the PR was. It does not vary at all — which is what an **absent gate** looks
|
|
221
|
+
like (§0). The fast majority is not a considered trade-off; it is merging that nothing
|
|
222
|
+
prevents. The tail is a separate problem: those PRs have the *highest* rate of reviews
|
|
223
|
+
landing after merge (20%) and a median span of **51 hours**, which is what makes the
|
|
224
|
+
loop intolerable once a gate forces engagement.
|
|
225
|
+
|
|
226
|
+
The window is genuinely tight. First review lands at a median of 6 minutes; merge at 11
|
|
227
|
+
minutes for single-round PRs and 36 overall. At p25, merge happens at 9 minutes against
|
|
228
|
+
a p25 review at 5. **For a large share of PRs the usable window is single-digit
|
|
229
|
+
minutes** — which makes time-to-first-review a first-class design constraint, not a
|
|
230
|
+
nice-to-have.
|
|
231
|
+
|
|
232
|
+
### Static prediction is weak
|
|
233
|
+
|
|
234
|
+
**Static complexity does not predict cost.** Spearman vs agent-call count across all 199
|
|
235
|
+
engaged PRs: churn 0.513, files 0.428, churn/files 0.321. The distributions overlap
|
|
236
|
+
severely — the largest one-call PR was **101,118 lines**; the smallest 7+-call PR was
|
|
237
|
+
**103**; and the single most expensive PR in the census (#1998, 26 calls) changed
|
|
238
|
+
**2 files**.
|
|
239
|
+
|
|
240
|
+
Conclusion: static features can answer only *"is this trivially safe to start cheap?"*
|
|
241
|
+
They set a floor. They cannot identify the hard PRs in advance, so they must never set
|
|
242
|
+
the ceiling.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 5. Finding 4 — model selection is currently inert
|
|
247
|
+
|
|
248
|
+
Three breaks in one path, all of which must be fixed before any tiering policy can have
|
|
249
|
+
an effect.
|
|
250
|
+
|
|
251
|
+
**a. The Claude override bypasses tiers.** `vendors.claude.model: sonnet` wins over the
|
|
252
|
+
tier table, so all 43 logged runs were `claude-sonnet-5` regardless of `quality.tier`.
|
|
253
|
+
|
|
254
|
+
**b. The Codex model is silently discarded.**
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
export function resolveCodexModel(quality, vendor): string {
|
|
258
|
+
if (vendor.auth !== 'api-key') return 'default' // ← drops the configured model
|
|
259
|
+
...
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The config sets `vendors.codex.model: gpt-5.6-sol` with `auth: subscription`, so it
|
|
264
|
+
never reaches the CLI. **148 of 199 engaged PRs and 482 of 597 calls (81%) ran on
|
|
265
|
+
`model=default`.** A live probe contradicts the guard's rationale: `codex -m/--model`
|
|
266
|
+
is a top-level flag and the CLI accepted it under subscription auth.
|
|
267
|
+
|
|
268
|
+
**c. The installed CLI is too old for the configured model.** The same probe returned
|
|
269
|
+
`The 'gpt-5.6-terra' model requires a newer version of Codex.` Installed
|
|
270
|
+
`codex-cli 0.141.0`; npm latest `0.147.0`. That error text is exactly what
|
|
271
|
+
`isVendorUnavailableError` matches, so smart-switch has been silently absorbing it.
|
|
272
|
+
|
|
273
|
+
Outcomes by first model:
|
|
274
|
+
|
|
275
|
+
| First model | PRs | Calls | Merged without APPROVE |
|
|
276
|
+
|---|---|---|---|
|
|
277
|
+
| `default` | 148 | 482 | **74%** |
|
|
278
|
+
| `claude-opus-5` | 22 | 60 | **5%** |
|
|
279
|
+
| `claude-sonnet-5` | 15 | 19 | 27% |
|
|
280
|
+
| `gpt-5.6-luna` | 6 | 22 | 17% |
|
|
281
|
+
| `gpt-5.6-sol` | 7 | 14 | 86% |
|
|
282
|
+
|
|
283
|
+
> **Confound, stated plainly.** Assignment was not random — it followed origin routing
|
|
284
|
+
> and smart-switch state. `gpt-5.6-sol`'s 86% is the clearest artifact: n=7, used as an
|
|
285
|
+
> *escalation target* on already-stuck PRs. The same bias inflates part of the `default`
|
|
286
|
+
> column. But `default` spans 148 PRs, and 74%-vs-5% is wider than selection alone
|
|
287
|
+
> plausibly explains.
|
|
288
|
+
|
|
289
|
+
### Price and capability
|
|
290
|
+
|
|
291
|
+
| Model | In | Out | Cost @ 48k out | Effort |
|
|
292
|
+
|---|---|---|---|---|
|
|
293
|
+
| `claude-fable-5` | $10 | $50 | $2.40 | low→max |
|
|
294
|
+
| `claude-opus-5` | $5 | $25 | $1.20 | low→max |
|
|
295
|
+
| `claude-sonnet-5` | $3 | $15 | $0.72 | low→max |
|
|
296
|
+
| `claude-haiku-4-5` | $1 | $5 | $0.24 | **none** |
|
|
297
|
+
| `gpt-5.6-sol` | $5 | $30 | $1.44 | none→max |
|
|
298
|
+
| `gpt-5.6-terra` | $2 | $12 | $0.58 | none→max |
|
|
299
|
+
| `gpt-5.6-luna` | $0.20 | $1.20 | **$0.058** | none→max |
|
|
300
|
+
|
|
301
|
+
SWE-bench Verified (one leaderboard, refreshed 2026-08-06, consistent within the Claude
|
|
302
|
+
family): Opus 5 **96.0%**, Fable 5 95.0%, Sonnet 5 **85.2%**, Haiku 4.5 **73.3%**.
|
|
303
|
+
Cross-family figures (Sol ~96.2%, Luna ~93%) come from a *different* aggregator and are
|
|
304
|
+
directional only.
|
|
305
|
+
|
|
306
|
+
Measured step costs (43 runs): review 643 s / 48.0k output tokens; **recheck 663 s /
|
|
307
|
+
48.9k — the same as a full review**; fix 409 s; conflict-resolve **37 s**.
|
|
308
|
+
|
|
309
|
+
Anthropic's effort guidance supports varying effort per call, with the constraint that
|
|
310
|
+
it must be constant *within* a cached conversation. Note Haiku 4.5 has no effort
|
|
311
|
+
parameter at all.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## 6. Design
|
|
316
|
+
|
|
317
|
+
Everything follows from §0: maximize actioned findings inside the merge window.
|
|
318
|
+
|
|
319
|
+
### 6.1 Front-load capability into pass 1 — against a latency budget
|
|
320
|
+
|
|
321
|
+
Pass 1 is the only pass reliably read before merge, and later passes find *more*
|
|
322
|
+
defects, not fewer (§3). So capability spent on pass 1 converts to action; capability
|
|
323
|
+
spent on pass 7 mostly does not.
|
|
324
|
+
|
|
325
|
+
But capability costs time, and §4 shows the window is often single-digit minutes. **This
|
|
326
|
+
tension is the actual case for dynamic thoroughness** — and it is the one justification
|
|
327
|
+
that survives the census. It is not cost. A review that is 10 points better on SWE-bench
|
|
328
|
+
and arrives after the merge scores zero.
|
|
329
|
+
|
|
330
|
+
So the tier is chosen against a **latency budget derived from expected merge speed**,
|
|
331
|
+
not from predicted difficulty:
|
|
332
|
+
|
|
333
|
+
| PR class | Expected merge | Budget | Tier |
|
|
334
|
+
|---|---|---|---|
|
|
335
|
+
| Trivial (§6.5) | ~9–11 min | **< 3 min** | `fast` — latency-driven, not cost-driven |
|
|
336
|
+
| Standard | ~36 min | < 10 min | `balanced` + `xhigh` |
|
|
337
|
+
| Risky / `risk:T3` | hours | < 20 min | `thorough` |
|
|
338
|
+
|
|
339
|
+
This is why the `fast` tier earns its place: on a PR that merges in nine minutes, Haiku
|
|
340
|
+
at 73.3% delivered in two minutes beats Opus at 96.0% delivered in twelve. The 12% of
|
|
341
|
+
reviews that currently land after merge are pure waste at any capability level.
|
|
342
|
+
|
|
343
|
+
- **Pin the models** (§5). Drop the `auth !== 'api-key'` guard; honor a configured model
|
|
344
|
+
under either auth, as `resolveClaudeModel` already does. Require `codex >= 0.147.0`
|
|
345
|
+
when a `gpt-5.6-*` model is set, and fail loudly at startup.
|
|
346
|
+
- **Refresh `review-model-tiers.json`.** `thorough` currently pins `claude-opus-4-8`,
|
|
347
|
+
now legacy; `claude-opus-5` supersedes it at the identical $5/$25 and scores 96.0% vs
|
|
348
|
+
88.6%. Free upgrade, ship independently.
|
|
349
|
+
- **Raise the pass-1 floor to `balanced`, and use `xhigh` effort.** Effort is the cheap
|
|
350
|
+
lever: Sonnet 5 at `xhigh` costs the same per token as at `medium` and merely spends
|
|
351
|
+
more of them, where Sonnet→Opus is a flat 1.67× on every token.
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"claude": { "fast": "claude-haiku-4-5-20251001",
|
|
356
|
+
"balanced": "claude-sonnet-5",
|
|
357
|
+
"thorough": "claude-opus-5" },
|
|
358
|
+
"codex_api": { "fast": "gpt-5.6-luna",
|
|
359
|
+
"balanced": "gpt-5.6-terra",
|
|
360
|
+
"thorough": "gpt-5.6-sol" }
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
No `frontier` tier for `claude-fable-5`: 2× Opus 5's output price for a *lower*
|
|
365
|
+
SWE-bench score.
|
|
366
|
+
|
|
367
|
+
### 6.2 Make the terminal state visible — the closing contract
|
|
368
|
+
|
|
369
|
+
The exit condition changes from "APPROVE" to "**the blocking set is closed**," and —
|
|
370
|
+
critically — **pass 1 must say so in the comment.**
|
|
371
|
+
|
|
372
|
+
Authors merge past findings because entering the loop is an open-ended commitment (§0).
|
|
373
|
+
Bounding the set internally does not fix that; the author cannot see the bound. The
|
|
374
|
+
first review has to carry the promise explicitly:
|
|
375
|
+
|
|
376
|
+
> **3 blocking issues. This is the complete blocking set — later rounds will not add to
|
|
377
|
+
> it.** 7 further observations are advisory and do not gate this PR.
|
|
378
|
+
|
|
379
|
+
That sentence is the whole intervention. It converts an open-ended commitment into a
|
|
380
|
+
bounded one, which is the difference between a decision an author can make in the merge
|
|
381
|
+
window and one they resolve by merging.
|
|
382
|
+
|
|
383
|
+
It also has to be *true*, which constrains the implementation:
|
|
384
|
+
|
|
385
|
+
- Pass 1 emits at most N blocking findings (default 5), ranked; everything else is
|
|
386
|
+
advisory and explicitly non-gating.
|
|
387
|
+
- **Advisory findings never trigger a fix round**, and later rounds may not promote a
|
|
388
|
+
finding into the blocking set. A new defect discovered in round 3 is reported as
|
|
389
|
+
advisory — otherwise the promise breaks and the learned disengagement returns.
|
|
390
|
+
- **Hard cap: 3 fix/recheck rounds, and a wall-clock budget.** Whichever binds first
|
|
391
|
+
ends the loop with a digest and a human assignment. Given §3 the process has no
|
|
392
|
+
natural terminal state, and given §4 the round count is the wrong unit — 7+ round PRs
|
|
393
|
+
span a median of 51 hours.
|
|
394
|
+
|
|
395
|
+
The one real cost: capping the blocking set means some genuine defects ship as advisory.
|
|
396
|
+
Given ~85% precision that is a real loss, and it is the right trade — a bounded set that
|
|
397
|
+
gets acted on beats an unbounded one that gets merged past. The advisory list preserves
|
|
398
|
+
the finding for the author and for follow-up.
|
|
399
|
+
|
|
400
|
+
### 6.3 Tighten severity so BLOCK means something
|
|
401
|
+
|
|
402
|
+
Six of 40 sampled findings were true but should not have gated a merge. BLOCK should
|
|
403
|
+
require a concrete failure path in the changed code: data loss, security boundary,
|
|
404
|
+
broken API contract, or a correctness bug with a reachable trigger. Explicitly **not**
|
|
405
|
+
BLOCK-grade:
|
|
406
|
+
|
|
407
|
+
- repository process and hygiene conventions (#20 — screenshot binaries)
|
|
408
|
+
- hardening that requires operator misconfiguration to exploit (#2)
|
|
409
|
+
- requests for validation beyond what the code's stated contract claims (#3)
|
|
410
|
+
|
|
411
|
+
These stay in the review as advisory. This costs nothing and raises the signal on the
|
|
412
|
+
verdict that gates the pipeline.
|
|
413
|
+
|
|
414
|
+
### 6.4 The ladder — narrow the scope, hold the model, escalate the effort
|
|
415
|
+
|
|
416
|
+
Start strong but not maxed (54% of engaged PRs are one-and-done — maxing every pass 1
|
|
417
|
+
wastes budget on PRs that need one), then escalate on measured non-convergence.
|
|
418
|
+
|
|
419
|
+
| Round | Scope | Model | Effort | Rationale |
|
|
420
|
+
|---|---|---|---|---|
|
|
421
|
+
| **1 · review** | Whole PR | `balanced`, or `thorough` for risk classes (§6.5) | `medium` | Only pass reliably read. Sets the blocking set. |
|
|
422
|
+
| **· fix** | The N blocking items | **same as review** | `medium` | See below — cheap fixes cost a whole round. |
|
|
423
|
+
| **2 · recheck** | Delta + open items only | **same as review** | `high` | Narrower task, not a weaker judge. |
|
|
424
|
+
| **3 · recheck** | Delta + open items | same | `xhigh` | Non-convergence *is* the difficulty signal. |
|
|
425
|
+
| **4+** | — | — | — | Stop. Digest + human (§6.2). |
|
|
426
|
+
|
|
427
|
+
**Should review get cheaper over rounds? Yes — but by narrowing scope, never by
|
|
428
|
+
weakening the model.** The two levers look similar on a cost report and are opposite in
|
|
429
|
+
effect:
|
|
430
|
+
|
|
431
|
+
- *Scope* legitimately shrinks. Round 1 reads the whole PR; round N only has to check N
|
|
432
|
+
known items against the delta. Today recheck costs the same as a full review (663 s
|
|
433
|
+
vs 643 s, 48.9k vs 48.0k tokens) **because it re-reviews everything** — that is
|
|
434
|
+
waste, and scoping it is a real saving that the closing contract (§6.2) already
|
|
435
|
+
implies, since later rounds may not add blocking findings anyway.
|
|
436
|
+
- *Model* must not weaken. CR-Bench shows weak models degrade fastest under iteration —
|
|
437
|
+
GPT-5-mini's SNR fell to 0.91, below 1, more noise than signal. Recheck is the call
|
|
438
|
+
that decides whether to spend another round; a weak judge there is how loops become
|
|
439
|
+
unbounded.
|
|
440
|
+
|
|
441
|
+
So the per-round cost curve falls because the **input shrinks**, while capability holds
|
|
442
|
+
and effort rises. That is the opposite of the intuitive "reviews are expensive, make
|
|
443
|
+
rechecks cheap," which optimizes the one call where cheapness is most damaging.
|
|
444
|
+
|
|
445
|
+
**On making `fix` cheaper:** it is the safest step to cheapen — generation against an
|
|
446
|
+
explicit list is the task models are strongest at (SWE-bench-shaped), unlike detection.
|
|
447
|
+
But the census argues for restraint. Two of 40 sampled findings are regressions
|
|
448
|
+
*introduced by a previous round's fix* (#15→#19, #32→#33), and each cost a full extra
|
|
449
|
+
round at ~10.7 minutes. Against that, a stronger fixer costs ~1.67× on a single call.
|
|
450
|
+
**Hold the model, drop effort one notch** — cheaper tokens without buying new defects.
|
|
451
|
+
A tier drop is defensible only for mechanical fix steps on trivial PRs.
|
|
452
|
+
|
|
453
|
+
### 6.5 The strategy table
|
|
454
|
+
|
|
455
|
+
Encoded in [`src/config/review-strategy.json`](../src/config/review-strategy.json), which
|
|
456
|
+
follows the pattern `review-model-tiers.json` already established: an `updated` date,
|
|
457
|
+
`sources` with verifiable `checks` strings, and a `review_interval_days` so drift is
|
|
458
|
+
detectable rather than silent (§6.6).
|
|
459
|
+
|
|
460
|
+
**Vendor tiers.** Cost is per 48k-output call, the census median.
|
|
461
|
+
|
|
462
|
+
| Tier | Claude | $/call | SWE-b | Codex | $/call | Effort |
|
|
463
|
+
|---|---|---|---|---|---|---|
|
|
464
|
+
| `fast` | `claude-haiku-4-5` | $0.240 | 73.3% | `gpt-5.6-luna` | **$0.058** | Claude: **none** · Codex: all |
|
|
465
|
+
| `balanced` | `claude-sonnet-5` | $0.720 | 85.2% | `gpt-5.6-terra` | $0.576 | both: all |
|
|
466
|
+
| `thorough` | `claude-opus-5` | $1.200 | 96.0% | `gpt-5.6-sol` | $1.440 | both: all |
|
|
467
|
+
|
|
468
|
+
*Claude strengths:* highest measured capability at `thorough`, most recent knowledge
|
|
469
|
+
cutoff (May 2026). *Weakness:* the `fast` tier has no effort parameter and only a 200k
|
|
470
|
+
context. *Codex strengths:* `fast` is 4× cheaper than Haiku on output, effort available
|
|
471
|
+
at every tier, 1.05M context throughout. *Weakness:* cross-family benchmarks are not
|
|
472
|
+
comparable — validate locally before assuming tier parity.
|
|
473
|
+
|
|
474
|
+
**`claude-fable-5` is banned from code review** (`banned_models` in the strategy file,
|
|
475
|
+
enforced by `verify:strategy`). At $50/MTok output it is 2× `claude-opus-5` for a
|
|
476
|
+
*lower* SWE-bench Verified score — $2.40 per call at the measured 48k output tokens,
|
|
477
|
+
with no capability justification at any tier.
|
|
478
|
+
|
|
479
|
+
### The second axis: domain
|
|
480
|
+
|
|
481
|
+
Capability is domain-shaped, not scalar, and a single tier ladder cannot express that.
|
|
482
|
+
SWE-bench Verified resolves issues in *Python* repositories; in this census **42% of
|
|
483
|
+
reviewed PRs are frontend-dominant and 55% touch frontend at all**. On the domain that
|
|
484
|
+
carries most of the workload the ordering inverts:
|
|
485
|
+
|
|
486
|
+
| Frontend Code Arena (Elo, blind pairwise) | | SWE-bench Verified | |
|
|
487
|
+
|---|---|---|---|
|
|
488
|
+
| **Kimi K3** *(open)* | **1679** | **Claude Opus 5** | **96.0** |
|
|
489
|
+
| Claude Fable 5 | 1631 | Claude Sonnet 5 | 85.2 |
|
|
490
|
+
| GPT-5.6 Sol | 1618 | DeepSeek V4 Pro *(open)* | 80.6 |
|
|
491
|
+
| GLM-5.2 *(open)* | 1587 | DeepSeek V4 Flash *(open)* | 79.0 |
|
|
492
|
+
| Claude Opus 4.8 | 1562 | GLM-5 *(open)* | 77.8 |
|
|
493
|
+
| Grok-4.5 | 1558 | Claude Haiku 4.5 | 73.3 |
|
|
494
|
+
|
|
495
|
+
The most capable frontend model available is open-weight, and it is a different model
|
|
496
|
+
from the backend leader. Hence `domains` in the strategy file: `frontend` prefers
|
|
497
|
+
`kimi-k3` → `gpt-5.6-sol` → `claude-opus-5` at `thorough`; `backend` prefers
|
|
498
|
+
`claude-opus-5` → `gpt-5.6-sol`. `mixed` and `unknown` fall back to `backend`.
|
|
499
|
+
|
|
500
|
+
> **Confidence: hypothesis, marked as such in the JSON.** Arena measures blind human
|
|
501
|
+
> preference on *generated* frontend output — a generation task, where review is
|
|
502
|
+
> detection. The same asymmetry that limits SWE-bench applies. And **Claude Opus 5 is
|
|
503
|
+
> absent from the retrieved frontend leaderboard** (only Opus 4.8 at 1562) — a missing
|
|
504
|
+
> measurement, not a low score. The backend row is `measured`; the frontend row needs a
|
|
505
|
+
> local A/B before it should be trusted over the default.
|
|
506
|
+
|
|
507
|
+
**PR classes.** First match wins, so ordering is the routing logic.
|
|
508
|
+
|
|
509
|
+
| # | Class | Detection | Tier | Effort | Steps |
|
|
510
|
+
|---|---|---|---|---|---|
|
|
511
|
+
| 1 | Generated / vendored only | every file is a lockfile, build output, or generated stub | — | — | **skip** |
|
|
512
|
+
| 2 | **Security / data-critical** | risky path, `risk:T3`, or hotfix→default branch | `thorough` | high | review, fix, recheck |
|
|
513
|
+
| 3 | Deletion-only | ≤ 5 additions with ≥ 20 deletions | `fast` | medium | review |
|
|
514
|
+
| 4 | Documentation / specification | ≥ 50% `.md`/`.rst`/`.adoc` | `balanced` | high | review |
|
|
515
|
+
| 5 | Test-only | every file is a test or fixture | `fast` | medium | review, fix |
|
|
516
|
+
| 6 | Config / infrastructure | ≥ 50% config, no source files | `balanced` | high | review, fix, recheck |
|
|
517
|
+
| 7 | Trivial | ≤ 3 files and ≤ 150 source churn | `fast` | medium | review, fix |
|
|
518
|
+
| 8 | Standard code | fallthrough | `balanced` | medium | review, fix, recheck |
|
|
519
|
+
|
|
520
|
+
Three classes carry reasoning that is not obvious from the row:
|
|
521
|
+
|
|
522
|
+
- **Deletion-only** is not "small, therefore cheap." Its risk is *reference breakage* —
|
|
523
|
+
dangling imports, call sites, route registrations, docs pointing at removed symbols —
|
|
524
|
+
which is a narrow lookup task, not defect detection. And it gets no fix loop: a wrong
|
|
525
|
+
deletion is reverted, not patched.
|
|
526
|
+
- **Docs is review-only.** Census: docs PRs converge worst (mean 4.1 calls vs 3.0), and
|
|
527
|
+
#1998 — the most expensive PR in the census at 26 calls — was two markdown files. The
|
|
528
|
+
findings were real, but they were *design negotiation*, which no automated loop
|
|
529
|
+
terminates. Removing the fix/recheck loop for this class is the single largest tail
|
|
530
|
+
saving available.
|
|
531
|
+
- **Security is the only promotion rule**, applied because a missed defect there is
|
|
532
|
+
expensive — *not* because those PRs are predicted to be hard. §4 shows static features
|
|
533
|
+
cannot predict difficulty.
|
|
534
|
+
|
|
535
|
+
**Mode.**
|
|
536
|
+
|
|
537
|
+
| | Cross-vendor | Single-vendor |
|
|
538
|
+
|---|---|---|
|
|
539
|
+
| Strength | Independent second perspective | One CLI to auth, version, monitor |
|
|
540
|
+
| Round-3 lever | **switch vendor + raise effort** | raise effort, then promote one tier |
|
|
541
|
+
| Cost | both CLIs must stay current | loses the deadlock-breaker |
|
|
542
|
+
| `max_rounds` | 3 | **2** |
|
|
543
|
+
|
|
544
|
+
Cross-vendor's specific value is empirical: a vendor switch broke a stalled loop twice
|
|
545
|
+
in the census (#2057, #2060) *after* same-vendor escalation had failed for 3–6 rounds.
|
|
546
|
+
Single-vendor has no equivalent move, so it should cap rounds more aggressively rather
|
|
547
|
+
than grind.
|
|
548
|
+
|
|
549
|
+
### 6.6 Citing the strategy in every review
|
|
550
|
+
|
|
551
|
+
A review is only auditable if it says what policy produced it. Every crosscheck comment
|
|
552
|
+
carries the strategy version, the PR class that was matched, and the tier that class
|
|
553
|
+
selected — in both the machine annotation and the human-readable line.
|
|
554
|
+
|
|
555
|
+
```
|
|
556
|
+
<!-- crosscheck: origin=claude reviewer=claude model=claude-opus-5 type=review
|
|
557
|
+
round=1 verdict=BLOCK strategy=1.1.0 class=risky tier=thorough
|
|
558
|
+
service=crosscheck sha=abc123 -->
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
> _Reviewed with [Claude Code](https://claude.ai/code) via [Crosscheck](https://github.com/humanbased-ai/crosscheck)
|
|
562
|
+
> with Opus 5 (high) — thorough tier · touches a security or data-critical path, where a
|
|
563
|
+
> missed defect is expensive · strategy v1.1.0_
|
|
564
|
+
|
|
565
|
+
The rationale text is not written per review — it is the matched class's `reason` field,
|
|
566
|
+
so the explanation and the routing decision cannot drift apart. `strategy`, `class`, and
|
|
567
|
+
`tier` are **additive** annotation fields: per the annotation contract in `CLAUDE.md`,
|
|
568
|
+
parsers already tolerate unknown fields, so this is a minor version bump, not a breaking
|
|
569
|
+
change.
|
|
570
|
+
|
|
571
|
+
This is what makes a past review explicable. A BLOCK from six weeks ago was produced by
|
|
572
|
+
whatever policy was current then; without the version stamp, re-reading it under today's
|
|
573
|
+
policy is a guess.
|
|
574
|
+
|
|
575
|
+
### 6.7 Keeping the table current
|
|
576
|
+
|
|
577
|
+
The table is a perishable asset — `review-model-tiers.json` already went stale, pinning
|
|
578
|
+
`thorough` to `claude-opus-4-8` after `claude-opus-5` superseded it at the same price
|
|
579
|
+
and +7.4 points. That is a free capability loss, and it happened silently.
|
|
580
|
+
|
|
581
|
+
Staleness is now loud, by machine:
|
|
582
|
+
|
|
583
|
+
1. **`npm run verify:strategy`** ([`scripts/verify-review-strategy.mjs`](../scripts/verify-review-strategy.mjs))
|
|
584
|
+
checks three things — internal consistency (every routed model exists; no banned
|
|
585
|
+
model is routed; every class carries a citable reason), freshness against
|
|
586
|
+
`review_interval_days`, and source drift (each `sources[].checks` string still
|
|
587
|
+
appears on the live page).
|
|
588
|
+
2. **The `Review Strategy` workflow** ([`.github/workflows/review-strategy.yml`](../.github/workflows/review-strategy.yml))
|
|
589
|
+
runs it on every PR touching the strategy, and weekly on a schedule. A scheduled
|
|
590
|
+
failure opens a `strategy-drift` issue with the report and the remediation steps —
|
|
591
|
+
it deliberately does *not* auto-edit the file, because model choice is a judgement
|
|
592
|
+
backed by benchmarks a human has to read.
|
|
593
|
+
3. **Fail loudly on model rejection.** The `gpt-5.6-terra` 400 (`requires a newer
|
|
594
|
+
version of Codex`) was silently absorbed by smart-switch, so the operator never
|
|
595
|
+
learned their configured model was dead. Version and model errors should surface as
|
|
596
|
+
configuration errors, not degrade quietly.
|
|
597
|
+
4. **`min_cli_version` per vendor**, checked at startup when a model needs it.
|
|
598
|
+
|
|
599
|
+
### 6.8 What classification may and may not decide
|
|
600
|
+
|
|
601
|
+
Every class in §6.5 is computed from the file list alone — no model call, no cost, and
|
|
602
|
+
available before the first review starts.
|
|
603
|
+
|
|
604
|
+
The hard constraint is what classification is *allowed* to conclude. It may:
|
|
605
|
+
|
|
606
|
+
- set the **floor** (`trivial`, `deletion_only`, `test_only` → `fast`)
|
|
607
|
+
- **promote** on consequence, not on predicted difficulty (`risky` → `thorough`)
|
|
608
|
+
- choose the **step set** (`docs` → review-only; `generated` → skip)
|
|
609
|
+
|
|
610
|
+
It may **not** predict that a PR will be hard and pre-emptively assign `thorough` for
|
|
611
|
+
that reason. §4 shows static features cannot support that inference: churn correlates
|
|
612
|
+
only 0.513 with realized cost, the largest one-call PR was 101,118 lines, and the most
|
|
613
|
+
expensive PR in the census changed 2 files. Difficulty is discovered by reviewing, and
|
|
614
|
+
that is what the ladder in §6.4 is for.
|
|
615
|
+
|
|
616
|
+
This is the discipline that keeps the table honest as it grows: new classes may adjust
|
|
617
|
+
the floor or the step set, but escalation stays evidence-driven.
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## 7. Expected effect
|
|
622
|
+
|
|
623
|
+
| Change | Mechanism | Effect on the goal |
|
|
624
|
+
|---|---|---|
|
|
625
|
+
| Bounded set + closing contract (§6.2) | Loop gets a terminal state | Prerequisite for everything else |
|
|
626
|
+
| **Docs → review-only** (§6.5) | Removes the loop from the worst-converging class | Largest single tail saving |
|
|
627
|
+
| Pin models (§5, §6.1) | 148 PRs leave `default` | Unresolved 74% → plausibly ~25% |
|
|
628
|
+
| Cap rounds + wall-clock (§6.2) | 18 PRs truncated to ≤7 calls | **139 of 597 calls removed (-23%)**, verified |
|
|
629
|
+
| Latency budget (§6.1) | Review lands inside the merge window | Recovers the 12% arriving after merge |
|
|
630
|
+
| Severity discipline (§6.3) | ~15% fewer spurious BLOCKs | BLOCK becomes actionable |
|
|
631
|
+
| Skip generated / deletion-only (§6.5) | Removes calls with no defect surface | Pure saving, no quality cost |
|
|
632
|
+
| Publish a check run | Lets a team gate if they choose | Enables adoption; team's decision, not ours |
|
|
633
|
+
|
|
634
|
+
**The gate is what converts every other item here from advisory to load-bearing.** Today
|
|
635
|
+
review latency and review quality are both free variables — nothing downstream consumes
|
|
636
|
+
them. Once `crosscheck/review` is a required check, review latency becomes time-to-merge
|
|
637
|
+
directly, and *that* is what makes dynamic thoroughness a velocity lever rather than a
|
|
638
|
+
cost optimization.
|
|
639
|
+
|
|
640
|
+
Cost moves in both directions — up on pass 1, down hard on the tail — and nets roughly
|
|
641
|
+
flat to modestly lower. **That is the correct trade for this goal.** The call-count
|
|
642
|
+
reduction is the firm number; it follows from the round cap alone.
|
|
643
|
+
|
|
644
|
+
The measurable success criterion is **actioned-finding rate**, not cost: today 38% of
|
|
645
|
+
engaged PRs reach a closed state. Everything above should be judged on whether it moves
|
|
646
|
+
that number.
|
|
647
|
+
|
|
648
|
+
Throughput: #1998 goes from 4.6 hours of reviewer wall-clock, merged unresolved, to
|
|
649
|
+
~1.2 hours with a human handoff carrying a bounded list.
|
|
650
|
+
|
|
651
|
+
Two levers not modelled: `gpt-5.6-luna` at $0.058/call is 4× cheaper than Haiku on
|
|
652
|
+
output and reportedly much stronger — but that number is cross-family, so it needs a
|
|
653
|
+
local A/B, not a config change. And prompt caching cuts cached input 90%.
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## 8. Rollout
|
|
658
|
+
|
|
659
|
+
Scoped to the tool. Whether a team gates on the result, and how they merge, is theirs to
|
|
660
|
+
decide — crosscheck's job is to be correct, bounded, and current by default.
|
|
661
|
+
|
|
662
|
+
**Silent-failure fixes** — pure defects, independent of every open design question:
|
|
663
|
+
|
|
664
|
+
1. **`resolveCodexModel` discards the configured model** under subscription auth (§5).
|
|
665
|
+
Verified: the CLI accepts `--model` under either auth. 81% of census calls ran on an
|
|
666
|
+
unpinned `default` because of this one guard.
|
|
667
|
+
2. **Model/version rejection is absorbed by smart-switch.** The `gpt-5.6-terra` 400 was
|
|
668
|
+
swallowed, so the operator never learned their configured model was dead. Surface
|
|
669
|
+
configuration errors as configuration errors; add `min_cli_version` checks at startup.
|
|
670
|
+
3. **Audit the round cap.** `workflow.yml` sets `max_rounds: 3`; #1998 reached round 12.
|
|
671
|
+
`exceedsMaxRounds` (`runner.ts:184`) exempts a review step coerced to recheck — a
|
|
672
|
+
plausible path, not yet confirmed. No bound holds until this does.
|
|
673
|
+
4. **Refresh the tier table** — `claude-opus-4-8` → `claude-opus-5`, same price, +7.4pts.
|
|
674
|
+
|
|
675
|
+
**Behavior** — needs the fixes above to be measurable:
|
|
676
|
+
|
|
677
|
+
5. **Bound and rank the finding set; state the closing contract** (§6.2); **tighten
|
|
678
|
+
BLOCK** (§6.3). Prompt-level only, reversible in one commit.
|
|
679
|
+
6. **Land the strategy table** (§6.5) in shadow mode — log the class and tier beside the
|
|
680
|
+
realized outcome, change nothing. Start with the three highest-confidence classes:
|
|
681
|
+
`generated` (skip), `deletion_only`, and `docs` (review-only).
|
|
682
|
+
7. **Measure per-tier latency**, then enable the latency budget (§6.1). The fast-lane
|
|
683
|
+
argument depends on numbers not yet measured.
|
|
684
|
+
8. **Enable the ladder** (§6.4) last — highest impact, easiest to get wrong.
|
|
685
|
+
|
|
686
|
+
**New capability** — makes crosscheck adoptable where review must be load-bearing:
|
|
687
|
+
|
|
688
|
+
9. **Publish a `crosscheck/review` check run** — `pending` while reviewing, `success`
|
|
689
|
+
when the blocking set is closed or empty, `failure` when it is not. `client.ts` reads
|
|
690
|
+
check-runs today but creates none, so a team *cannot* gate on crosscheck even if they
|
|
691
|
+
want to. Ship it off by default and let teams opt in.
|
|
692
|
+
|
|
693
|
+
```yaml
|
|
694
|
+
quality:
|
|
695
|
+
tier: balanced
|
|
696
|
+
mode: smart # already in schema.ts; currently inert
|
|
697
|
+
smart:
|
|
698
|
+
shadow: false
|
|
699
|
+
max_blocking: 5 # above this → advisory, never gating
|
|
700
|
+
max_rounds: 3 # hard stop, then hand to a human
|
|
701
|
+
max_wall_clock_min: 60 # whichever binds first ends the loop
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### Open questions
|
|
705
|
+
|
|
706
|
+
- **What block rate would a required check actually produce?** Today 62% of engaged PRs
|
|
707
|
+
end non-APPROVE. Gating naively would block roughly that share — untenable. Step 3's
|
|
708
|
+
unrequired rollout measures the real number after §6.2–6.3 land, and that number
|
|
709
|
+
decides whether gating is viable at all.
|
|
710
|
+
- **Does the closing contract change behavior on its own?** It is the least-proven part
|
|
711
|
+
of the design, and it only matters once a gate forces engagement. Cheapest test: ship
|
|
712
|
+
the bounded-set wording for two weeks and watch the actioned-finding rate.
|
|
713
|
+
- **Should the gate apply to every PR?** A required check on trivial PRs that merge in
|
|
714
|
+
nine minutes may cost more velocity than the defects it catches. Gating only the
|
|
715
|
+
risky-path and `risk:T3` classes (§6.5) is the conservative first cut.
|
|
716
|
+
- **What is the real time-to-first-review at each tier?** The latency budget in §6.1 is
|
|
717
|
+
built on one measured configuration (Sonnet 5, 643 s median). Haiku and Luna
|
|
718
|
+
latencies on real diffs are unmeasured, and the whole fast-lane argument depends on
|
|
719
|
+
them. Measure before committing thresholds.
|
|
720
|
+
- **Does `fast` hold on trivial PRs?** All one-call PRs ran Sonnet 5. Whether Haiku 4.5
|
|
721
|
+
(73.3%) reaches the same verdicts is untested. Replay those diffs at both tiers.
|
|
722
|
+
- **Is `default` causal or a proxy for routing?** Shadow mode with a pinned model on
|
|
723
|
+
unchanged routing settles it.
|
|
724
|
+
- **Should docs PRs enter the fix/recheck loop at all?** They converge worst (#1998).
|
|
725
|
+
Their findings are real but constitute design negotiation. A review-only workflow may
|
|
726
|
+
fit them better.
|
|
727
|
+
- **Should coverage widen?** 201 of 400 merged PRs saw no review at all — an author-scope
|
|
728
|
+
gate. Out of scope here, but it dominates any projection.
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
## Sources
|
|
733
|
+
|
|
734
|
+
- [Anthropic model catalog](https://platform.claude.com/docs/en/about-claude/models/overview) — pricing, legacy status
|
|
735
|
+
- [Anthropic effort parameter](https://platform.claude.com/docs/en/build-with-claude/effort) — levels, guidance, caching constraint
|
|
736
|
+
- [OpenAI model catalog](https://developers.openai.com/api/docs/models) — GPT-5.6 family
|
|
737
|
+
- [CR-Bench](https://arxiv.org/html/2603.11078v1) — review precision/recall/SNR
|
|
738
|
+
- [SWE-bench Verified leaderboard](https://benchlm.ai/benchmarks/sweVerified) — Claude-family scores
|