From c8990a456eccfbddab962ef0d44c4b4579ca66c4 Mon Sep 17 00:00:00 2001 From: Elia <83713217+eliahilse@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:24:58 +0200 Subject: [PATCH 1/3] fix: declare zod and drizzle-orm in @kyora-sh/mcp, pin bun in CI Both were resolving through hoisting locally but fail on the runner's bun linker. CI now runs the same bun as development. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CQy3ZJ5MyUxo4qjZwA93Na --- .github/workflows/ci.yml | 2 +- bun.lock | 2 ++ packages/state/mcp/package.json | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f0a6e6..8611462 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - uses: oven-sh/setup-bun@v2 with: - bun-version: latest + bun-version: 1.3.14 - run: bun install --frozen-lockfile diff --git a/bun.lock b/bun.lock index e2c2687..df6f5b2 100644 --- a/bun.lock +++ b/bun.lock @@ -61,6 +61,8 @@ "@kyora/nora": "workspace:*", "@kyora/sdk": "workspace:*", "@modelcontextprotocol/sdk": "^1.0.0", + "drizzle-orm": "^0.39.0", + "zod": "^4.3.6", }, "devDependencies": { "@repo/typescript-config": "workspace:*", diff --git a/packages/state/mcp/package.json b/packages/state/mcp/package.json index b0be234..8b9cda7 100644 --- a/packages/state/mcp/package.json +++ b/packages/state/mcp/package.json @@ -32,7 +32,9 @@ "@kyora/db": "workspace:*", "@kyora/nora": "workspace:*", "@kyora/sdk": "workspace:*", - "@modelcontextprotocol/sdk": "^1.0.0" + "@modelcontextprotocol/sdk": "^1.0.0", + "drizzle-orm": "^0.39.0", + "zod": "^4.3.6" }, "devDependencies": { "@repo/typescript-config": "workspace:*", From 5806dd3ce96f0fe9589b50a8bfb0413d8204814a Mon Sep 17 00:00:00 2001 From: Elia <83713217+eliahilse@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:28:45 +0200 Subject: [PATCH 2/3] fix: reference bun types via @types/bun instead of transitive bun-types Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CQy3ZJ5MyUxo4qjZwA93Na --- packages/review/cli/tsconfig.json | 2 +- packages/state/db/tsconfig.json | 2 +- packages/state/mcp/tsconfig.json | 2 +- packages/state/nora/tsconfig.json | 2 +- packages/state/sdk/tsconfig.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/review/cli/tsconfig.json b/packages/review/cli/tsconfig.json index 2714e51..17ddc96 100644 --- a/packages/review/cli/tsconfig.json +++ b/packages/review/cli/tsconfig.json @@ -2,7 +2,7 @@ "extends": "@repo/typescript-config/base.json", "compilerOptions": { "noEmit": true, - "types": ["bun-types"], + "types": ["bun"], "module": "ESNext", "moduleResolution": "bundler" }, diff --git a/packages/state/db/tsconfig.json b/packages/state/db/tsconfig.json index 3272a9e..061fc0a 100644 --- a/packages/state/db/tsconfig.json +++ b/packages/state/db/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "dist", "rootDir": "src", - "types": ["bun-types"], + "types": ["bun"], "module": "ESNext", "moduleResolution": "bundler" }, diff --git a/packages/state/mcp/tsconfig.json b/packages/state/mcp/tsconfig.json index 3272a9e..061fc0a 100644 --- a/packages/state/mcp/tsconfig.json +++ b/packages/state/mcp/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "dist", "rootDir": "src", - "types": ["bun-types"], + "types": ["bun"], "module": "ESNext", "moduleResolution": "bundler" }, diff --git a/packages/state/nora/tsconfig.json b/packages/state/nora/tsconfig.json index 3272a9e..061fc0a 100644 --- a/packages/state/nora/tsconfig.json +++ b/packages/state/nora/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "dist", "rootDir": "src", - "types": ["bun-types"], + "types": ["bun"], "module": "ESNext", "moduleResolution": "bundler" }, diff --git a/packages/state/sdk/tsconfig.json b/packages/state/sdk/tsconfig.json index 3272a9e..061fc0a 100644 --- a/packages/state/sdk/tsconfig.json +++ b/packages/state/sdk/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "dist", "rootDir": "src", - "types": ["bun-types"], + "types": ["bun"], "module": "ESNext", "moduleResolution": "bundler" }, From 4c134f872d4647720382183c7e581c7963e3a3f7 Mon Sep 17 00:00:00 2001 From: Elia <83713217+eliahilse@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:52:52 +0200 Subject: [PATCH 3/3] feat: verification probes with CI-aware execution policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Engines can now execute targeted probes (snippet evaluation, single- function checks) to verify findings, while the commands CI already runs are auto-detected from .github/workflows and declared off-limits — re-running suites the runner executes anyway is pure compute waste. Claude/kimi get Bash with deny rules for suites, builds, installs, writes, and history-mutating git; codex keeps its read-only sandbox. Also restores the TOC README from #2, which was stranded on feat/review-framework because #1 squash-merged before #2 landed, and ignores generated app artifacts at the root. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CQy3ZJ5MyUxo4qjZwA93Na --- .gitignore | 5 ++ README.md | 139 ++++++++++++++++++++++++++--- action/README.md | 2 +- packages/review/cli/README.md | 2 +- packages/review/cli/src/ci.test.ts | 47 ++++++++++ packages/review/cli/src/ci.ts | 47 ++++++++++ packages/review/cli/src/engines.ts | 15 +++- packages/review/cli/src/index.ts | 5 +- packages/review/cli/src/schema.ts | 13 ++- 9 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 packages/review/cli/src/ci.test.ts create mode 100644 packages/review/cli/src/ci.ts diff --git a/.gitignore b/.gitignore index e3db48b..c07b0ad 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,8 @@ yarn-error.log* # Kyora data .kyora + +# generated app artifacts +.source/ +next-env.d.ts +*.tsbuildinfo diff --git a/README.md b/README.md index 5d7947e..525c25e 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,37 @@ Tools that make coding agents trustworthy — by grounding them in what actually happens: at runtime, and in review. -Two products, one repo: +[kyora.sh](https://kyora.sh) -## kyora state — queryable temporal runtime state +## Contents -Records state mutations, function calls, HTTP traffic, and errors over time, then exposes it all via MCP so agents can query what actually happened at runtime. Also indexes dependencies and docs semantically, minimizing hallucinations. +- [kyora state — queryable temporal runtime state](#kyora-state) + - [Quick start](#quick-start) + - [Instrumentation](#instrumentation) + - [Auto-instrumentation (Bun plugin)](#auto-instrumentation-bun-plugin) + - [MCP tools](#mcp-tools) +- [kyora review — multi-engine code review](#kyora-review) + - [Quick start](#quick-start-1) + - [How findings are ranked](#how-findings-are-ranked) + - [Engines](#engines) + - [CI](#ci) + - [Configuration](#configuration) +- [Repo layout](#repo-layout) +- [Development](#development) +- [License](#license) + +## kyora state + +Queryable temporal runtime state for coding agents. Records state mutations, function calls, HTTP traffic, and errors over time, then exposes it all via MCP so agents can query what actually happened at runtime — instead of guessing from source. Also indexes dependencies and docs semantically, minimizing hallucinations. + +### Quick start ```bash bunx @kyora-sh/mcp ``` +Add to `.claude/settings.json`: + ```json { "mcpServers": { @@ -24,20 +45,118 @@ bunx @kyora-sh/mcp } ``` -Instrument with `@kyora/sdk` (`watch`, `trace`, auto-patching of fetch/console/errors, Bun plugin for annotation-driven instrumentation) and query it back through MCP tools (`kyora_query_state`, `kyora_get_recent_errors`, `kyora_get_http_log`, semantic doc search). Full docs: [`packages/state`](packages/state). +### Instrumentation + +```ts +import { init, watch, trace } from "@kyora/sdk" + +init({ dataDir: ".kyora" }) + +// track state over time +const cart = watch({ items: [], total: 0 }, "cart") +cart.items.push({ name: "Widget", price: 9.99 }) + +// record function calls (args, return values, errors, timing) +const fetchUsers = trace(async function fetchUsers() { + return (await fetch("/api/users")).json() +}, "fetchUsers") +``` + +`init()` automatically patches `fetch`, `console`, and error handlers. + +### Auto-instrumentation (Bun plugin) + +```toml +# bunfig.toml +preload = ["@kyora/sdk/plugin"] +``` + +```ts +// @kyora.watch +const state = { count: 0, users: [] } + +// @kyora.trace +async function loadUsers() { + state.users = await (await fetch("/api/users")).json() +} +``` + +Transforms at load time, no manual wrapping. + +### MCP tools + +| Tool | Description | +|------|-------------| +| `kyora_query_state` | query state snapshots over time | +| `kyora_get_recent_errors` | recent errors with stack traces | +| `kyora_get_http_log` | HTTP requests and responses | +| `kyora_search_docs` | semantic search across indexed docs | +| `kyora_list_indexed` | list indexed documentation sources | +| `nora_index_source` | index npm packages, URLs, or local files | +| `kyora_index_status` | check indexing progress | -## kyora review — multi-engine code review on your own subscriptions +## kyora review -Codex, Claude Code, Kimi, Grok, and Qwen reviewing the same PR together — each vendor's own CLI, headless, under your login, inside the checkout so it can verify claims against real code. Findings merge with consensus ranking; single-engine findings can be adversarially cross-verified by another engine before they reach you. +Multi-engine AI code review on the coding-agent subscriptions you already pay for. Codex, Claude Code, Kimi, Grok, and Qwen review the same diff independently — each vendor's own CLI running headless *inside your checkout*, under your own login, so it can grep callers and read tests instead of guessing from the diff. Findings are merged with consensus ranking and optional adversarial cross-verification, then land as one PR review with inline comments. + +No hosting, no accounts, no middleman keys: every engine is the vendor's own CLI authenticated with your subscription. + +### Quick start + +```bash +bunx @kyora-sh/review doctor # which engines are ready on this machine +bunx @kyora-sh/review # review your branch (diff vs main) +``` + +Review a PR and post the results: ```bash -bunx @kyora-sh/review doctor # which engines are ready -bunx @kyora-sh/review --pr 123 --post # panel-review a PR +bunx @kyora-sh/review review --pr 123 --post --verify ``` -CI: one workflow + your subscription tokens as repo secrets, auto-refreshed. See [`action/README.md`](action/README.md) and [`packages/review/cli`](packages/review/cli). +### How findings are ranked + +- **consensus** — two or more engines independently flagged the same issue. Rare and almost always real. +- **verified** — one engine flagged it, a *different* engine was asked to refute it against the actual code, and couldn't (`--verify`). +- **single** — one engine, unchallenged. Refuted findings are dropped entirely. + +Findings cluster by file, overlapping lines, and description similarity, so five engines saying the same thing arrive as one finding with five votes — not five comments. + +### Engines + +| id | runs | auth | +| --- | --- | --- | +| `codex` | `codex exec` (read-only sandbox) | `codex login` (ChatGPT sub) or `OPENAI_API_KEY` | +| `claude` | `claude -p` (probes allowed, writes and CI suites denied) | `claude` login or `CLAUDE_CODE_OAUTH_TOKEN` | +| `kimi` | Claude Code against Kimi's Anthropic-compatible endpoint | `KIMI_API_KEY` | +| `grok` | `grok -p` (grok-4.5, high reasoning effort) | `grok login` (SuperGrok / X Premium+) or `GROK_API_KEY` | +| `qwen` | `qwen -p` | `qwen` login (Coding Plan) or API key | + +Every available engine runs by default; pick explicitly with `--engines codex,kimi`. An engine that's missing, rate-limited, or failing drops out and the review still lands with the rest. If *every* engine fails, the run exits non-zero instead of reporting a clean review. + +Engines may execute small targeted probes (snippet evaluation, single-function checks) to verify a suspicion, but never the repo's test suites, builds, or type checks — those are auto-detected from `.github/workflows/*` and declared off-limits, since CI runs them anyway. Writes, installs, and history-mutating git commands are denied. + +### CI + +One workflow plus your subscription tokens as repo secrets. Rotating credentials (Codex) are persisted via `actions/cache`, so you seed once and they keep themselves alive: + +```yaml +- uses: eliahilse/kyora/action@main + with: + verify: "true" + env: + CODEX_AUTH_JSON: ${{ secrets.KYORA_CODEX_AUTH }} + CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.KYORA_CLAUDE_TOKEN }} + KIMI_API_KEY: ${{ secrets.KYORA_KIMI_KEY }} +``` + +Full setup, secret-seeding commands, and security notes: [`action/README.md`](action/README.md). + +### Configuration + +`kyora-review.config.json` at the repo root sets defaults (`engines`, `verify`, `post`, `base`, `failOn`, `maxDiffBytes`, `timeoutMs`), plus per-engine overrides — `bin`, `args` (with `{prompt}`/`{schema}`/`{schemaJson}`/`{out}` tokens), and `env` — so a vendor CLI changing its flags is a config edit, not a code change. CLI reference: [`packages/review/cli`](packages/review/cli). -## Layout +## Repo layout ``` packages/state/sdk @kyora/sdk instrumentation (watch, trace, auto-patching) diff --git a/action/README.md b/action/README.md index cdf44f3..724a95b 100644 --- a/action/README.md +++ b/action/README.md @@ -68,4 +68,4 @@ Every engine uses *your* account through *its vendor's own CLI* — that's what ## Security notes - **Public repos:** Actions caches are readable by workflows in the same repo, including ones triggered from fork PRs. The `if:` guard above stops fork PRs from running this job, but if other workflows in your repo run untrusted code, set `persist-auth: "false"` and rely on the seeded secrets alone (Codex seeds then need re-seeding when the refresh token rotates out). -- The review job needs only `contents: read` + `pull-requests: write`. Engines run with read-only sandboxes/tool allowlists — they review, they don't edit. +- The review job needs only `contents: read` + `pull-requests: write`. Engines may execute targeted verification probes but are denied writes, installs, and the repo's CI-covered suites — they review, they don't edit. diff --git a/packages/review/cli/README.md b/packages/review/cli/README.md index 43fab2d..0f7796e 100644 --- a/packages/review/cli/README.md +++ b/packages/review/cli/README.md @@ -28,7 +28,7 @@ bunx @kyora-sh/review review --pr 123 --post --verify | id | runs | auth | | --- | --- | --- | | `codex` | `codex exec` (read-only sandbox) | `codex login` (ChatGPT sub) or `OPENAI_API_KEY` | -| `claude` | `claude -p` (read-only tool allowlist) | `claude` login or `CLAUDE_CODE_OAUTH_TOKEN` | +| `claude` | `claude -p` (probes allowed, writes and CI suites denied) | `claude` login or `CLAUDE_CODE_OAUTH_TOKEN` | | `kimi` | Claude Code against Kimi's Anthropic-compatible endpoint | `KIMI_API_KEY` (+ optional `KIMI_BASE_URL`, `KIMI_MODEL`) | | `grok` | `grok -p` | `grok` login or `GROK_API_KEY` / `XAI_API_KEY` | | `qwen` | `qwen -p` | `qwen` login (Coding Plan) or API key | diff --git a/packages/review/cli/src/ci.test.ts b/packages/review/cli/src/ci.test.ts new file mode 100644 index 0000000..049420f --- /dev/null +++ b/packages/review/cli/src/ci.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, test } from "bun:test" +import { extractRunCommands, isCiCovered } from "./ci" + +const WORKFLOW = `name: CI +on: push +jobs: + ci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: bun install --frozen-lockfile + - run: bun run build + - name: multi + run: | + # comment + bun run check-types + bun run test + - run: echo "done" +` + +describe("extractRunCommands", () => { + test("collects single-line and block-scalar run commands", () => { + expect(extractRunCommands(WORKFLOW)).toEqual([ + "bun install --frozen-lockfile", + "bun run build", + "bun run check-types", + "bun run test", + 'echo "done"', + ]) + }) +}) + +describe("isCiCovered", () => { + test("flags suites, builds, and checkers", () => { + expect(isCiCovered("bun run test")).toBe(true) + expect(isCiCovered("bun run build")).toBe(true) + expect(isCiCovered("bun run check-types")).toBe(true) + expect(isCiCovered("npx vitest run")).toBe(true) + expect(isCiCovered("tsc --noEmit")).toBe(true) + }) + + test("ignores installs and misc commands", () => { + expect(isCiCovered("bun install --frozen-lockfile")).toBe(false) + expect(isCiCovered('echo "done"')).toBe(false) + expect(isCiCovered("git fetch origin main")).toBe(false) + }) +}) diff --git a/packages/review/cli/src/ci.ts b/packages/review/cli/src/ci.ts new file mode 100644 index 0000000..7198085 --- /dev/null +++ b/packages/review/cli/src/ci.ts @@ -0,0 +1,47 @@ +const COVERED = + /(?:^|[\s/])(test|tests|build|lint|typecheck|check-types|types:check|tsc|vitest|jest|pytest|eslint|prettier)(?::|\s|$)/ + +export function isCiCovered(command: string): boolean { + return COVERED.test(command) +} + +export function extractRunCommands(workflowYaml: string): string[] { + const commands: string[] = [] + const lines = workflowYaml.split("\n") + for (let i = 0; i < lines.length; i++) { + const match = /^(\s*)(?:-\s+)?run:\s*(.*)$/.exec(lines[i]!) + if (!match) continue + const indent = match[1]!.length + const value = match[2]!.trim() + if (value && value !== "|" && value !== ">") { + commands.push(value) + continue + } + for (let j = i + 1; j < lines.length; j++) { + const line = lines[j]! + if (line.trim() === "") continue + const lineIndent = line.length - line.trimStart().length + if (lineIndent <= indent) break + const command = line.trim() + if (!command.startsWith("#")) commands.push(command) + } + } + return commands +} + +/** Commands the repo's CI already runs that reviewers must not duplicate. */ +export async function ciCoveredCommands(root: string): Promise { + const covered = new Set() + const glob = new Bun.Glob(".github/workflows/*.{yml,yaml}") + try { + for await (const file of glob.scan({ cwd: root, dot: true })) { + const text = await Bun.file(`${root}/${file}`).text() + for (const command of extractRunCommands(text)) { + if (isCiCovered(command)) covered.add(command) + } + } + } catch { + return [] + } + return [...covered].sort() +} diff --git a/packages/review/cli/src/engines.ts b/packages/review/cli/src/engines.ts index 20575fd..8a54ac7 100644 --- a/packages/review/cli/src/engines.ts +++ b/packages/review/cli/src/engines.ts @@ -17,6 +17,17 @@ export interface EngineDef { authHint: string } +const CLAUDE_DENIED = [ + "Write", "Edit", "MultiEdit", "NotebookEdit", "WebFetch", "WebSearch", + "Bash(bun test:*)", "Bash(bun run:*)", "Bash(bun install:*)", "Bash(bunx turbo:*)", + "Bash(npm test:*)", "Bash(npm run:*)", "Bash(npm install:*)", "Bash(npx turbo:*)", + "Bash(pnpm test:*)", "Bash(pnpm run:*)", "Bash(pnpm install:*)", + "Bash(yarn:*)", "Bash(turbo:*)", "Bash(tsc:*)", "Bash(next:*)", + "Bash(vitest:*)", "Bash(jest:*)", "Bash(pytest:*)", "Bash(go test:*)", "Bash(cargo test:*)", + "Bash(make:*)", "Bash(pip install:*)", "Bash(rm:*)", "Bash(mv:*)", + "Bash(git push:*)", "Bash(git commit:*)", "Bash(git checkout:*)", "Bash(git reset:*)", "Bash(git stash:*)", +].join(",") + const CLAUDE_ARGS = [ "-p", "{prompt}", @@ -25,7 +36,9 @@ const CLAUDE_ARGS = [ "--max-turns", "40", "--allowedTools", - "Read,Grep,Glob,Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(ls:*)", + "Read,Grep,Glob,Bash", + "--disallowedTools", + CLAUDE_DENIED, ] export const ENGINES: EngineDef[] = [ diff --git a/packages/review/cli/src/index.ts b/packages/review/cli/src/index.ts index 59303e3..e009dbc 100644 --- a/packages/review/cli/src/index.ts +++ b/packages/review/cli/src/index.ts @@ -1,4 +1,5 @@ import { parseArgs } from "node:util" +import { ciCoveredCommands } from "./ci" import { buildContext, repoRoot } from "./diff" import { ENGINES, engineById, engineStatus, runEngineRaw, type EngineDef } from "./engines" import { extractFindings, extractPayload } from "./extract" @@ -131,7 +132,9 @@ async function review(flags: Flags): Promise { } log(`reviewing ${ctx.changedFiles.length} changed file(s) with: ${selected.map((engine) => engine.id).join(", ")}`) - const prompt = reviewPrompt(ctx, config.maxFindingsPerEngine) + const ciCovered = await ciCoveredCommands(root) + if (ciCovered.length > 0) log(`execution policy: ${ciCovered.length} CI-covered command(s) off-limits to engines`) + const prompt = reviewPrompt(ctx, config.maxFindingsPerEngine, ciCovered) const runs: EngineRun[] = await Promise.all( selected.map(async (engine): Promise => { log(`${engine.id}: starting`) diff --git a/packages/review/cli/src/schema.ts b/packages/review/cli/src/schema.ts index b49f9db..18f2921 100644 --- a/packages/review/cli/src/schema.ts +++ b/packages/review/cli/src/schema.ts @@ -48,10 +48,17 @@ export const VERDICTS_SCHEMA = { }, } as const -export function reviewPrompt(ctx: ReviewContext, maxFindings: number): string { +export function reviewPrompt(ctx: ReviewContext, maxFindings: number, ciCovered: string[]): string { + const ciSection = + ciCovered.length > 0 + ? `\nCI for this repository already runs the following — never run them or their equivalents; if a finding depends on their outcome, state the expectation instead:\n${ciCovered.map((command) => ` ${command}`).join("\n")}\n` + : "" return `You are one reviewer on a multi-model code review panel. Different models review the same change independently; findings are cross-checked afterwards, so precision matters more than volume. -You are inside the repository checkout (current working directory). The change under review is the diff below. Before reporting a finding, verify it against the actual code: read the surrounding file, check callers and tests with grep, confirm the claim holds. Never report an issue you could have disproven by reading the repo. Do not modify any files. +You are inside the repository checkout (current working directory). The change under review is the diff below. Before reporting a finding, verify it against the actual code: read the surrounding file, check callers and tests with grep, confirm the claim holds. Never report an issue you could have disproven by reading the repo. + +EXECUTION POLICY: You may run small, targeted probes to verify a suspicion — evaluate a snippet (\`bun -e\`, \`node -e\`, \`python3 -c\`), exercise a single function against an edge case, inspect git history. You must NOT run the project's test suites, builds, linters, or type-checkers: CI runs those already, and re-running them wastes the panel's compute without adding signal. Never modify files, install packages, or access the network. +${ciSection} Report only issues that matter: bugs, correctness, security, data loss, races, broken error handling, API misuse, significant performance problems. No style or formatting nits unless they hide a defect. Report at most ${maxFindings} findings — fewer, well-verified findings beat many speculative ones. If the change looks correct, return an empty findings array. @@ -86,7 +93,7 @@ export function verifyPrompt(claims: VerifyClaim[]): string { .join("\n\n") return `You are an adversarial verifier on a code review panel. Each claim below was reported by only ONE reviewer, so it is suspect. You are inside the repository checkout: for each claim, read the actual code and decide whether the issue is real. -Actively try to refute each claim. "confirmed" only if you can point at the code path that makes it true; if the claim is speculative, already handled elsewhere, or you cannot reproduce the reasoning from the code, return "refuted". Do not modify any files. +Actively try to refute each claim. "confirmed" only if you can point at the code path that makes it true; if the claim is speculative, already handled elsewhere, or you cannot reproduce the reasoning from the code, return "refuted". You may run small targeted probes (snippet evaluation, single-function checks) to test a claim, but never the project's test suites or builds, and never modify files. OUTPUT: respond with ONLY a JSON object, no prose, one verdict per claim index: {"verdicts": [{"index": 0, "verdict": "confirmed", "reason": "..."}]}