From 9c0916f7113ec5f70c13c9dbdc61b8fc1d819003 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 13:39:16 +0530
Subject: [PATCH 01/37] chore(quality): repair the knip gate and drop unused
dependencies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
knip:strict runs in CI (ci.yml "Code health") but was analyzing zero files:
knip.json declared root-relative entry paths while pnpm-workspace.yaml sets
packages: apps/*, so knip resolved the apps as separate workspaces and every
entry/project pattern matched nothing. `knip --reporter json` returned
{"issues":[]}. The unused-code gate has been passing vacuously.
Rewrite the config workspace-aware (., apps/desktop, apps/landing-page-astro)
and strip the suppression that hid real findings — ignoreDependencies drops
from ~24 entries to 2, and the blanket ignore list is gone entirely.
With the gate live it reported six genuinely unused dependencies, verified by
hand as having zero imports anywhere in the desktop app. They were invisible
because the old config named @xterm/* and react-resizable-panels in
ignoreDependencies. They are leftovers from the removed agent terminal UI.
ignoreIssues now whitelists the warm-verification / scenario-compiler contract
modules file-by-file rather than by directory glob, so a new dead module in
those directories still fails the gate. Verified by canary: adding an unused
export is detected.
Co-Authored-By: Claude Opus 5 (1M context)
---
apps/desktop/package.json | 6 -
knip.json | 301 ++++++++++++++++++++------------------
pnpm-lock.yaml | 58 --------
3 files changed, 159 insertions(+), 206 deletions(-)
diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index ea9487df..b04aa7de 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -65,17 +65,11 @@
"@tauri-apps/plugin-notification": "^2.3.3",
"@tauri-apps/plugin-process": "^2.0.0",
"@tauri-apps/plugin-updater": "^2.0.0",
- "@xterm/addon-fit": "^0.10.0",
- "@xterm/addon-search": "0.16.0",
- "@xterm/addon-web-links": "^0.12.0",
- "@xterm/addon-webgl": "0.19.0",
- "@xterm/xterm": "^5.5.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^1.7.0",
"react": "^19.2.8",
"react-dom": "^19.2.8",
- "react-resizable-panels": "^4.9.0",
"react-router-dom": "^7.18.2",
"tailwind-merge": "^3.5.0"
},
diff --git a/knip.json b/knip.json
index d39c60b3..61c94e41 100644
--- a/knip.json
+++ b/knip.json
@@ -1,157 +1,174 @@
{
"$schema": "https://unpkg.com/knip@latest/schema.json",
- "entry": [
- "apps/desktop/src/main.tsx",
- "apps/desktop/src/App.tsx",
- "apps/desktop/src/lib/verify-cli.ts",
- "apps/desktop/src/lib/warm-verification/daemon-entry.ts",
- "apps/desktop/src/lib/intent-debugger/run-intent-cli.ts",
- "apps/desktop/src/lib/synthetic-qa/run-fixture-cli.ts"
- ],
- "project": ["**/*.{ts,tsx,js,jsx,mjs,cjs,mts}"],
- "ignore": [
- "**/dist/**",
- "**/build/**",
- "**/.next/**",
- "**/.astro/**",
- "**/.output/**",
- "**/node_modules/**",
- "**/coverage/**",
- "**/public/**",
- "**/*.config.{js,ts,mjs,cjs}",
- "**/eslint.config.*",
- "**/blume.config.*",
- "**/docs-blume/**",
- "**/docs-site/**",
- "scripts/**",
- "**/scripts/**",
- "tests/e2e/**",
- "**/tests/**",
- "test/**",
- "**/*.test.{ts,tsx,js,mjs}",
- "**/*.spec.{ts,tsx,js,mjs}",
- "**/*.d.mts",
- "**/*.d.ts",
- "**/__tests__/**",
- "**/playground/**",
- "**/examples/**",
- "**/fixtures/**",
- "**/verify/**",
- "benchmark/**",
- "benchmarks/**",
- "openspec/**",
- "research/**",
- "**/worker.mjs",
- "**/src-tauri/**"
- ],
+ "workspaces": {
+ ".": {
+ "entry": [
+ "scripts/**/*.mjs"
+ ],
+ "project": [
+ "scripts/**/*.mjs"
+ ]
+ },
+ "apps/desktop": {
+ "entry": [
+ "scripts/**/*.mjs",
+ "tests/**/*.spec.ts",
+ "src/**/*.test.{ts,tsx}"
+ ],
+ "project": [
+ "src/**/*.{ts,tsx}",
+ "scripts/**/*.mjs"
+ ]
+ },
+ "apps/landing-page-astro": {
+ "entry": [
+ "src/pages/**/*.{astro,ts}"
+ ],
+ "project": [
+ "src/**/*.{ts,astro}"
+ ]
+ }
+ },
"ignoreDependencies": [
- "typescript",
- "@types/*",
- "biome",
- "@biomejs/biome",
- "prettier",
- "prettier-plugin-tailwindcss",
- "husky",
- "lint-staged",
- "vitest",
- "@vitest/*",
- "playwright",
- "@playwright/test",
"tailwindcss",
- "@tailwindcss/*",
- "lightningcss",
- "tsx",
- "size-limit",
- "knip",
- "blume",
- "@blume/*",
- "astro",
- "@astrojs/*",
- "@shikijs/*",
- "shiki",
- "wrangler",
- "@tauri-apps/cli",
- "@tauri-apps/api",
- "@tauri-apps/plugin-*",
- "@vitejs/plugin-react",
- "vite",
- "autoprefixer",
- "postcss",
- "c8",
- "msw",
- "yaml",
- "class-variance-authority",
- "clsx",
- "tailwind-merge",
- "tailwindcss-animate",
- "@radix-ui/*",
- "lucide-react",
- "react",
- "react-dom",
- "react-router-dom",
- "react-resizable-panels",
- "@xterm/*",
- "@axe-core/playwright",
"ccusage"
],
"ignoreBinaries": [
- "astro",
- "vite",
- "wrangler",
- "tsx",
- "biome",
- "playwright",
- "knip",
- "prettier",
- "blume",
- "tauri",
+ "du",
+ "go",
+ "lipo",
"lsof",
"netstat",
"ps",
"rustc",
- "cargo",
- "swift"
+ "swift",
+ "tauri",
+ "xcode-select"
],
"ignoreIssues": {
- "src/app/api/**/route.ts": ["exports", "types"],
- "src/lib/actions/**": ["exports", "types"],
- "lib/actions/**": ["exports", "types"],
- "**/schema.ts": ["exports", "types"],
- "**/db/schema*.ts": ["exports", "types"],
- "**/commands/**": ["exports", "types"],
- "**/agent-edge.*": ["exports", "types"],
- "**/foundry-monitoring.ts": ["exports", "types"],
- "**/analytics.ts": ["exports", "types"],
- "**/api-timing.ts": ["exports", "types"],
- "**/contracts.ts": ["exports", "types"],
- "**/differential-contracts.ts": ["exports", "types"],
- "**/differential-daemon-contracts.ts": ["exports", "types"],
- "**/differential-plan.ts": ["exports", "types"],
- "**/differential-config.ts": ["exports", "types"],
- "**/differential-source.ts": ["exports", "types"],
- "**/differential-comparator.ts": ["exports", "types", "duplicates"],
- "**/differential-timing-policy.ts": ["exports", "types"],
- "**/differential-scheduler.ts": ["exports", "types"],
- "**/qualification-policy.ts": ["exports", "types"],
- "**/tauri-ipc.ts": ["exports", "types"],
- "**/verification-state-bridge.ts": ["exports", "types"],
- "**/warm-verification/config.ts": ["exports", "types"],
- "**/warm-verification/config-loader.ts": ["exports", "types"],
- "**/warm-verification/contracts.ts": ["exports", "types"],
- "**/warm-verification/adapters.ts": ["exports", "types"],
- "**/warm-verification/change-set.ts": ["exports", "types"],
- "**/warm-verification/ipc.ts": ["exports", "types"],
- "**/warm-verification/manifest-loader.ts": ["exports", "types"],
- "**/warm-verification/scenario.ts": ["exports", "types"],
- "**/warm-verification/source-watcher.ts": ["exports", "types"],
- "**/warm-verification/state.ts": ["exports", "types"],
- "**/warm-verification/supervision.ts": ["exports", "types"],
- "**/warm-verification/visual.ts": ["exports", "types"],
- "**/warm-verification/selection.ts": ["exports", "types"],
- "**/warm-verification/retention.ts": ["exports", "types"],
- "**/scenario-compiler/contracts.ts": ["exports", "types"],
- "**/scenario-compiler/candidate.ts": ["exports", "types"],
- "**/scenario-compiler/cli.ts": ["exports", "types"],
- "**/scenario-compiler/provider.ts": ["exports", "types"]
+ "apps/desktop/src/lib/business-rule-archaeology/qualification-policy.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/scenario-compiler/candidate.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/scenario-compiler/cli.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/scenario-compiler/provider.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/verification-state-bridge.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/adapters.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/change-set.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/config-loader.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/config.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-comparator.ts": [
+ "duplicates",
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-config.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-contracts.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-daemon-contracts.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-plan.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-scheduler.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-source.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/differential-timing-policy.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/ipc.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/manifest-loader.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/retention.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/scenario.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/selection.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/source-watcher.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/state.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/supervision.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/visual.ts": [
+ "exports",
+ "types"
+ ],
+ "**/commands/**": [
+ "exports",
+ "types"
+ ],
+ "**/tauri-ipc.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/warm-verification/contracts.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/business-rule-archaeology/contracts.ts": [
+ "exports",
+ "types"
+ ],
+ "apps/desktop/src/lib/scenario-compiler/contracts.ts": [
+ "types"
+ ]
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a8c0b76f..ec4de4e6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -81,21 +81,6 @@ importers:
'@tauri-apps/plugin-updater':
specifier: ^2.0.0
version: 2.10.1
- '@xterm/addon-fit':
- specifier: ^0.10.0
- version: 0.10.0(@xterm/xterm@5.5.0)
- '@xterm/addon-search':
- specifier: 0.16.0
- version: 0.16.0
- '@xterm/addon-web-links':
- specifier: ^0.12.0
- version: 0.12.0
- '@xterm/addon-webgl':
- specifier: 0.19.0
- version: 0.19.0
- '@xterm/xterm':
- specifier: ^5.5.0
- version: 5.5.0
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -111,9 +96,6 @@ importers:
react-dom:
specifier: ^19.2.8
version: 19.2.8(react@19.2.8)
- react-resizable-panels:
- specifier: ^4.9.0
- version: 4.10.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
react-router-dom:
specifier: ^7.18.2
version: 7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -2307,23 +2289,6 @@ packages:
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
- '@xterm/addon-fit@0.10.0':
- resolution: {integrity: sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==}
- peerDependencies:
- '@xterm/xterm': ^5.0.0
-
- '@xterm/addon-search@0.16.0':
- resolution: {integrity: sha512-9OeuBFu0/uZJPu+9AHKY6g/w0Czyb/Ut0A5t79I4ULoU4IfU5BEpPFVGQxP4zTTMdfZEYkVIRYbHBX1xWwjeSA==}
-
- '@xterm/addon-web-links@0.12.0':
- resolution: {integrity: sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw==}
-
- '@xterm/addon-webgl@0.19.0':
- resolution: {integrity: sha512-b3fMOsyLVuCeNJWxolACEUED0vm7qC0cy4wRvf3oURSzDTYVQiGPhTnhWZwIHdvC48Y+oLhvYXnY4XDXPoJo6A==}
-
- '@xterm/xterm@5.5.0':
- resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==}
-
am-i-vibing@0.4.0:
resolution: {integrity: sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg==}
hasBin: true
@@ -3569,12 +3534,6 @@ packages:
'@types/react':
optional: true
- react-resizable-panels@4.10.0:
- resolution: {integrity: sha512-frjewRQt7TCv/vCH1pJfjZ7RxAhr5pKuqVQtVgzFq/vherxBFOWyC3xMbryx5Ti2wylViGUFc93Etg4rB3E0UA==}
- peerDependencies:
- react: ^18.0.0 || ^19.0.0
- react-dom: ^18.0.0 || ^19.0.0
-
react-router-dom@7.18.2:
resolution: {integrity: sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==}
engines: {node: '>=20.0.0'}
@@ -5905,18 +5864,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@xterm/addon-fit@0.10.0(@xterm/xterm@5.5.0)':
- dependencies:
- '@xterm/xterm': 5.5.0
-
- '@xterm/addon-search@0.16.0': {}
-
- '@xterm/addon-web-links@0.12.0': {}
-
- '@xterm/addon-webgl@0.19.0': {}
-
- '@xterm/xterm@5.5.0': {}
-
am-i-vibing@0.4.0:
dependencies:
process-ancestry: 0.1.0
@@ -7218,11 +7165,6 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.18
- react-resizable-panels@4.10.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
- dependencies:
- react: 19.2.8
- react-dom: 19.2.8(react@19.2.8)
-
react-router-dom@7.18.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
dependencies:
react: 19.2.8
From f50bd728315007545e12b8f3247ef640aacb7f33 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 13:40:08 +0530
Subject: [PATCH 02/37] chore(repo): untrack orphaned tool output and tidy
gitignore
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
.impeccable/ and .claude/projects/ had zero inbound references anywhere in the
repo — they are local tool output, not shared repo content. Untrack them (kept
on disk) and gitignore them.
.claude/settings.local.json was tracked despite already being listed in
.gitignore. Its contents are stale per-developer state: every path points at
/Users/sarthakagrawal/Desktop/code-reviewer/ with a packages/ + workers/
layout that no longer exists, plus Vercel permissions from before the move to
Cloudflare Pages.
research/ held one real document — a survey of codebase-context tooling — so
move it to docs/knowledge/ with the frontmatter check-docs.mjs requires rather
than dropping it.
Also drop gitignore entries for a layout that no longer exists: the
"Action runtime bundle" dist/* + !dist/index.js pair (there is no action.yml
in this repo), packages/*, workers/* and .vercel. dist/* becomes dist/ rather
than being deleted, since it matches at any depth and is what keeps
docs-site/dist and apps/landing-page-astro/dist out of the index.
This commit also carries the gitignore lines for the corpus and evidence moves
in the two commits that follow, since they share one file.
Co-Authored-By: Claude Opus 5 (1M context)
---
.../memory/MEMORY.md | 5 -
.../memory/project_agent_first_pivot.md | 21 --
.../project_shelved_playwright_testing.md | 19 --
.claude/settings.local.json | 98 --------
.gitignore | 20 +-
...s-run-structural-context-evaluation-mjs.md | 103 ---------
...apps-desktop-src-components-sidebar-tsx.md | 102 ---------
...-01T17-55-01Z__apps-desktop-src-app-tsx.md | 171 --------------
...31-57Z__apps-desktop-src-pages-home-tsx.md | 74 ------
...p-src-components-app-error-boundary-tsx.md | 57 -----
..._apps-desktop-src-pages-performance-tsx.md | 30 ---
.impeccable/design.json | 212 ------------------
.../codebase-context-tools-landscape.md | 7 +
13 files changed, 17 insertions(+), 902 deletions(-)
delete mode 100644 .claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/MEMORY.md
delete mode 100644 .claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_agent_first_pivot.md
delete mode 100644 .claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_shelved_playwright_testing.md
delete mode 100644 .claude/settings.local.json
delete mode 100644 .impeccable/critique/2026-07-27T05-06-55Z__scripts-run-structural-context-evaluation-mjs.md
delete mode 100644 .impeccable/critique/2026-07-30T06-34-52Z__apps-desktop-src-components-sidebar-tsx.md
delete mode 100644 .impeccable/critique/2026-08-01T17-55-01Z__apps-desktop-src-app-tsx.md
delete mode 100644 .impeccable/critique/2026-08-10T18-31-57Z__apps-desktop-src-pages-home-tsx.md
delete mode 100644 .impeccable/critique/2026-08-15T20-33-20Z__apps-desktop-src-components-app-error-boundary-tsx.md
delete mode 100644 .impeccable/critique/2026-08-15T21-39-48Z__apps-desktop-src-pages-performance-tsx.md
delete mode 100644 .impeccable/design.json
rename {research => docs/knowledge}/codebase-context-tools-landscape.md (99%)
diff --git a/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/MEMORY.md b/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/MEMORY.md
deleted file mode 100644
index 4ec74f63..00000000
--- a/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/MEMORY.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Memory Index
-
-## Project Direction
-- [Agent-First Pivot](project_agent_first_pivot.md) — CodeVetter pivoting to AI-agent-first: reviewing agent-generated PRs, agent-to-agent interaction on GitHub
-- [Shelved: Playwright Testing](project_shelved_playwright_testing.md) — AI E2E testing idea explored and shelved, possible v2+ "verify the fix" feature
diff --git a/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_agent_first_pivot.md b/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_agent_first_pivot.md
deleted file mode 100644
index 379792fd..00000000
--- a/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_agent_first_pivot.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-name: Product Pivot - AI Agent-First Code Review
-description: CodeVetter is pivoting to be an AI-agent-first product — reviewing PRs generated by AI coding agents and interacting with agents directly on GitHub PR pages.
-type: project
----
-
-## Product Direction: AI Agent-First (2026-03-11)
-
-**Core pivot:** CodeVetter should be an AI-agent-first product, not human-first.
-
-**What this means:**
-- Primary audience: AI coding agents (Claude Code, Cursor, Devin, Copilot Workspace, etc.) that generate PRs
-- CodeVetter reviews all PRs generated by agents automatically
-- AI agents can talk to CodeVetter directly on the GitHub PR page itself (agent-to-agent conversation)
-- The product is a quality gate / reviewer for AI-generated code
-
-**Why this matters:**
-- AI agents are generating an increasing volume of PRs
-- Human reviewers can't keep up with the volume
-- Agent-generated code has different failure modes than human code (hallucinated APIs, subtle logic errors, over-engineering)
-- Agent-to-agent review loop on GitHub is a novel interaction model
diff --git a/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_shelved_playwright_testing.md b/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_shelved_playwright_testing.md
deleted file mode 100644
index 05113298..00000000
--- a/.claude/projects/-Users-sarthakagrawal-Desktop-code-reviewer/memory/project_shelved_playwright_testing.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-name: Shelved - AI Playwright Testing Feature
-description: Idea to add AI-driven Playwright E2E testing was explored and shelved. Could revisit as a "verify the fix" feature in v2+.
-type: project
----
-
-## Shelved Idea: AI-Powered Playwright Testing (2026-03-11)
-
-**Concept:** Users provide auth + instructions, AI uses Playwright to run E2E tests on their app.
-
-**Decision:** Shelved. Not pursuing now.
-
-**Reasons:**
-- Market already crowded (Browserbase, Momentic, QA Wolf, Shortest, Drizzle AI)
-- Tangential to core code review value prop
-- Expensive to run on every PR; running only before releases makes it an afterthought
-- Would split focus from core product
-
-**Potential future angle:** "Verify the fix" step triggered by review intelligence — differentiated because it's driven by CodeVetter's review findings, not generic E2E. Only revisit if users explicitly ask for it.
diff --git a/.claude/settings.local.json b/.claude/settings.local.json
deleted file mode 100644
index 9ffcd90a..00000000
--- a/.claude/settings.local.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "permissions": {
- "allow": [
- "Bash(git add:*)",
- "Bash(tail:*)",
- "Bash(which npm:*)",
- "Bash(git:*)",
- "Bash(which tsc:*)",
- "Bash(/Users/sarthakagrawal/Desktop/code-reviewer/node_modules/.bin/tsc:*)",
- "Bash(head:*)",
- "Bash(node:*)",
- "Bash(pkill:*)",
- "Bash(sleep 2:*)",
- "Bash(sleep 3:*)",
- "mcp__plugin_playwright_playwright__browser_navigate",
- "Bash(whois:*)",
- "Bash(which vercel 2>/dev/null && vercel --version 2>/dev/null; which wrangler 2>/dev/null && wrangler --version 2>/dev/null)",
- "Bash(wrangler whoami:*)",
- "Bash(vercel teams:*)",
- "Bash(wrangler:*)",
- "Bash(cd /Users/sarthakagrawal/Desktop/code-reviewer/apps/landing-page && vercel --prod --yes 2>&1)",
- "Bash(cd /Users/sarthakagrawal/Desktop/code-reviewer/apps/landing-page && vercel link --yes --scope sarthak-agrawals-projects-5d4953f8 2>&1 && vercel --prod --yes --scope sarthak-agrawals-projects-5d4953f8 2>&1)",
- "Bash(vercel project:*)",
- "Bash(vercel link:*)",
- "Bash(vercel:*)",
- "mcp__plugin_playwright_playwright__browser_install",
- "mcp__plugin_playwright_playwright__browser_take_screenshot",
- "Bash(find:*)",
- "Bash(grep:*)",
- "Bash(fd:*)",
- "Bash(wc:*)",
- "Bash(ls:*)",
- "Bash(for f:*)",
- "Read(//Users/sarthakagrawal/Desktop/code-reviewer/**)",
- "Bash(bash /tmp/count_dashboard.sh)",
- "Bash(cat:*)",
- "Bash(cd:*)",
- "Bash(npx tsc:*)",
- "Bash(npx vite:*)",
- "Bash(npm install:*)",
- "Bash(lsof:*)",
- "Bash(curl:*)",
- "Bash(python3:*)",
- "WebSearch",
- "WebFetch(domain:www.greptile.com)",
- "WebFetch(domain:www.coderabbit.ai)",
- "WebFetch(domain:www.conductor.build)",
- "WebFetch(domain:www.ellipsis.dev)",
- "WebFetch(domain:bito.ai)",
- "WebFetch(domain:whatthediff.ai)",
- "WebFetch(domain:superset.sh)",
- "WebFetch(domain:github.com)",
- "WebFetch(domain:news.ycombinator.com)",
- "WebFetch(domain:www.ycombinator.com)",
- "WebFetch(domain:makerstack.co)",
- "WebFetch(domain:launchllama.co)",
- "WebFetch(domain:docs.superset.sh)",
- "WebFetch(domain:www.producthunt.com)",
- "Bash(cargo check:*)",
- "WebFetch(domain:docs.dodopayments.com)",
- "Bash(pnpm tauri:*)",
- "Bash(npx @tauri-apps/cli build)",
- "Bash(gh run:*)",
- "mcp__claude_ai_Vercel__list_projects",
- "mcp__claude_ai_Vercel__get_deployment_build_logs",
- "mcp__claude_ai_Vercel__list_deployments",
- "Bash(gh release:*)",
- "Bash(gh api:*)",
- "Bash(xargs -I {} sh -c 'git push origin :refs/tags/{} 2>&1; git tag -d {}')",
- "Bash(npm test:*)",
- "Bash(npm run:*)",
- "Bash(/bin/ls -la /Users/sarthakagrawal/Desktop/code-reviewer/)",
- "Bash(/bin/ls -la /Users/sarthakagrawal/Desktop/code-reviewer/apps/)",
- "Bash(/bin/ls -la /Users/sarthakagrawal/Desktop/code-reviewer/packages/)",
- "Bash(/bin/ls -la /Users/sarthakagrawal/Desktop/code-reviewer/workers/)",
- "Bash(/bin/ls -la /Users/sarthakagrawal/Desktop/code-reviewer/tests/)",
- "Bash(for pkg:*)",
- "Bash(do echo:*)",
- "Bash(/usr/bin/python3 -c \"import json; d=json.load\\(open\\(''/Users/sarthakagrawal/Desktop/code-reviewer/$pkg/package.json''\\)\\); scripts=d.get\\(''scripts'',{}\\); [print\\(f'' {k}: {v}''\\) for k,v in scripts.items\\(\\)]\")",
- "Bash(done)",
- "Bash(/bin/ls /Users/sarthakagrawal/Desktop/code-reviewer/packages/review-core/dist/)",
- "Bash(npx eslint:*)",
- "Read(//Library/Logs/DiagnosticReports/**)",
- "Read(//Users/sarthakagrawal/Library/Logs/DiagnosticReports/**)",
- "Bash(pmset -g log)",
- "Bash(/bin/ls /Users/sarthakagrawal/Desktop/code-reviewer/packages/db/src/)",
- "Bash(sysctl hw.model hw.ncpu kern.version)",
- "Bash(/bin/ls /Users/sarthakagrawal/Desktop/code-reviewer/tests/)",
- "Bash(ps aux:*)",
- "Bash(sudo mdutil:*)",
- "Bash(mdutil -s /)",
- "Bash(mdutil:*)",
- "Read(//Applications/**)",
- "Bash(brew list:*)",
- "Bash(xargs kill:*)"
- ]
- }
-}
diff --git a/.gitignore b/.gitignore
index 562233e3..5470fc8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,7 @@
node_modules/
-# Action runtime bundle must stay versioned.
-dist/*
-!dist/index.js
-
# Generated build artifacts should not be tracked.
-packages/*/dist
-workers/*/dist
-workers/*/dist-cjs
-workers/*/.wrangler
-.vercel
+dist/
out/
.next/
target/
@@ -35,6 +27,11 @@ apps/desktop/native/AgentIsland/.build/
# Secrets
.claude/settings.local.json
+# Local agent/tool state and output — not shared repo content.
+.claude/projects/
+.fleet/
+.impeccable/
+
# IDE
.vscode/
.idea/
@@ -50,7 +47,10 @@ apps/desktop/synthetic-qa-artifacts/
.playwright-mcp/
# Public benchmark reviewer output (drop tool outputs here, not tracked)
-benchmark/reviews/
+benchmarks/public-catch-rate/reviews/
+
+# Scratch output from CLI runs (--out artifacts/...). Committed evidence lives in evidence/.
+artifacts/
# Coverage
coverage/
diff --git a/.impeccable/critique/2026-07-27T05-06-55Z__scripts-run-structural-context-evaluation-mjs.md b/.impeccable/critique/2026-07-27T05-06-55Z__scripts-run-structural-context-evaluation-mjs.md
deleted file mode 100644
index c94c42c3..00000000
--- a/.impeccable/critique/2026-07-27T05-06-55Z__scripts-run-structural-context-evaluation-mjs.md
+++ /dev/null
@@ -1,103 +0,0 @@
----
-target: structural-context evaluation HTML report
-total_score: 33
-max_score: 40
-na_heuristics:
-p0_count: 0
-p1_count: 0
-timestamp: 2026-07-27T05-06-55Z
-slug: scripts-run-structural-context-evaluation-mjs
----
-Method: dual-agent (A: impeccable_assessment_a · B: impeccable_assessment_b)
-
-## Design Health Score
-
-| # | Heuristic | Score | Key finding |
-|---|---|---:|---|
-| 1 | Visibility of System Status | 4 | Qualification, pair counts, gates, source, and read-only state are explicit. |
-| 2 | Match System / Real World | 3 | A/A and discordance still assume evaluation fluency. |
-| 3 | User Control and Freedom | 2 | A static report has no filtering or bulk disclosure controls. |
-| 4 | Consistency and Standards | 4 | Evidence hierarchy, arm naming, and CodeVetter tokens are cohesive. |
-| 5 | Error Prevention | 4 | Claim boundaries and neutral diagnostic deltas prevent overstatement. |
-| 6 | Recognition Rather Than Recall | 4 | Mobile diagnostics now expose every comparison value in each metric card. |
-| 7 | Flexibility and Efficiency | 2 | Large experiments will eventually need anchors, filters, or condensed rows. |
-| 8 | Aesthetic and Minimalist Design | 4 | The report remains focused and qualification-first across all widths. |
-| 9 | Error Recovery | 3 | Invalid pairs explain concrete exclusion reasons; generation errors remain CLI-only. |
-| 10 | Help and Documentation | 3 | Inline caveats are strong; evaluation terms have no compact glossary. |
-| **Total** | | **33/40** | **Good, above the Fleet floor after polish.** |
-
-## Design Specificity Verdict
-
-The report is authored for CodeVetter rather than a generic analytics
-dashboard. Its sequence is the product's evidence model: claim boundary,
-paired executable outcome, changed checks and graph traces, qualification,
-activity diagnostics, and limitations. Amber remains the evidence accent and
-cyan is reserved for graph provenance.
-
-The CLI detector returned zero findings. The rendered detector found 15
-advisory issues before polish: eight small-text or line-length findings and
-seven cyan-palette findings. The cyan findings were false positives because the
-color has a stable graph-provenance meaning. The small text, touch target, copy
-measure, and mobile diagnostics issues were fixed.
-
-## Overall Impression
-
-The opening creates curiosity, then immediately constrains interpretation with
-an unqualified claim. The paired corridor is the visual peak. The closing
-authorized-claim block now restores that same boundary after the evidence
-detail, so a long read ends with the correct decision.
-
-## What's Working
-
-- Qualification appears before the favorable synthetic percentage.
-- Paired outcomes and hidden-check changes are readable without decorative
- metric cards.
-- Native details, semantic regions, a real data table, textual PASS/FAIL
- labels, visible focus, and high contrast support accessible inspection.
-
-## Priority Issues
-
-### [P2] Large-run navigation
-
-The schema permits much larger experiments than the two-pair sample. A future
-real corpus may need outcome filters, section anchors, or condensed tie rows.
-This does not block the bounded local report.
-
-### [P3] Evaluation terminology
-
-A/A, discordance, and coverage are correct but assume statistical fluency. A
-compact glossary may help less experienced product owners when real receipts
-arrive.
-
-### [P3] Fixed dark presentation
-
-The tokenized fixed-dark report is coherent with CodeVetter and includes print
-rules, but it does not offer an alternate light screen theme.
-
-## Persona Red Flags
-
-**Alex, power user:** The two-pair report is fast to scan, but dozens of pairs
-would require outcome filtering and condensed ties.
-
-**Sam, accessibility-dependent user:** Semantic structure, contrast, keyboard
-disclosures, 44px summary targets, and stacked mobile diagnostics now support
-the core reading path. A future large corpus needs skip links or section
-navigation.
-
-**Priya, technical product owner:** The synthetic and unqualified boundary is
-now tied to both the comparison corridor and the closing verdict. Activity
-deltas are neutral and explicitly mean less, not better.
-
-## Minor Observations
-
-- Long identities and source paths wrap safely.
-- A zero-valid-pair state withholds the percentage corridor.
-- Print semantic colors use darker values while retaining text labels.
-- Missing optional diagnostics remain missing rather than becoming zero.
-
-## Questions to Consider
-
-- At what corpus size should the evidence brief become a navigable
- investigation tool?
-- Should real-trial reports define a tiny inline glossary for A/A noise and
- qualification policy?
diff --git a/.impeccable/critique/2026-07-30T06-34-52Z__apps-desktop-src-components-sidebar-tsx.md b/.impeccable/critique/2026-07-30T06-34-52Z__apps-desktop-src-components-sidebar-tsx.md
deleted file mode 100644
index 4f4d8232..00000000
--- a/.impeccable/critique/2026-07-30T06-34-52Z__apps-desktop-src-components-sidebar-tsx.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-target: CodeVetter desktop sidebar
-total_score: 33
-max_score: 40
-na_heuristics:
-p0_count: 0
-p1_count: 0
-timestamp: 2026-07-30T06-34-52Z
-slug: apps-desktop-src-components-sidebar-tsx
----
-Method: dual-agent (A: sidebar_critique_a · B: sidebar_critique_b)
-
-## Design Health Score
-
-| # | Heuristic | Score | Key issue |
-|---|---|---:|---|
-| 1 | Visibility of system status | 3 | Active location is clear; the transient G chord remains intentionally quiet. |
-| 2 | Match system / real world | 3 | Product labels are established but assume some CodeVetter familiarity. |
-| 3 | User control and freedom | 4 | Navigation is reversible and the palette now restores focus to its trigger. |
-| 4 | Consistency and standards | 4 | Rows, grouping, focus, active state, and spacing follow the Evidence Bench system. |
-| 5 | Error prevention | 3 | Shortcut handling protects form controls; contenteditable remains a narrow edge case. |
-| 6 | Recognition rather than recall | 3 | Every destination is labeled; detailed descriptions remain in accessible tooltips. |
-| 7 | Flexibility and efficiency | 4 | Search, Cmd-K, and G chords provide strong expert acceleration. |
-| 8 | Aesthetic and minimalist design | 4 | The rail is calm, compact, and free of decorative feature noise. |
-| 9 | Error recovery | 3 | Search dismisses cleanly and restores focus; mistimed G chords remain silent. |
-| 10 | Help and documentation | 2 | Tooltips explain destinations, but the rail intentionally carries no dedicated help surface. |
-| **Total** | | **33/40** | **Good; no blocking or major issues remain.** |
-
-## Design Specificity Verdict
-
-The sidebar is clearly adapted to CodeVetter through its Context and
-Verification grouping, Evidence Workbench identity, warm verification accent,
-real product routes, resource utility, and keyboard model. Its basic rail
-composition is conventional, but the content and state grammar are not a
-generic mockup.
-
-The deterministic scan returned zero findings across `App.tsx`, `sidebar.tsx`,
-`ResourceChip.tsx`, and `command-palette.tsx`. Browser evidence confirmed AA
-contrast, one accessible active destination, no overflow at supported desktop
-sizes, a working Search trigger, and keyboard focus restoration. No reliable
-browser overlay was available because the exposed evaluation surface was
-read-only; live screenshots, computed styles, geometry, axe, and Playwright
-interaction checks were used instead.
-
-## Overall Impression
-
-The new rail feels like a quiet native instrument and carries the reference's
-search-first hierarchy without importing an unrelated cream visual system. The
-main opportunity was finishing keyboard and control-size details, both of which
-were corrected during the pass.
-
-## What's Working
-
-- The active state uses position, icon treatment, text, and `aria-current`, so
- it is legible without color alone.
-- Context, Verification, and bottom utilities produce a clear three-part
- information hierarchy.
-- Cmd-K, visible G chords, and direct search make the compact shell efficient
- for repeat users.
-
-## Priority Issues
-
-- **[P1, fixed] Command palette dialog naming:** Opening Search exposed a Radix
- accessibility error because the dialog had no screen-reader title. The
- palette now includes a visually hidden `DialogTitle`, and the interaction
- test asserts that opening and closing it emits no console error.
-- **[P2, fixed] Palette focus restoration:** Closing Search initially returned
- focus to the document body. The shell now remembers the invoking element and
- restores focus after Radix closes.
-- **[P2, fixed] Control sizing:** Root font sizing made Tailwind rem-based
- 40px controls render at 35px. Search and navigation rows now use explicit
- 40px dimensions and full 13–14px labels.
-- **[P3] Silent G-chord timeout:** A mistimed chord has no feedback. This is
- acceptable for a secondary expert accelerator, but could gain a tiny
- transient key hint if real usage shows failures.
-- **[P3] Destination descriptions rely on tooltips:** First-time users may
- need a little exploration to distinguish Work, Board, Review, and Testing.
- Existing product labels were preserved deliberately.
-
-## Persona Red Flags
-
-- **Power user:** Search and G chords are fast, but the 500ms G timeout may
- feel unforgiving until learned.
-- **First-timer:** The grouping helps, though the differences among Work,
- Board, Review, and Testing are learned through tooltips and page content.
-- **Keyboard or low-vision user:** The final build has a global amber focus
- ring, 40px controls, AA contrast, semantic groups, text labels, and focus
- restoration. No major barrier remains in the rail.
-
-## Minor Observations
-
-- The 224px rail stays proportionate at the configured 900px minimum window.
-- The warm ambient wash respects the single-accent rule.
-- The resource chip is absent in browser fallback because Tauri resource data
- is unavailable; it remains present in the desktop runtime.
-
-## Questions to Consider
-
-- Should future usage evidence show the current repository or verification run
- in this rail, or should project context stay inside the owning workspaces?
-- If users do not discover G chords, would one compact shortcuts hint be more
- useful than permanent suffixes?
diff --git a/.impeccable/critique/2026-08-01T17-55-01Z__apps-desktop-src-app-tsx.md b/.impeccable/critique/2026-08-01T17-55-01Z__apps-desktop-src-app-tsx.md
deleted file mode 100644
index 2a6b1ba4..00000000
--- a/.impeccable/critique/2026-08-01T17-55-01Z__apps-desktop-src-app-tsx.md
+++ /dev/null
@@ -1,171 +0,0 @@
----
-target: current CodeVetter desktop product and UI
-total_score: 23
-max_score: 40
-na_heuristics:
-p0_count: 1
-p1_count: 4
-timestamp: 2026-08-01T17-55-01Z
-slug: apps-desktop-src-app-tsx
----
-# CodeVetter product and desktop critique
-
-## Strategic verdict
-
-CodeVetter is impressive engineering but not yet a coherent product. The repository contains a substantial local verification stack: bounded execution, runtime receipts, structural and historical evidence, deterministic scoring, a qualified synthetic task corpus, CLI/MCP boundaries, and unusually honest failure states. But that core is buried beneath an older AI-review workbench, repository-intelligence suite, usage dashboard, agent workspace, board, and native agent presentation layer.
-
-The July pivot exists in product documentation and newer harness work. It does not yet exist as the user's product. The desktop's default object is still a dashboard or repository; it should be a verification case.
-
-The focused job should be:
-
-> Given a task and an agent-authored change, did it actually work? Show the executable evidence, state what remains unverified, and make the result reproducible.
-
-Comparative agent and context experiments are the second job, powered by the same receipts. Graph context is an experimental input, not the product.
-
-## Competition
-
-The tools initially identified are several different markets:
-
-- pgGraph and HydraDB are graph infrastructure. They are not meaningful product competitors.
-- CodeGraph, Graphify, and RepoWise are agent-readable context engines. RepoWise also spans human wiki, history, decisions, and code health, creating direct overlap with Repo Unpack.
-- DeepWiki is primarily human-readable generated documentation and grounded Q&A.
-- Sourcegraph is enterprise code search and multi-repository context.
-- CodeRabbit and Qodo compete with the legacy Review proposition and have much stronger pull-request distribution.
-- Harbor/Terminal-Bench and SWE-bench occupy coding-agent benchmark infrastructure.
-- Braintrust and LangSmith occupy general experiment, dataset, scoring, tracing, and comparison infrastructure.
-
-CodeVetter should not try to beat focused context providers at indexing, established review vendors at PR distribution, or general evaluation platforms at horizontal breadth. Its credible wedge is local, software-specific, execution-backed verification with hidden checks, immutable evidence identities, contamination detection, and reproducible comparisons.
-
-## Design Health Score
-
-| # | Heuristic | Score | Key issue |
-|---|---|---:|---|
-| 1 | Visibility of System Status | 3 | Strong local states, but no unified verification-run status across surfaces. |
-| 2 | Match System / Real World | 2 | Repo Unpack, T-Rex, warm verification, and Review with Claude obscure the core job. |
-| 3 | User Control and Freedom | 3 | Good cancellation, retry, persistence, and reversible actions; deeper exits and undo vary. |
-| 4 | Consistency and Standards | 2 | Coherent tokens, inconsistent page structures and navigation documentation. |
-| 5 | Error Prevention | 3 | Strong validation and confirmations, but advanced forms expose too many paths. |
-| 6 | Recognition Rather Than Recall | 2 | Users must remember how Repo, Review, Testing, and Work compose. |
-| 7 | Flexibility and Efficiency | 3 | Strong shortcuts, persistent state, history, and expert affordances. |
-| 8 | Aesthetic and Minimalist Design | 2 | Visually disciplined but functionally overloaded. |
-| 9 | Error Recovery | 2 | Several actionable errors, but no consistent guided recovery model. |
-| 10 | Help and Documentation | 1 | Onboarding teaches the outdated review product rather than verification evidence. |
-| **Total** | | **23/40** | **Acceptable craft; substantial product simplification required.** |
-
-## Design Specificity Verdict
-
-### Design assessment
-
-Visually authored, structurally unfocused. The dark ink and warm amber Evidence Bench language is coherent and appropriate. The app feels technically serious. But the shell presents several historical products as peers, so it reads as a consolidated suite rather than one verification instrument.
-
-### Deterministic scan
-
-The detector reported 10 `gray-on-color` findings: five in Home, three in AgentPanel, and two in QuickReview. Source inspection makes six definite false positives and the remaining four likely false positives because the backgrounds are mutually exclusive branches or very low-opacity tints over dark surfaces. The scan did not reveal a systemic mechanical design defect.
-
-This reinforces the main conclusion: the highest-impact UI problems are information architecture, terminology, and hierarchy—not Tailwind color cleanup.
-
-### Visual overlays
-
-No reliable visual overlay is available. Browser control reported no connected browser, so mutable injection and screenshots could not be performed. Five representative Vite routes returned HTTP 200, which confirms routing only, not rendered quality.
-
-## Overall Impression
-
-The strongest moments are the honest receipt and no-confidence states in Testing and Review. The weakest moment is the product entrance: onboarding teaches model selection and AI review, then the app opens on usage telemetry. A user must cross several legacy concepts before reaching the differentiated product.
-
-The biggest opportunity is not a redesign of each page. It is choosing one canonical object—`verification case`—and reorganizing everything around it.
-
-## What's Working
-
-- Honest semantic states such as partial coverage, passed with limits, and no confidence are unusually good.
-- Persistent routes, cancellation, retries, bounded output, and history show excellent operational care.
-- The ink/amber system, evidence typography, focus treatment, and written status labels are a solid craft foundation worth preserving.
-
-## Priority Issues
-
-### P0 — The visible product contradicts the stated product
-
-**Why it matters:** The repo says CLI/MCP verification is primary and desktop is a receipt viewer. The app leads with Usage, Repo Unpack, Work, Board, Review, and Testing. The landing page still sells a desktop AI reviewer and makes claims about vulnerability classes and offline behavior. Users cannot form a stable expectation.
-
-**Fix:** Pick the verification product explicitly. Rewrite landing, onboarding, navigation, and the default route around one verification case. Remove unsupported claims and demote unrelated surfaces.
-
-**Suggested command:** `$impeccable shape`
-
-### P1 — The shell contradicts the core loop
-
-**Why it matters:** Launching into usage telemetry makes administration feel more important than determining whether a change is correct. Work and Board are agent-control products placed inside Verification.
-
-**Fix:** Use a minimal shell such as Verify, Runs, Experiments, and Settings. Put repository context inside a case; move Usage, Work, Board, and Agent Island to Labs/Legacy or remove them from primary navigation.
-
-**Suggested command:** `$impeccable distill`
-
-### P1 — Review and Testing split one user question across two products
-
-**Why it matters:** A user asks whether a change is correct. Review emphasizes model findings; Testing owns the strongest executable receipts. The user must mentally merge them.
-
-**Fix:** Model a verification case with stages: target and intent, checks, findings, runtime evidence, verdict, limitations, and next action.
-
-**Suggested command:** `$impeccable shape`
-
-### P1 — Results bury the verdict beneath accumulated features
-
-**Why it matters:** Review's sidebar contains roughly a dozen evidence, graph, QA, export, and audience systems. Equal visual weight makes source-backed limitations and next actions hard to locate.
-
-**Fix:** Pin verdict, evidence strength, limitations, and next action. Move graphs, audience simulation, X-Ray, synthetic QA, and exports behind secondary disclosure.
-
-**Suggested command:** `$impeccable distill`
-
-### P1 — Onboarding installs the wrong mental model
-
-**Why it matters:** It teaches model selection, usage stats, and AI review instead of task completion and executable proof.
-
-**Fix:** First run should select a repository/change, run one bounded check, and teach how to read a receipt, failure, and limitation.
-
-**Suggested command:** `$impeccable onboard`
-
-### P2 — Dense evidence presentation strains accessibility
-
-**Why it matters:** Critical context is often 9–11px and muted; dense sidebars create long keyboard paths.
-
-**Fix:** Increase essential evidence metadata size and contrast, simplify result order, and confirm effective runtime contrast visually.
-
-**Suggested command:** `$impeccable audit`
-
-## Cognitive Load
-
-High: seven of eight checklist areas fail. Grouping is generally good, but single focus, chunking, hierarchy, one-thing-at-a-time flow, minimal choices, working-memory burden, and progressive disclosure do not.
-
-Decision points above four include:
-
-- six primary destinations plus Settings and command search;
-- up to eight Repo Unpack sections;
-- eleven Settings categories;
-- roughly a dozen Review result-side modules; and
-- seven setup concepts inside expanded Review context.
-
-## Emotional Journey
-
-The user expects verification, encounters usage administration, becomes uncertain about which surface owns the task, then finally reaches excellent evidence language in Testing. The product peaks late and ends without one calm closure: verified, failed, or no confidence, followed by the next safe action.
-
-## Persona Red Flags
-
-**Alex, power user:** Strong shortcuts and persistent state do not answer whether the same change belongs in Repo, Review, or Testing. A trustworthy evaluation in under a minute is unlikely.
-
-**Jordan, first-timer:** Usage telemetry and AI-review onboarding create the wrong model before they encounter Repo Unpack, T-Rex, warm verification, and scenario compilation.
-
-**Sam, keyboard/low-vision user:** Focus and reduced-motion support are positive, but tiny muted evidence text and the long Review sidebar journey reduce practical accessibility.
-
-## Minor Observations
-
-- Design and surface documentation describe a top rail while implementation uses a fixed left rail.
-- Board has a keyboard shortcut but is absent from the command palette.
-- Page-title structures differ substantially by route.
-- T-Rex is internal-history branding, not self-explanatory product language.
-- The sidebar subtitle Evidence workbench is good; the rest of the IA does not yet fulfill it.
-- The four largest page files total roughly 14,900 lines, mirroring feature and state accumulation in the user experience.
-
-## Questions to Consider
-
-- If Usage, Work, Board, Agent Island, and most Repo Unpack sections disappeared from primary navigation, would the actual verification product lose anything essential?
-- Why are Review and Testing separate when the user asks one question: is this change correct?
-- Does a panel change the verdict or explain its confidence? If not, why is it in the primary result view?
-- Is CodeVetter a daily verification tool, an evaluation research lab, or a broad agent workbench? It cannot lead with all three.
diff --git a/.impeccable/critique/2026-08-10T18-31-57Z__apps-desktop-src-pages-home-tsx.md b/.impeccable/critique/2026-08-10T18-31-57Z__apps-desktop-src-pages-home-tsx.md
deleted file mode 100644
index 6e31755f..00000000
--- a/.impeccable/critique/2026-08-10T18-31-57Z__apps-desktop-src-pages-home-tsx.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-target: Usage telemetry evidence tiers
-total_score: 36
-max_score: 40
-na_heuristics:
-p0_count: 0
-p1_count: 0
-timestamp: 2026-08-10T18-31-57Z
-slug: apps-desktop-src-pages-home-tsx
----
-## Design Health Score
-
-| # | Heuristic | Score | Key issue |
-|---|---|---:|---|
-| 1 | Visibility of system status | 4 | Verified, partial, stale, pending, and loading states are written explicitly. |
-| 2 | Match system / real world | 3 | API-equivalent remains specialist language, now explained as not subscription spend. |
-| 3 | User control and freedom | 4 | Reconcile and recovery settings are available at the diagnosis. |
-| 4 | Consistency and standards | 4 | One reconciliation verb now owns the refresh path. |
-| 5 | Error prevention | 4 | Legacy, ambiguous, stale, and unpriced data cannot masquerade as verified. |
-| 6 | Recognition rather than recall | 4 | Recovery settings are linked in context. |
-| 7 | Flexibility and efficiency | 3 | Aggregate categories are not yet drillable to individual sources. |
-| 8 | Aesthetic and minimalist design | 4 | Evidence hierarchy is compact and uses the incumbent workbench language. |
-| 9 | Error recovery | 3 | Recovery is complete, but source-level diagnostics remain aggregate. |
-| 10 | Help and documentation | 3 | Inline pricing and recovery explanations cover the main uncertainty model. |
-| **Total** | | **36/40** | **Excellent** |
-
-## Design Specificity Verdict
-
-The result is authored for CodeVetter's Evidence Bench. Accepted transcript observations,
-scanner revision, observation watermark, exact/ranged/unpriced pricing, and explicit legacy
-exclusion make the surface an evidence instrument rather than a generic analytics card.
-
-The deterministic detector returned five `gray-on-color` warnings in Home.tsx and none in
-Settings.tsx. All five are contextual false positives: the background is translucent over ink or
-the slate text classes are mutually exclusive with the cyan active state. Verified detector issue
-count: zero.
-
-## Overall Impression
-
-The trusted number leads, uncertainty is written rather than hidden, and recovery is attached to
-the diagnosis. The remaining opportunity is source/session drill-down, not another visual layer.
-
-## What's Working
-
-- Verified totals and legacy estimates are structurally separated.
-- Cost bounds explain unknown service tier and disclaim subscription spend.
-- Recovery is one bounded flow: import roots, then re-index and reconcile.
-
-## Priority Issues
-
-- **P2 — Aggregate diagnostics are not drillable.** Users can see affected counts but not the
- source identities. Add a source-detail disclosure after the read cutover is qualified.
-- **P3 — Narrow screenshots compress below the product contract.** The Tauri app enforces a 900px
- minimum; 390px is retained as evidence but is not a supported window state.
-
-## Persona Red Flags
-
-- **Alex:** source-level evidence is not yet inspectable from the aggregate.
-- **Sam:** the cost range is now explicitly API-equivalent and not subscription spend; written
- partial coverage does not rely on color.
-- **Riley:** import persistence failures are announced and the recovery action returns to a single
- reconciliation path.
-
-## Minor Observations
-
-- Legacy period estimates remain expanded for continuity; a later release may collapse them once
- users have migrated to verified reads.
-- The app's documented and configured minimum width is 900px, so mobile-shell adaptation is out of
- scope for this macOS desktop viewer.
-
-## Questions to Consider
-
-- Should the next qualified iteration expose the exact sessions behind each unresolved tier?
-- Once verified coverage stabilizes, should the legacy blended summary become collapsed by default?
diff --git a/.impeccable/critique/2026-08-15T20-33-20Z__apps-desktop-src-components-app-error-boundary-tsx.md b/.impeccable/critique/2026-08-15T20-33-20Z__apps-desktop-src-components-app-error-boundary-tsx.md
deleted file mode 100644
index 3c800eac..00000000
--- a/.impeccable/critique/2026-08-15T20-33-20Z__apps-desktop-src-components-app-error-boundary-tsx.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-target: apps/desktop/src/components/app-error-boundary.tsx
-total_score: 35
-maximum: 40
-p0: 0
-p1: 0
-p2: 1
-method: dual-agent
-timestamp: 2026-08-15T20-33-20Z
-slug: apps-desktop-src-components-app-error-boundary-tsx
----
-# CodeVetter crash recovery critique
-
-## Method
-
-Dual-agent review: a detector-blind visual/heuristic assessment plus an independent detector and responsive-browser evidence pass. The final state was then rechecked at 390, 768, and 1440 px after resolving the review findings.
-
-## Nielsen assessment — 35/40
-
-| Heuristic | Score | Final assessment |
-| --- | ---: | --- |
-| Visibility of system status | 3 | The interruption, local receipt, and copy status are explicit; repeated retry has no attempt counter. |
-| Match to the real world | 4 | Scope-aware language and plain recovery actions describe what happened and what each action does. |
-| User control and freedom | 3 | Retry, reload, and Usage escape cover the common exits; Usage remains a best-effort app route. |
-| Consistency and standards | 4 | Uses the established ink surface, amber action, semantic rose state, type, buttons, and focus treatment. |
-| Error prevention | 3 | The boundary contains the failure and avoids unsupported safety claims; it does not add a repeated-failure safe mode. |
-| Recognition over recall | 4 | Actions are visible and retry/reload behavior is stated directly. |
-| Flexibility and efficiency | 3 | Keyboard recovery and copyable diagnostics are available without exposing raw details by default. |
-| Aesthetic and minimalist design | 4 | The hierarchy stays focused: interruption, recovery, then local evidence. |
-| Error recognition and recovery | 4 | Scope, three recovery routes, incident identity, and technical evidence are all visible. |
-| Help and documentation | 3 | Technical details support reporting, but no dedicated troubleshooting route is present. |
-
-## Cognitive load — 8/8
-
-The surface has one focus, three clearly grouped recovery choices, a short behavioral explanation, and progressive disclosure for diagnostics. No decision point exceeds four choices.
-
-## Accessibility and responsive evidence
-
-- Focus moves to the recovery heading on mount; the next Tab reaches the primary recovery action.
-- The full-page alert was narrowed to the interruption announcement, leaving controls outside the live alert.
-- Muted metadata uses the higher-contrast zinc-400 token.
-- Axe reported no critical or serious violations in the focused Playwright check.
-- Document scroll width matched client width at 390, 768, and 1440 px.
-
-## Findings resolved
-
-- **P1 resolved:** removed the categorical claim that the repository was unmodified. The UI now states that repository state was not checked.
-- **P1 resolved:** application-shell failures now always expose a Return to Usage action in addition to retry and reload.
-- **P2 resolved:** recovery takes focus, metadata contrast was raised, and retry versus reload behavior is explained.
-
-## Remaining advisory item
-
-- **P2:** if the same render failure repeats, the surface does not yet count attempts or escalate to a dedicated safe mode. This is a future reliability enhancement, not a blocker for the bounded recovery layer.
-
-## Detector and integrity
-
-The advisory detector returned an empty result (`[]`) across the recovery component and entry point. No production dependency was added, raw error messages and stacks are not persisted, and repository/query data is excluded from the local incident receipt.
diff --git a/.impeccable/critique/2026-08-15T21-39-48Z__apps-desktop-src-pages-performance-tsx.md b/.impeccable/critique/2026-08-15T21-39-48Z__apps-desktop-src-pages-performance-tsx.md
deleted file mode 100644
index 3e1f0590..00000000
--- a/.impeccable/critique/2026-08-15T21-39-48Z__apps-desktop-src-pages-performance-tsx.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-timestamp: 2026-08-15T21-39-48Z
-slug: apps-desktop-src-pages-performance-tsx
----
-# Performance workbench critique
-
-Target: `apps/desktop/src/pages/Performance.tsx`
-
-## Outcome
-
-- Design heuristic score: 35/40 (good, near excellent).
-- Automated detector: 0 findings.
-- Responsive qualification: no horizontal overflow at 390, 768, or 1440 px.
-- Accessibility structure: one main landmark, labelled workload controls, labelled evidence region, and accessible form names.
-- Final severity: 0 P0, 0 P1.
-
-## Resolved during critique
-
-- Added a real same-scope paired-verification action and verdict-driven campaign states.
-- Invalidated stale evidence when scope fields or the selected repository change.
-- Cancelled and discarded late receipts from a prior repository generation.
-- Added truthful blocked, failed, and no-confidence recovery states.
-- Separated observed, inferred, and unverified evidence without truncating captured rows.
-- Raised low-contrast operational copy and removed empty machine-detail rows.
-
-## Evidence
-
-- `artifacts/design/product-surfaces-after-390.jpg`
-- `artifacts/design/product-surfaces-after-768.jpg`
-- `artifacts/design/product-surfaces-after-1440.jpg`
diff --git a/.impeccable/design.json b/.impeccable/design.json
deleted file mode 100644
index ad45e6cb..00000000
--- a/.impeccable/design.json
+++ /dev/null
@@ -1,212 +0,0 @@
-{
- "schemaVersion": 2,
- "generatedAt": "2026-07-29T00:00:00.000Z",
- "title": "Design System: CodeVetter",
- "extensions": {
- "colorMeta": {
- "canvas-ink": {
- "role": "neutral",
- "displayName": "Canvas Ink",
- "canonical": "#060708",
- "tonalRamp": [
- "#060708",
- "#0c0d0f",
- "#111316",
- "#17191d",
- "#35383e",
- "#6c7078",
- "#a1a1aa",
- "#f4f4f5"
- ]
- },
- "action-amber": {
- "role": "primary",
- "displayName": "Action Amber",
- "canonical": "#f3ad3d",
- "tonalRamp": [
- "#2a1b05",
- "#4b3008",
- "#71490d",
- "#9b6818",
- "#c88728",
- "#f3ad3d",
- "#ffc75e",
- "#fff0c7"
- ]
- },
- "failure-rose": {
- "role": "semantic",
- "displayName": "Failure Rose",
- "canonical": "#fb7185",
- "tonalRamp": [
- "#2e080e",
- "#54121d",
- "#7f2030",
- "#aa3448",
- "#d94f65",
- "#fb7185",
- "#fda4af",
- "#ffe4e6"
- ]
- },
- "verified-green": {
- "role": "semantic",
- "displayName": "Verified Green",
- "canonical": "#4ade80",
- "tonalRamp": [
- "#052e16",
- "#14532d",
- "#166534",
- "#15803d",
- "#22c55e",
- "#4ade80",
- "#86efac",
- "#dcfce7"
- ]
- }
- },
- "typographyMeta": {
- "title": {
- "displayName": "Workbench Title",
- "purpose": "Page, panel, and evidence-section headings."
- },
- "body": {
- "displayName": "Operating Body",
- "purpose": "Instructions, summaries, and supporting context."
- },
- "label": {
- "displayName": "Compact Label",
- "purpose": "Fields, controls, metrics, and metadata."
- },
- "evidence": {
- "displayName": "Evidence Mono",
- "purpose": "Paths, revisions, commands, and machine identities."
- }
- },
- "shadows": [
- {
- "name": "surface-ambient",
- "value": "0 28px 80px -52px rgba(0, 0, 0, 0.92)",
- "purpose": "Diffuse depth for major cards and overlays."
- },
- {
- "name": "action-warm",
- "value": "0 12px 30px -18px rgba(243, 173, 61, 0.9)",
- "purpose": "Restrained emphasis for primary action controls."
- }
- ],
- "motion": [
- {
- "name": "control-state",
- "value": "150ms ease",
- "purpose": "Color, border, shadow, and pressed-state transitions."
- },
- {
- "name": "content-enter",
- "value": "200ms ease-out",
- "purpose": "Short opacity and 4px translate entrance for newly available content."
- }
- ],
- "breakpoints": [
- {
- "name": "sm",
- "value": "640px"
- },
- {
- "name": "lg",
- "value": "1024px"
- },
- {
- "name": "desktop-window-min",
- "value": "900px"
- }
- ]
- },
- "components": [
- {
- "name": "Primary Button",
- "kind": "button",
- "refersTo": "button-primary",
- "description": "The single intentional action within a verification context.",
- "html": "",
- "css": ".ds-button-primary { height: 40px; padding: 8px 16px; border: 1px solid rgba(253,230,138,.2); border-radius: 10px; background: var(--cv-accent, #f3ad3d); color: #211609; font: 500 14px/1.25 -apple-system,BlinkMacSystemFont,\"SF Pro Text\",sans-serif; box-shadow: 0 12px 30px -18px rgba(243,173,61,.9), inset 0 1px 0 rgba(255,255,255,.3); transition: background-color 150ms ease, transform 150ms ease; } .ds-button-primary:hover { background: var(--cv-accent-strong, #ffc75e); } .ds-button-primary:focus-visible { outline: 2px solid rgba(243,173,61,.88); outline-offset: 2px; } .ds-button-primary:active { transform: translateY(1px); }"
- },
- {
- "name": "Outline Button",
- "kind": "button",
- "refersTo": "button-outline",
- "description": "A bounded secondary action that does not compete with execution.",
- "html": "",
- "css": ".ds-button-outline { height: 40px; padding: 8px 16px; border: 1px solid rgba(255,255,255,.11); border-radius: 10px; background: rgba(255,255,255,.035); color: #e4e4e7; font: 500 14px/1.25 -apple-system,BlinkMacSystemFont,\"SF Pro Text\",sans-serif; box-shadow: inset 0 1px 0 rgba(255,255,255,.04); transition: background-color 150ms ease, border-color 150ms ease; } .ds-button-outline:hover { border-color: rgba(255,255,255,.18); background: rgba(255,255,255,.075); color: #fff; } .ds-button-outline:focus-visible { outline: 2px solid rgba(243,173,61,.88); outline-offset: 2px; }"
- },
- {
- "name": "Evidence Input",
- "kind": "input",
- "refersTo": "input",
- "description": "A compact field for URLs, ranges, and verification parameters.",
- "html": "",
- "css": ".ds-input { width: 100%; height: 40px; padding: 8px 12px; border: 1px solid rgba(255,255,255,.1); border-radius: 10px; background: rgba(255,255,255,.035); color: #f4f4f5; font: 400 14px/1.5 -apple-system,BlinkMacSystemFont,\"SF Pro Text\",sans-serif; box-shadow: inset 0 1px 0 rgba(255,255,255,.025); transition: background-color 150ms ease, border-color 150ms ease, box-shadow 150ms ease; } .ds-input:hover { border-color: rgba(255,255,255,.15); } .ds-input:focus-visible { outline: 2px solid rgba(243,173,61,.15); outline-offset: 2px; border-color: rgba(252,211,77,.35); background: rgba(255,255,255,.05); }"
- },
- {
- "name": "Verification Card",
- "kind": "card",
- "refersTo": "card",
- "description": "The primary workbench plane for one verification mechanism.",
- "html": "
Test change in preview
Resolve exact source identity and return browser evidence.
",
- "css": ".ds-card { padding: 20px; border: 1px solid rgba(255,255,255,.075); border-radius: 12px; background: var(--cv-surface, #0c0d0f); color: #f4f4f5; box-shadow: 0 24px 70px -50px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.025); } .ds-card h3 { margin: 0; font: 600 18px/1.25 \"SF Pro Display\",-apple-system,sans-serif; letter-spacing: -.018em; } .ds-card p { margin: 6px 0 0; color: #a1a1aa; font: 400 14px/1.5 -apple-system,BlinkMacSystemFont,\"SF Pro Text\",sans-serif; }"
- },
- {
- "name": "Evidence Badge",
- "kind": "chip",
- "refersTo": "badge",
- "description": "A written status or scope qualifier paired with semantic color.",
- "html": "Passed with limits",
- "css": ".ds-badge { display: inline-flex; min-height: 24px; align-items: center; padding: 4px 10px; border: 1px solid rgba(252,211,77,.2); border-radius: 9999px; background: rgba(252,211,77,.1); color: #fde68a; font: 500 12px/1 -apple-system,BlinkMacSystemFont,\"SF Pro Text\",sans-serif; transition: background-color 150ms ease; } .ds-badge:hover { background: rgba(252,211,77,.16); } .ds-badge:focus-visible { outline: 2px solid rgba(243,173,61,.88); outline-offset: 2px; }"
- }
- ],
- "narrative": {
- "northStar": "The Evidence Bench",
- "overview": "CodeVetter feels like a precise local instrument: dark, quiet, dense enough for technical work, and candid about the strength of every claim. Warm amber marks the next intentional action. Semantic colors communicate verified, warning, or failure states only when the same meaning is also written in text or expressed with an icon. The interface should recede behind source identities, runtime results, and limitations.",
- "keyCharacteristics": [
- "Ink surfaces separated by restrained tonal steps and hairline borders.",
- "Compact native-feeling controls with generous focus treatment.",
- "Warm amber used sparingly for action, selection, and verification emphasis.",
- "Monospace reserved for paths, revisions, commands, and evidence identities.",
- "Every state remains understandable without color alone."
- ],
- "rules": [
- {
- "name": "The One Warm Voice Rule",
- "body": "Amber identifies intentional action or active verification context; it is not ambient decoration.",
- "section": "colors"
- },
- {
- "name": "The Written State Rule",
- "body": "Green, gold, rose, and blue may reinforce meaning, but a label or icon must communicate the same state.",
- "section": "colors"
- },
- {
- "name": "The Evidence Type Rule",
- "body": "Monospace signals data a user may compare, copy, or feed to another tool; prose and actions stay in the system sans.",
- "section": "typography"
- },
- {
- "name": "The Flat Evidence Rule",
- "body": "Evidence rows are stable nested planes; hover lift and decorative transform are reserved for actionable controls.",
- "section": "elevation"
- }
- ],
- "dos": [
- "Do lead with the action, exact identity, verdict, and limitation.",
- "Do reuse the established card, input, button, badge, and focus patterns.",
- "Do keep verification forms compact and preserve evidence below the action.",
- "Do provide loading, empty, error, limited, failed, and no-confidence states with plain-language labels."
- ],
- "donts": [
- "Don't present model opinion, topology, or a fixture as executable proof.",
- "Don't use amber across large decorative regions or for non-action accents.",
- "Don't communicate pass, warning, or failure through color alone.",
- "Don't add floating glass cards, hero typography, or agent theater to operating surfaces."
- ]
- }
-}
diff --git a/research/codebase-context-tools-landscape.md b/docs/knowledge/codebase-context-tools-landscape.md
similarity index 99%
rename from research/codebase-context-tools-landscape.md
rename to docs/knowledge/codebase-context-tools-landscape.md
index 167f1dc1..488b3574 100644
--- a/research/codebase-context-tools-landscape.md
+++ b/docs/knowledge/codebase-context-tools-landscape.md
@@ -1,3 +1,10 @@
+---
+title: Codebase context tools landscape
+description: Survey of codebase indexing, context-provider, and documentation tools evaluated for CodeVetter (research snapshot, April 2026).
+sidebar:
+ order: 90
+---
+
# Codebase Context Tools for AI Agents & AI Code Review
## Complete Landscape Research - April 2026
From 3de2b4941d1498a66fa21869e4fc2af0b0586008 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 13:40:26 +0530
Subject: [PATCH 03/37] refactor(benchmarks): fold the public corpus into one
benchmarks/ root
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
benchmark/ and benchmarks/ differed by a single character while holding
different things: the public hand-labeled catch-rate corpus, and the internal
evaluation corpora (agent-prs, agent-tasks, runtime-challenges, context-*,
performance-lab). Move the former to benchmarks/public-catch-rate/ so there is
one corpus root and no singular/plural ambiguity.
The published surface is unchanged. scripts/generate-benchmark-dataset.mjs
still emits apps/landing-page-astro/public/benchmark/codevetter-benchmark-v1.json
and the site still serves /benchmark/... — only the repo-root source directory
moved. Verified: pnpm bench:public scores all 27 cases from the new path, the
generator reads it, and the Astro build produces all 24 pages.
Deliberately not rewritten: the pinned-SHA GitHub raw URLs in Bento.astro
(they resolve against commit 006c2e5c, where the old path still exists), the
public /benchmark/ URLs in agent-markdown.ts and benchmark.astro, and
docs/development/performance.md's --target benchmark/parser.mjs, which is an
unrelated perf example rather than the corpus.
Co-Authored-By: Claude Opus 5 (1M context)
---
PROJECT_STATUS.md | 4 ++--
apps/desktop/src-tauri/src/commands/review.rs | 4 ++--
apps/landing-page-astro/src/pages/benchmark.astro | 4 ++--
{benchmark => benchmarks/public-catch-rate}/README.md | 8 ++++----
.../public-catch-rate}/cases/go-errcheck/label.json | 0
.../public-catch-rate}/cases/go-errcheck/source.go | 0
.../cases/go-hardcoded-credentials/label.json | 0
.../cases/go-hardcoded-credentials/source.go | 0
.../public-catch-rate}/cases/go-nil-pointer/label.json | 0
.../public-catch-rate}/cases/go-nil-pointer/source.go | 0
.../cases/go-race-condition/label.json | 0
.../cases/go-race-condition/source.go | 0
.../cases/go-sql-injection/label.json | 0
.../cases/go-sql-injection/source.go | 0
.../cases/java-insecure-random/label.json | 0
.../cases/java-insecure-random/source.java | 0
.../cases/js-eval-injection/label.json | 0
.../cases/js-eval-injection/source.js | 0
.../cases/js-open-redirect/label.json | 0
.../cases/js-open-redirect/source.js | 0
.../public-catch-rate}/cases/py-bare-except/label.json | 0
.../public-catch-rate}/cases/py-bare-except/source.py | 0
.../cases/py-command-injection/label.json | 0
.../cases/py-command-injection/source.py | 0
.../cases/py-hardcoded-secret/label.json | 0
.../cases/py-hardcoded-secret/source.py | 0
.../cases/py-insecure-deserialization/label.json | 0
.../cases/py-insecure-deserialization/source.py | 0
.../cases/py-path-traversal/label.json | 0
.../cases/py-path-traversal/source.py | 0
.../cases/py-sql-injection/label.json | 0
.../cases/py-sql-injection/source.py | 0
.../public-catch-rate}/cases/py-ssrf/label.json | 0
.../public-catch-rate}/cases/py-ssrf/source.py | 0
.../public-catch-rate}/cases/py-weak-hash/label.json | 0
.../public-catch-rate}/cases/py-weak-hash/source.py | 0
.../public-catch-rate}/cases/py-zip-bomb/label.json | 0
.../public-catch-rate}/cases/py-zip-bomb/source.py | 0
.../cases/rust-integer-overflow/label.json | 0
.../cases/rust-integer-overflow/source.rs | 0
.../public-catch-rate}/cases/ts-dead-code/label.json | 0
.../public-catch-rate}/cases/ts-dead-code/source.ts | 0
.../cases/ts-hardcoded-credentials/label.json | 0
.../cases/ts-hardcoded-credentials/source.ts | 0
.../cases/ts-insecure-cookie/label.json | 0
.../cases/ts-insecure-cookie/source.ts | 0
.../cases/ts-missing-await/label.json | 0
.../cases/ts-missing-await/source.ts | 0
.../cases/ts-prototype-pollution/label.json | 0
.../cases/ts-prototype-pollution/source.ts | 0
.../public-catch-rate}/cases/ts-regex-dos/label.json | 0
.../public-catch-rate}/cases/ts-regex-dos/source.ts | 0
.../cases/ts-sql-injection/label.json | 0
.../cases/ts-sql-injection/source.ts | 0
.../cases/ts-type-confusion/label.json | 0
.../cases/ts-type-confusion/source.ts | 0
.../public-catch-rate}/cases/ts-xss/label.json | 0
.../public-catch-rate}/cases/ts-xss/source.tsx | 0
.../reviews-raw/go-errcheck.codevetter.raw.json | 0
.../go-hardcoded-credentials.codevetter.raw.json | 0
.../reviews-raw/go-nil-pointer.codevetter.raw.json | 0
.../reviews-raw/go-race-condition.codevetter.raw.json | 0
.../reviews-raw/go-sql-injection.codevetter.raw.json | 0
.../java-insecure-random.codevetter.raw.json | 0
.../reviews-raw/js-eval-injection.codevetter.raw.json | 0
.../reviews-raw/js-open-redirect.codevetter.raw.json | 0
.../reviews-raw/py-bare-except.codevetter.raw.json | 0
.../py-command-injection.codevetter.raw.json | 0
.../py-hardcoded-secret.codevetter.raw.json | 0
.../py-insecure-deserialization.codevetter.raw.json | 0
.../reviews-raw/py-path-traversal.codevetter.raw.json | 0
.../reviews-raw/py-sql-injection.codevetter.raw.json | 0
.../reviews-raw/py-ssrf.codevetter.raw.json | 0
.../reviews-raw/py-weak-hash.codevetter.raw.json | 0
.../reviews-raw/py-zip-bomb.codevetter.raw.json | 0
.../rust-integer-overflow.codevetter.raw.json | 0
.../reviews-raw/ts-dead-code.codevetter.raw.json | 0
.../ts-hardcoded-credentials.codevetter.raw.json | 0
.../reviews-raw/ts-insecure-cookie.codevetter.raw.json | 0
.../reviews-raw/ts-missing-await.codevetter.raw.json | 0
.../ts-prototype-pollution.codevetter.raw.json | 0
.../reviews-raw/ts-regex-dos.codevetter.raw.json | 0
.../reviews-raw/ts-sql-injection.codevetter.raw.json | 0
.../reviews-raw/ts-type-confusion.codevetter.raw.json | 0
.../reviews-raw/ts-xss.codevetter.raw.json | 0
biome.json | 2 +-
docs/development/benchmark.md | 2 +-
docs/operations/automation-contract.md | 2 +-
docs/product/overview.md | 2 +-
scripts/generate-benchmark-dataset.mjs | 2 +-
scripts/map-benchmark-reviews.mjs | 4 ++--
scripts/run-public-benchmark.mjs | 10 +++++-----
92 files changed, 22 insertions(+), 22 deletions(-)
rename {benchmark => benchmarks/public-catch-rate}/README.md (95%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-errcheck/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-errcheck/source.go (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-hardcoded-credentials/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-hardcoded-credentials/source.go (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-nil-pointer/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-nil-pointer/source.go (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-race-condition/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-race-condition/source.go (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-sql-injection/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/go-sql-injection/source.go (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/java-insecure-random/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/java-insecure-random/source.java (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/js-eval-injection/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/js-eval-injection/source.js (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/js-open-redirect/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/js-open-redirect/source.js (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-bare-except/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-bare-except/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-command-injection/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-command-injection/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-hardcoded-secret/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-hardcoded-secret/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-insecure-deserialization/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-insecure-deserialization/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-path-traversal/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-path-traversal/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-sql-injection/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-sql-injection/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-ssrf/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-ssrf/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-weak-hash/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-weak-hash/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-zip-bomb/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/py-zip-bomb/source.py (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/rust-integer-overflow/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/rust-integer-overflow/source.rs (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-dead-code/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-dead-code/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-hardcoded-credentials/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-hardcoded-credentials/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-insecure-cookie/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-insecure-cookie/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-missing-await/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-missing-await/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-prototype-pollution/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-prototype-pollution/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-regex-dos/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-regex-dos/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-sql-injection/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-sql-injection/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-type-confusion/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-type-confusion/source.ts (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-xss/label.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/cases/ts-xss/source.tsx (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/go-errcheck.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/go-hardcoded-credentials.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/go-nil-pointer.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/go-race-condition.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/go-sql-injection.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/java-insecure-random.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/js-eval-injection.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/js-open-redirect.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-bare-except.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-command-injection.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-hardcoded-secret.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-insecure-deserialization.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-path-traversal.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-sql-injection.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-ssrf.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-weak-hash.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/py-zip-bomb.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/rust-integer-overflow.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-dead-code.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-hardcoded-credentials.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-insecure-cookie.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-missing-await.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-prototype-pollution.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-regex-dos.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-sql-injection.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-type-confusion.codevetter.raw.json (100%)
rename {benchmark => benchmarks/public-catch-rate}/reviews-raw/ts-xss.codevetter.raw.json (100%)
diff --git a/PROJECT_STATUS.md b/PROJECT_STATUS.md
index 2275663f..a38d40a9 100644
--- a/PROJECT_STATUS.md
+++ b/PROJECT_STATUS.md
@@ -397,7 +397,7 @@ Internal (fleet):
- **2026-07-03 — Surface consolidation + finishes (multi-agent pass):** removed redundant standalone pages QaReplay (`/qa-replay`) and IntentDebugger (`/intent-debugger`) — their functionality lives in Review. Finished Rubrics (review↔pack linkage via `local_reviews.standards_pack`, exact prompt preview, per-pack usage stats, pack cloning), T-Rex (per-watcher error recovery + retry, run drill-down dialog with persisted findings/log excerpt, pre-flight gh/token validation, per-PR base-branch inference), and AgentMemories (copy-as-markdown export, substring//regex/ line filter, git-diff-vs-HEAD view with secret redaction). Refactored QuickReview.tsx 6,264→3,050 lines into 12 components + 4 lib modules (behavior-preserving, 15 commits). Raw-Claude baseline scored on the 27 public benchmark cases (catch 0.931 / precision 0.397 / F1 0.557); CodeVetter's own comparator slot still needs generation before head-to-head claims.
- **2026-07-03 (shipped in v1.2.8) — By-model cost attribution fix:** session-level `model_used` is last-model-wins, so multi-model Claude sessions booked ALL tokens/cost to the final model (a 211MB session with 17k opus-4-7 messages + 1.6k fable-5 messages billed $3.6k entirely to fable). Fix: per-message `session_model_usage` table populated by the indexer + one-time streaming backfill over existing Claude JSONL; by-model panel and per-session costs now sum per-model parts. Also added Fable/Mythos 5 pricing ($10/$50; was falling to sonnet default), folded `` into "unknown", and removed the Top-projects cost panel from Home (with its query/command/IPC). Verified by replaying the fix over the live DB: opus-4-7 $21,986→$29,473 (was under-credited), fable-5 correctly repriced. Guarded by `multi_model_claude_session_splits_usage_per_model`.
- **2026-07-03:** Removed legacy Next.js landing page (`apps/landing-page`) — fully superseded by Astro site; `next-env.d.ts` git-removed, stale doc references cleaned up.
-- **2026-07-03:** Published 27 hand-labeled public benchmark cases (`benchmark/cases/`) covering 7 languages (TypeScript, Python, Go, Rust, JavaScript, Java) and 15+ vulnerability types (SQL injection, XSS, hardcoded secrets, race conditions, path traversal, SSRF, prototype pollution, regex DoS, zip bombs, etc.). Scorer script (`scripts/run-public-benchmark.mjs`) validates labels and computes catch-rate/precision/F1 per reviewer. `pnpm bench:public`. Enterprise claims now backed by external, repeatable proof.
+- **2026-07-03:** Published 27 hand-labeled public benchmark cases (`benchmarks/public-catch-rate/cases/`) covering 7 languages (TypeScript, Python, Go, Rust, JavaScript, Java) and 15+ vulnerability types (SQL injection, XSS, hardcoded secrets, race conditions, path traversal, SSRF, prototype pollution, regex DoS, zip bombs, etc.). Scorer script (`scripts/run-public-benchmark.mjs`) validates labels and computes catch-rate/precision/F1 per reviewer. `pnpm bench:public`. Enterprise claims now backed by external, repeatable proof.
- **2026-07-02/03:** Streamlined telemetry + fleet navigation, guarded manual deploy command in CI, polished repo intelligence evidence surfaces.
- **2026-06-28:** Devin agent indexing, agent hide/show filter, Grok parser improvements; PROJECT_STATUS audited as source of truth.
- **2026-06-21 (v1.1.99) — Codex cost over-count fix:** Codex reports session-CUMULATIVE token totals; the incremental indexer was ADDING that running total every pass, inflating one session to 61.5B tokens / $35k (true: 391M / ~$220) and making "today" read ~$12.9k. Fix: `tokens_absolute` flag so cumulative tokens are SET not added, plus a one-time `fix_codex_token_totals` repair re-reading each Codex file. Verified on a live-DB copy: today $12,896→$377, year $82k→$38k (Claude cache-read costs, which are real, dominate the remainder). Guarded by `eval_append_delta_sets_cumulative_tokens_but_adds_per_message`.
@@ -471,7 +471,7 @@ Internal (fleet):
The corpus passes its contract-readiness publication gates; it does not by
itself establish agent quality, provider superiority, or product value.
- `--evidence-comparison=with:without` mode compares stored outputs with and without deterministic evidence search.
-- 27 hand-labeled public benchmark cases (`benchmark/cases/`) covering 7 languages and 15+ vulnerability types; `pnpm bench:public` scores catch-rate/precision/F1.
+- 27 hand-labeled public benchmark cases (`benchmarks/public-catch-rate/cases/`) covering 7 languages and 15+ vulnerability types; `pnpm bench:public` scores catch-rate/precision/F1.
### Evidence Pattern Search
- Deterministic risk candidate packets from changed files, sensitive paths, optional `ast-grep` structural matches, blast/history context, and verification signals; top candidates and procedure gates injected into review prompts.
diff --git a/apps/desktop/src-tauri/src/commands/review.rs b/apps/desktop/src-tauri/src/commands/review.rs
index e4feff91..9ad461a6 100644
--- a/apps/desktop/src-tauri/src/commands/review.rs
+++ b/apps/desktop/src-tauri/src/commands/review.rs
@@ -3495,9 +3495,9 @@ mod tests {
use super::*;
/// Generate CodeVetter's public-benchmark comparator outputs by running
- /// every `benchmark/cases//` through the REAL production review
+ /// every `benchmarks/public-catch-rate/cases//` through the REAL production review
/// pipeline (risk tiers, specialists, coordinator, dedup) headlessly.
- /// Raw pipeline output lands in `benchmark/reviews-raw/.codevetter.raw.json`;
+ /// Raw pipeline output lands in `benchmarks/public-catch-rate/reviews-raw/.codevetter.raw.json`;
/// ground-truth mapping is a separate, human-checked step. Requires the
/// `claude` CLI on PATH and burns real quota — hence ignored.
#[test]
diff --git a/apps/landing-page-astro/src/pages/benchmark.astro b/apps/landing-page-astro/src/pages/benchmark.astro
index f5b3b17d..5e50cbc6 100644
--- a/apps/landing-page-astro/src/pages/benchmark.astro
+++ b/apps/landing-page-astro/src/pages/benchmark.astro
@@ -5,7 +5,7 @@ import Footer from '@/components/Footer.astro';
import dataset from '@/../public/benchmark/codevetter-benchmark-v1.json';
import results from '@/data/benchmark-results.json';
-// Real numbers, sourced from benchmark/cases + benchmark/reviews scored by
+// Real numbers, sourced from benchmarks/public-catch-rate/cases + .../reviews scored by
// scripts/run-public-benchmark.mjs. Regenerate with `node /tmp/gen-benchmark.mjs`
// (or the committed generator) after any case/review change.
const cv = results.codevetter;
@@ -185,7 +185,7 @@ const datasetJsonLd = {
Methodology
-
Each case lives in benchmark/cases/<id>/ with a source.<ext> and a hand-written label.json ground truth (type, severity, line range, description).
+
Each case lives in benchmarks/public-catch-rate/cases/<id>/ with a source.<ext> and a hand-written label.json ground truth (type, severity, line range, description).
A reviewer's output is normalized into reviews/<case-id>.<reviewer>.json with a matched_ground_truth array per finding.
The scorer (scripts/run-public-benchmark.mjs) computes catch rate, precision, F1, false positives, and redundant matches.
diff --git a/benchmark/README.md b/benchmarks/public-catch-rate/README.md
similarity index 95%
rename from benchmark/README.md
rename to benchmarks/public-catch-rate/README.md
index 4cdcf359..555f838b 100644
--- a/benchmark/README.md
+++ b/benchmarks/public-catch-rate/README.md
@@ -13,7 +13,7 @@ audited.
## Layout
```
-benchmark/
+benchmarks/public-catch-rate/
cases/
/
source. # the code snippet with known issues
@@ -112,7 +112,7 @@ From the repo root:
# This requires no reviewer output and always works.
npm run bench:public
-# Score a reviewer's output after dropping files into benchmark/reviews/.
+# Score a reviewer's output after dropping files into benchmarks/public-catch-rate/reviews/.
npm run bench:public -- --reviewer=codevetter
# Emit a JSON scorecard.
@@ -127,7 +127,7 @@ npm run bench:public -- --reviewer=codevetter --min-rate=0.8
## How to evaluate a tool against this benchmark
-1. For each case in `benchmark/cases//`, feed `source.` to your
+1. For each case in `benchmarks/public-catch-rate/cases//`, feed `source.` to your
reviewer (CodeVetter or any comparator).
2. Normalize the reviewer's findings into the `reviews/.json` shape
above, filling `matched_ground_truth` with the ground-truth ids each finding
@@ -149,6 +149,6 @@ npm run bench:public -- --reviewer=codevetter --min-rate=0.8
- Cases are synthetic and self-contained; they are not tied to a specific PR or
repo. They exist to make the benchmark reproducible by anyone, anywhere.
- The sibling `benchmarks/agent-prs/` harness measures catch rate on real public
- agent-generated PRs with preserved review artifacts. This `benchmark/` set
+ agent-generated PRs with preserved review artifacts. This `benchmarks/public-catch-rate/` set
complements it with broad, language- and issue-type coverage that is cheap to
re-run.
diff --git a/benchmark/cases/go-errcheck/label.json b/benchmarks/public-catch-rate/cases/go-errcheck/label.json
similarity index 100%
rename from benchmark/cases/go-errcheck/label.json
rename to benchmarks/public-catch-rate/cases/go-errcheck/label.json
diff --git a/benchmark/cases/go-errcheck/source.go b/benchmarks/public-catch-rate/cases/go-errcheck/source.go
similarity index 100%
rename from benchmark/cases/go-errcheck/source.go
rename to benchmarks/public-catch-rate/cases/go-errcheck/source.go
diff --git a/benchmark/cases/go-hardcoded-credentials/label.json b/benchmarks/public-catch-rate/cases/go-hardcoded-credentials/label.json
similarity index 100%
rename from benchmark/cases/go-hardcoded-credentials/label.json
rename to benchmarks/public-catch-rate/cases/go-hardcoded-credentials/label.json
diff --git a/benchmark/cases/go-hardcoded-credentials/source.go b/benchmarks/public-catch-rate/cases/go-hardcoded-credentials/source.go
similarity index 100%
rename from benchmark/cases/go-hardcoded-credentials/source.go
rename to benchmarks/public-catch-rate/cases/go-hardcoded-credentials/source.go
diff --git a/benchmark/cases/go-nil-pointer/label.json b/benchmarks/public-catch-rate/cases/go-nil-pointer/label.json
similarity index 100%
rename from benchmark/cases/go-nil-pointer/label.json
rename to benchmarks/public-catch-rate/cases/go-nil-pointer/label.json
diff --git a/benchmark/cases/go-nil-pointer/source.go b/benchmarks/public-catch-rate/cases/go-nil-pointer/source.go
similarity index 100%
rename from benchmark/cases/go-nil-pointer/source.go
rename to benchmarks/public-catch-rate/cases/go-nil-pointer/source.go
diff --git a/benchmark/cases/go-race-condition/label.json b/benchmarks/public-catch-rate/cases/go-race-condition/label.json
similarity index 100%
rename from benchmark/cases/go-race-condition/label.json
rename to benchmarks/public-catch-rate/cases/go-race-condition/label.json
diff --git a/benchmark/cases/go-race-condition/source.go b/benchmarks/public-catch-rate/cases/go-race-condition/source.go
similarity index 100%
rename from benchmark/cases/go-race-condition/source.go
rename to benchmarks/public-catch-rate/cases/go-race-condition/source.go
diff --git a/benchmark/cases/go-sql-injection/label.json b/benchmarks/public-catch-rate/cases/go-sql-injection/label.json
similarity index 100%
rename from benchmark/cases/go-sql-injection/label.json
rename to benchmarks/public-catch-rate/cases/go-sql-injection/label.json
diff --git a/benchmark/cases/go-sql-injection/source.go b/benchmarks/public-catch-rate/cases/go-sql-injection/source.go
similarity index 100%
rename from benchmark/cases/go-sql-injection/source.go
rename to benchmarks/public-catch-rate/cases/go-sql-injection/source.go
diff --git a/benchmark/cases/java-insecure-random/label.json b/benchmarks/public-catch-rate/cases/java-insecure-random/label.json
similarity index 100%
rename from benchmark/cases/java-insecure-random/label.json
rename to benchmarks/public-catch-rate/cases/java-insecure-random/label.json
diff --git a/benchmark/cases/java-insecure-random/source.java b/benchmarks/public-catch-rate/cases/java-insecure-random/source.java
similarity index 100%
rename from benchmark/cases/java-insecure-random/source.java
rename to benchmarks/public-catch-rate/cases/java-insecure-random/source.java
diff --git a/benchmark/cases/js-eval-injection/label.json b/benchmarks/public-catch-rate/cases/js-eval-injection/label.json
similarity index 100%
rename from benchmark/cases/js-eval-injection/label.json
rename to benchmarks/public-catch-rate/cases/js-eval-injection/label.json
diff --git a/benchmark/cases/js-eval-injection/source.js b/benchmarks/public-catch-rate/cases/js-eval-injection/source.js
similarity index 100%
rename from benchmark/cases/js-eval-injection/source.js
rename to benchmarks/public-catch-rate/cases/js-eval-injection/source.js
diff --git a/benchmark/cases/js-open-redirect/label.json b/benchmarks/public-catch-rate/cases/js-open-redirect/label.json
similarity index 100%
rename from benchmark/cases/js-open-redirect/label.json
rename to benchmarks/public-catch-rate/cases/js-open-redirect/label.json
diff --git a/benchmark/cases/js-open-redirect/source.js b/benchmarks/public-catch-rate/cases/js-open-redirect/source.js
similarity index 100%
rename from benchmark/cases/js-open-redirect/source.js
rename to benchmarks/public-catch-rate/cases/js-open-redirect/source.js
diff --git a/benchmark/cases/py-bare-except/label.json b/benchmarks/public-catch-rate/cases/py-bare-except/label.json
similarity index 100%
rename from benchmark/cases/py-bare-except/label.json
rename to benchmarks/public-catch-rate/cases/py-bare-except/label.json
diff --git a/benchmark/cases/py-bare-except/source.py b/benchmarks/public-catch-rate/cases/py-bare-except/source.py
similarity index 100%
rename from benchmark/cases/py-bare-except/source.py
rename to benchmarks/public-catch-rate/cases/py-bare-except/source.py
diff --git a/benchmark/cases/py-command-injection/label.json b/benchmarks/public-catch-rate/cases/py-command-injection/label.json
similarity index 100%
rename from benchmark/cases/py-command-injection/label.json
rename to benchmarks/public-catch-rate/cases/py-command-injection/label.json
diff --git a/benchmark/cases/py-command-injection/source.py b/benchmarks/public-catch-rate/cases/py-command-injection/source.py
similarity index 100%
rename from benchmark/cases/py-command-injection/source.py
rename to benchmarks/public-catch-rate/cases/py-command-injection/source.py
diff --git a/benchmark/cases/py-hardcoded-secret/label.json b/benchmarks/public-catch-rate/cases/py-hardcoded-secret/label.json
similarity index 100%
rename from benchmark/cases/py-hardcoded-secret/label.json
rename to benchmarks/public-catch-rate/cases/py-hardcoded-secret/label.json
diff --git a/benchmark/cases/py-hardcoded-secret/source.py b/benchmarks/public-catch-rate/cases/py-hardcoded-secret/source.py
similarity index 100%
rename from benchmark/cases/py-hardcoded-secret/source.py
rename to benchmarks/public-catch-rate/cases/py-hardcoded-secret/source.py
diff --git a/benchmark/cases/py-insecure-deserialization/label.json b/benchmarks/public-catch-rate/cases/py-insecure-deserialization/label.json
similarity index 100%
rename from benchmark/cases/py-insecure-deserialization/label.json
rename to benchmarks/public-catch-rate/cases/py-insecure-deserialization/label.json
diff --git a/benchmark/cases/py-insecure-deserialization/source.py b/benchmarks/public-catch-rate/cases/py-insecure-deserialization/source.py
similarity index 100%
rename from benchmark/cases/py-insecure-deserialization/source.py
rename to benchmarks/public-catch-rate/cases/py-insecure-deserialization/source.py
diff --git a/benchmark/cases/py-path-traversal/label.json b/benchmarks/public-catch-rate/cases/py-path-traversal/label.json
similarity index 100%
rename from benchmark/cases/py-path-traversal/label.json
rename to benchmarks/public-catch-rate/cases/py-path-traversal/label.json
diff --git a/benchmark/cases/py-path-traversal/source.py b/benchmarks/public-catch-rate/cases/py-path-traversal/source.py
similarity index 100%
rename from benchmark/cases/py-path-traversal/source.py
rename to benchmarks/public-catch-rate/cases/py-path-traversal/source.py
diff --git a/benchmark/cases/py-sql-injection/label.json b/benchmarks/public-catch-rate/cases/py-sql-injection/label.json
similarity index 100%
rename from benchmark/cases/py-sql-injection/label.json
rename to benchmarks/public-catch-rate/cases/py-sql-injection/label.json
diff --git a/benchmark/cases/py-sql-injection/source.py b/benchmarks/public-catch-rate/cases/py-sql-injection/source.py
similarity index 100%
rename from benchmark/cases/py-sql-injection/source.py
rename to benchmarks/public-catch-rate/cases/py-sql-injection/source.py
diff --git a/benchmark/cases/py-ssrf/label.json b/benchmarks/public-catch-rate/cases/py-ssrf/label.json
similarity index 100%
rename from benchmark/cases/py-ssrf/label.json
rename to benchmarks/public-catch-rate/cases/py-ssrf/label.json
diff --git a/benchmark/cases/py-ssrf/source.py b/benchmarks/public-catch-rate/cases/py-ssrf/source.py
similarity index 100%
rename from benchmark/cases/py-ssrf/source.py
rename to benchmarks/public-catch-rate/cases/py-ssrf/source.py
diff --git a/benchmark/cases/py-weak-hash/label.json b/benchmarks/public-catch-rate/cases/py-weak-hash/label.json
similarity index 100%
rename from benchmark/cases/py-weak-hash/label.json
rename to benchmarks/public-catch-rate/cases/py-weak-hash/label.json
diff --git a/benchmark/cases/py-weak-hash/source.py b/benchmarks/public-catch-rate/cases/py-weak-hash/source.py
similarity index 100%
rename from benchmark/cases/py-weak-hash/source.py
rename to benchmarks/public-catch-rate/cases/py-weak-hash/source.py
diff --git a/benchmark/cases/py-zip-bomb/label.json b/benchmarks/public-catch-rate/cases/py-zip-bomb/label.json
similarity index 100%
rename from benchmark/cases/py-zip-bomb/label.json
rename to benchmarks/public-catch-rate/cases/py-zip-bomb/label.json
diff --git a/benchmark/cases/py-zip-bomb/source.py b/benchmarks/public-catch-rate/cases/py-zip-bomb/source.py
similarity index 100%
rename from benchmark/cases/py-zip-bomb/source.py
rename to benchmarks/public-catch-rate/cases/py-zip-bomb/source.py
diff --git a/benchmark/cases/rust-integer-overflow/label.json b/benchmarks/public-catch-rate/cases/rust-integer-overflow/label.json
similarity index 100%
rename from benchmark/cases/rust-integer-overflow/label.json
rename to benchmarks/public-catch-rate/cases/rust-integer-overflow/label.json
diff --git a/benchmark/cases/rust-integer-overflow/source.rs b/benchmarks/public-catch-rate/cases/rust-integer-overflow/source.rs
similarity index 100%
rename from benchmark/cases/rust-integer-overflow/source.rs
rename to benchmarks/public-catch-rate/cases/rust-integer-overflow/source.rs
diff --git a/benchmark/cases/ts-dead-code/label.json b/benchmarks/public-catch-rate/cases/ts-dead-code/label.json
similarity index 100%
rename from benchmark/cases/ts-dead-code/label.json
rename to benchmarks/public-catch-rate/cases/ts-dead-code/label.json
diff --git a/benchmark/cases/ts-dead-code/source.ts b/benchmarks/public-catch-rate/cases/ts-dead-code/source.ts
similarity index 100%
rename from benchmark/cases/ts-dead-code/source.ts
rename to benchmarks/public-catch-rate/cases/ts-dead-code/source.ts
diff --git a/benchmark/cases/ts-hardcoded-credentials/label.json b/benchmarks/public-catch-rate/cases/ts-hardcoded-credentials/label.json
similarity index 100%
rename from benchmark/cases/ts-hardcoded-credentials/label.json
rename to benchmarks/public-catch-rate/cases/ts-hardcoded-credentials/label.json
diff --git a/benchmark/cases/ts-hardcoded-credentials/source.ts b/benchmarks/public-catch-rate/cases/ts-hardcoded-credentials/source.ts
similarity index 100%
rename from benchmark/cases/ts-hardcoded-credentials/source.ts
rename to benchmarks/public-catch-rate/cases/ts-hardcoded-credentials/source.ts
diff --git a/benchmark/cases/ts-insecure-cookie/label.json b/benchmarks/public-catch-rate/cases/ts-insecure-cookie/label.json
similarity index 100%
rename from benchmark/cases/ts-insecure-cookie/label.json
rename to benchmarks/public-catch-rate/cases/ts-insecure-cookie/label.json
diff --git a/benchmark/cases/ts-insecure-cookie/source.ts b/benchmarks/public-catch-rate/cases/ts-insecure-cookie/source.ts
similarity index 100%
rename from benchmark/cases/ts-insecure-cookie/source.ts
rename to benchmarks/public-catch-rate/cases/ts-insecure-cookie/source.ts
diff --git a/benchmark/cases/ts-missing-await/label.json b/benchmarks/public-catch-rate/cases/ts-missing-await/label.json
similarity index 100%
rename from benchmark/cases/ts-missing-await/label.json
rename to benchmarks/public-catch-rate/cases/ts-missing-await/label.json
diff --git a/benchmark/cases/ts-missing-await/source.ts b/benchmarks/public-catch-rate/cases/ts-missing-await/source.ts
similarity index 100%
rename from benchmark/cases/ts-missing-await/source.ts
rename to benchmarks/public-catch-rate/cases/ts-missing-await/source.ts
diff --git a/benchmark/cases/ts-prototype-pollution/label.json b/benchmarks/public-catch-rate/cases/ts-prototype-pollution/label.json
similarity index 100%
rename from benchmark/cases/ts-prototype-pollution/label.json
rename to benchmarks/public-catch-rate/cases/ts-prototype-pollution/label.json
diff --git a/benchmark/cases/ts-prototype-pollution/source.ts b/benchmarks/public-catch-rate/cases/ts-prototype-pollution/source.ts
similarity index 100%
rename from benchmark/cases/ts-prototype-pollution/source.ts
rename to benchmarks/public-catch-rate/cases/ts-prototype-pollution/source.ts
diff --git a/benchmark/cases/ts-regex-dos/label.json b/benchmarks/public-catch-rate/cases/ts-regex-dos/label.json
similarity index 100%
rename from benchmark/cases/ts-regex-dos/label.json
rename to benchmarks/public-catch-rate/cases/ts-regex-dos/label.json
diff --git a/benchmark/cases/ts-regex-dos/source.ts b/benchmarks/public-catch-rate/cases/ts-regex-dos/source.ts
similarity index 100%
rename from benchmark/cases/ts-regex-dos/source.ts
rename to benchmarks/public-catch-rate/cases/ts-regex-dos/source.ts
diff --git a/benchmark/cases/ts-sql-injection/label.json b/benchmarks/public-catch-rate/cases/ts-sql-injection/label.json
similarity index 100%
rename from benchmark/cases/ts-sql-injection/label.json
rename to benchmarks/public-catch-rate/cases/ts-sql-injection/label.json
diff --git a/benchmark/cases/ts-sql-injection/source.ts b/benchmarks/public-catch-rate/cases/ts-sql-injection/source.ts
similarity index 100%
rename from benchmark/cases/ts-sql-injection/source.ts
rename to benchmarks/public-catch-rate/cases/ts-sql-injection/source.ts
diff --git a/benchmark/cases/ts-type-confusion/label.json b/benchmarks/public-catch-rate/cases/ts-type-confusion/label.json
similarity index 100%
rename from benchmark/cases/ts-type-confusion/label.json
rename to benchmarks/public-catch-rate/cases/ts-type-confusion/label.json
diff --git a/benchmark/cases/ts-type-confusion/source.ts b/benchmarks/public-catch-rate/cases/ts-type-confusion/source.ts
similarity index 100%
rename from benchmark/cases/ts-type-confusion/source.ts
rename to benchmarks/public-catch-rate/cases/ts-type-confusion/source.ts
diff --git a/benchmark/cases/ts-xss/label.json b/benchmarks/public-catch-rate/cases/ts-xss/label.json
similarity index 100%
rename from benchmark/cases/ts-xss/label.json
rename to benchmarks/public-catch-rate/cases/ts-xss/label.json
diff --git a/benchmark/cases/ts-xss/source.tsx b/benchmarks/public-catch-rate/cases/ts-xss/source.tsx
similarity index 100%
rename from benchmark/cases/ts-xss/source.tsx
rename to benchmarks/public-catch-rate/cases/ts-xss/source.tsx
diff --git a/benchmark/reviews-raw/go-errcheck.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/go-errcheck.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/go-errcheck.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/go-errcheck.codevetter.raw.json
diff --git a/benchmark/reviews-raw/go-hardcoded-credentials.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/go-hardcoded-credentials.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/go-hardcoded-credentials.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/go-hardcoded-credentials.codevetter.raw.json
diff --git a/benchmark/reviews-raw/go-nil-pointer.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/go-nil-pointer.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/go-nil-pointer.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/go-nil-pointer.codevetter.raw.json
diff --git a/benchmark/reviews-raw/go-race-condition.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/go-race-condition.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/go-race-condition.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/go-race-condition.codevetter.raw.json
diff --git a/benchmark/reviews-raw/go-sql-injection.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/go-sql-injection.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/go-sql-injection.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/go-sql-injection.codevetter.raw.json
diff --git a/benchmark/reviews-raw/java-insecure-random.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/java-insecure-random.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/java-insecure-random.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/java-insecure-random.codevetter.raw.json
diff --git a/benchmark/reviews-raw/js-eval-injection.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/js-eval-injection.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/js-eval-injection.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/js-eval-injection.codevetter.raw.json
diff --git a/benchmark/reviews-raw/js-open-redirect.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/js-open-redirect.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/js-open-redirect.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/js-open-redirect.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-bare-except.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-bare-except.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-bare-except.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-bare-except.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-command-injection.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-command-injection.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-command-injection.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-command-injection.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-hardcoded-secret.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-hardcoded-secret.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-hardcoded-secret.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-hardcoded-secret.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-insecure-deserialization.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-insecure-deserialization.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-insecure-deserialization.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-insecure-deserialization.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-path-traversal.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-path-traversal.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-path-traversal.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-path-traversal.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-sql-injection.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-sql-injection.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-sql-injection.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-sql-injection.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-ssrf.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-ssrf.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-ssrf.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-ssrf.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-weak-hash.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-weak-hash.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-weak-hash.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-weak-hash.codevetter.raw.json
diff --git a/benchmark/reviews-raw/py-zip-bomb.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/py-zip-bomb.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/py-zip-bomb.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/py-zip-bomb.codevetter.raw.json
diff --git a/benchmark/reviews-raw/rust-integer-overflow.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/rust-integer-overflow.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/rust-integer-overflow.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/rust-integer-overflow.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-dead-code.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-dead-code.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-dead-code.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-dead-code.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-hardcoded-credentials.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-hardcoded-credentials.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-hardcoded-credentials.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-hardcoded-credentials.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-insecure-cookie.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-insecure-cookie.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-insecure-cookie.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-insecure-cookie.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-missing-await.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-missing-await.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-missing-await.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-missing-await.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-prototype-pollution.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-prototype-pollution.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-prototype-pollution.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-prototype-pollution.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-regex-dos.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-regex-dos.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-regex-dos.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-regex-dos.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-sql-injection.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-sql-injection.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-sql-injection.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-sql-injection.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-type-confusion.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-type-confusion.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-type-confusion.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-type-confusion.codevetter.raw.json
diff --git a/benchmark/reviews-raw/ts-xss.codevetter.raw.json b/benchmarks/public-catch-rate/reviews-raw/ts-xss.codevetter.raw.json
similarity index 100%
rename from benchmark/reviews-raw/ts-xss.codevetter.raw.json
rename to benchmarks/public-catch-rate/reviews-raw/ts-xss.codevetter.raw.json
diff --git a/biome.json b/biome.json
index 5fdb8c3a..899fac06 100644
--- a/biome.json
+++ b/biome.json
@@ -36,7 +36,7 @@
"!**/*.css",
"!**/*.svg",
"!**/*.astro",
- "!benchmark/cases"
+ "!benchmarks/public-catch-rate/cases"
]
},
"formatter": {
diff --git a/docs/development/benchmark.md b/docs/development/benchmark.md
index 146c1a26..62e5351c 100644
--- a/docs/development/benchmark.md
+++ b/docs/development/benchmark.md
@@ -95,7 +95,7 @@ avoid overfitting 27 cases.
Protocol: every case ran through the REAL production pipeline (risk tiers,
specialists, coordinator, dedup) via the ignored Rust harness
`diag_benchmark_generate_codevetter_reviews`; raw outputs live in
-`benchmark/reviews-raw/`. Ground-truth mapping was proposed mechanically
+`benchmarks/public-catch-rate/reviews-raw/`. Ground-truth mapping was proposed mechanically
(`scripts/map-benchmark-reviews.mjs`) and then hand-judged per finding under
one rule: a finding matches only if its CORE CLAIM identifies the defect;
process findings (no-tests, shipped-with-comment) never match.
diff --git a/docs/operations/automation-contract.md b/docs/operations/automation-contract.md
index 29aad18a..5f234e4e 100644
--- a/docs/operations/automation-contract.md
+++ b/docs/operations/automation-contract.md
@@ -34,7 +34,7 @@ Do not duplicate this matrix elsewhere — link here.
| Desktop Rust backend | `apps/desktop/src-tauri/src/` | `ci.yml` MCP tests; `release.yml` Tauri build | Sarthak |
| Local SQLite | `rusqlite` in Rust backend (no server) | Local only; `observability.rs` aggregates locally | Sarthak |
| MCP sidecar | `apps/desktop/src-tauri/src/bin/codevetter-mcp.rs` | `ci.yml` MCP protocol + stdio lifecycle tests; `mcp/sanitize.rs` redaction | Sarthak |
-| Benchmark | `benchmark/` + `scripts/run-catch-rate-benchmark.mjs` | `pnpm test:benchmark`; public cases committed | Sarthak |
+| Benchmark | `benchmarks/public-catch-rate/` + `scripts/run-catch-rate-benchmark.mjs` | `pnpm test:benchmark`; public cases committed | Sarthak |
| Release pipeline | `auto-release.yml` → `release.yml` → GitHub Releases | Release assets + `latest.json` manifest | Sarthak |
| Auto-updater | `@tauri-apps/plugin-updater` consuming `latest.json` | `scripts/verify-release-manifest.mjs` validates linkage | Sarthak |
| Docs | `docs/` + `docs-site/` (Blume) | `docs.yml` link + structure validation | Sarthak |
diff --git a/docs/product/overview.md b/docs/product/overview.md
index 0def6952..6181e561 100644
--- a/docs/product/overview.md
+++ b/docs/product/overview.md
@@ -56,7 +56,7 @@ work, and did the affected audience succeed with it?*
## Benchmark evidence
-27 hand-labeled public benchmark cases (`benchmark/cases/`) covering 7
+27 hand-labeled public benchmark cases (`benchmarks/public-catch-rate/cases/`) covering 7
languages and 15+ vulnerability types. The coordinator dedup fix
(2026-07-11) flipped the head-to-head vs raw Claude: catch 1.000 vs 0.931,
precision 0.433 vs 0.397, F1 0.604 vs 0.557. Real agent-PR case curation
diff --git a/scripts/generate-benchmark-dataset.mjs b/scripts/generate-benchmark-dataset.mjs
index dc9ea3da..92508c66 100644
--- a/scripts/generate-benchmark-dataset.mjs
+++ b/scripts/generate-benchmark-dataset.mjs
@@ -14,7 +14,7 @@ import fs from 'node:fs';
import path from 'node:path';
const ROOT = process.cwd();
-const CASES_DIR = path.join(ROOT, 'benchmark/cases');
+const CASES_DIR = path.join(ROOT, 'benchmarks/public-catch-rate/cases');
const LANDING_PUBLIC = path.join(ROOT, 'apps/landing-page-astro/public');
const LANDING_DATA = path.join(ROOT, 'apps/landing-page-astro/src/data');
diff --git a/scripts/map-benchmark-reviews.mjs b/scripts/map-benchmark-reviews.mjs
index 8082c84c..e6d67492 100644
--- a/scripts/map-benchmark-reviews.mjs
+++ b/scripts/map-benchmark-reviews.mjs
@@ -1,7 +1,7 @@
#!/usr/bin/env node
-// Convert raw CodeVetter pipeline output (benchmark/reviews-raw/.codevetter.raw.json,
+// Convert raw CodeVetter pipeline output (benchmarks/public-catch-rate/reviews-raw/.codevetter.raw.json,
// produced by the diag_benchmark_generate_codevetter_reviews harness) into the
-// scorer's reviewer format at benchmark/reviews/.codevetter.json.
+// scorer's reviewer format at benchmarks/public-catch-rate/reviews/.codevetter.json.
//
// Ground-truth matching here is a mechanical PROPOSAL (line overlap + keyword
// correspondence); every proposed file is meant to be hand-checked before
diff --git a/scripts/run-public-benchmark.mjs b/scripts/run-public-benchmark.mjs
index a60498b3..e9600a4e 100644
--- a/scripts/run-public-benchmark.mjs
+++ b/scripts/run-public-benchmark.mjs
@@ -1,8 +1,8 @@
#!/usr/bin/env node
-// Public benchmark scorer for benchmark/cases/*.
+// Public benchmark scorer for benchmarks/public-catch-rate/cases/*.
//
// Validates every hand-labeled case and, when reviewer output files are
-// present in benchmark/reviews/.json, computes catch-rate, precision,
+// present in benchmarks/public-catch-rate/reviews/.json, computes catch-rate, precision,
// F1, false-positive, redundant-match, and per-severity metrics.
//
// Usage:
@@ -14,8 +14,8 @@
import fs from 'node:fs';
import path from 'node:path';
-const CASES_DIR = path.resolve(process.cwd(), 'benchmark/cases');
-const REVIEWS_DIR = path.resolve(process.cwd(), 'benchmark/reviews');
+const CASES_DIR = path.resolve(process.cwd(), 'benchmarks/public-catch-rate/cases');
+const REVIEWS_DIR = path.resolve(process.cwd(), 'benchmarks/public-catch-rate/reviews');
const SEVERITY_RANK = { low: 1, medium: 2, high: 3, critical: 4 };
@@ -320,7 +320,7 @@ function main() {
process.exit(1);
}
if (!cases.length) {
- console.error('No benchmark cases found under benchmark/cases');
+ console.error('No benchmark cases found under benchmarks/public-catch-rate/cases');
process.exit(1);
}
const reviews = loadReviews(args.reviewer);
From 5bd34270ef9775a57305171c6d9f232f4ae5ca2a Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 13:40:37 +0530
Subject: [PATCH 04/37] refactor(evidence): consolidate committed evidence into
one evidence/ root
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Evidence was spread across four locations: artifacts/, .fleet/evidence/,
.fleet/design-reviews/, and apps/desktop/artifacts/. The split was actively
lossy — .fleet/evidence/landing-audit/ held the scorecard and performance
report while artifacts/design/landing-audit/ held the screenshots of the same
audit. They now sit together.
artifacts/ also had two incompatible jobs: committed design evidence, and the
scratch output path the docs tell users to write to (--out artifacts/... in
docs/development/verification-receipts.md, benchmark.md and performance.md).
Splitting them resolves that — artifacts/ is now gitignored scratch, and those
existing doc examples become correct rather than ambiguous.
Layout:
evidence/design/ screenshots, landing-audit, changelog, probes, reviews
evidence/performance/ performance-lab results and manifests
evidence/reviews/ PR review captures
All moves use git mv so rename history survives.
Co-Authored-By: Claude Opus 5 (1M context)
---
docs/knowledge/performance-lab-publication.md | 2 +-
{artifacts => evidence}/design/after-1440.png | Bin
{artifacts => evidence}/design/after-390.png | Bin
{artifacts => evidence}/design/after-768.png | Bin
.../design}/changelog/after-1440.png | Bin
.../design}/changelog/after-390.png | Bin
.../design}/changelog/after-768.png | Bin
.../design}/changelog/before-1440.png | Bin
.../design/content-cluster-after-1440.png | Bin
.../design/content-cluster-after-390.png | Bin
.../design/content-cluster-after-768.png | Bin
.../design/content-cluster-before.png | Bin
.../design/crash-recovery-after-1440.png | Bin
.../design/crash-recovery-after-390.png | Bin
.../design/crash-recovery-after-768.png | Bin
.../design/crash-recovery-before-1440.png | Bin
.../design/crash-recovery-final-1440.jpg | Bin
.../design/crash-recovery-final-390.jpg | Bin
.../design/crash-recovery-final-768.jpg | Bin
{artifacts => evidence}/design/design-review.json | 0
.../design/landing-audit/candidate-1440.png | Bin
.../design/landing-audit/candidate-390.png | Bin
.../design/landing-audit/candidate-768.png | Bin
.../design/landing-audit/final-1440.png | Bin
.../design/landing-audit/final-390.png | Bin
.../design/landing-audit/final-768.png | Bin
.../design/landing-audit/final-p1-1440.png | Bin
.../design/landing-audit/final-p1-390.png | Bin
.../design/landing-audit/final-p1-768.png | Bin
.../design}/landing-audit/performance.html | 0
.../design/landing-audit/rendered-1440.png | Bin
.../design/landing-audit/rendered-390.png | Bin
.../design/landing-audit/rendered-768.png | Bin
.../design}/landing-audit/scorecard.json | 0
.../design/landing-audit/scrolled-390.png | Bin
.../design/probes/review-overhaul-directions.html | 0
.../probes/review-overhaul-evidence-brief.png | Bin
.../design/probes/review-overhaul-inline-review.png | Bin
.../design/probes/review-overhaul-triage-desk.png | Bin
.../design/product-surfaces-after-1440.jpg | Bin
.../design/product-surfaces-after-390.jpg | Bin
.../design/product-surfaces-after-768.jpg | Bin
.../design/product-surfaces-before-1440.jpg | Bin
.../design/product-surfaces-scope-1440.png | Bin
.../design/product-surfaces-scope-390.png | Bin
.../design/product-surfaces-scope-768.png | Bin
.../design/review-agent-readiness-after-1440.png | Bin
.../design/review-agent-readiness-after-390.png | Bin
.../design/review-agent-readiness-after-768.png | Bin
.../design/review-desktop-after-1440.png | Bin
.../design/review-desktop-final-1440.png | Bin
.../design/review-inline-overhaul-after-1280.png | Bin
.../design/review-inline-overhaul-after-1440.png | Bin
.../design/review-inline-overhaul-after-900.png | Bin
.../design/review-inline-overhaul-audit-390.png | Bin
.../design/review-inline-overhaul-audit-768.png | Bin
.../design/review-inspector-readable-after-1440.png | Bin
.../design/review-navigation-after-1440.png | Bin
.../design/review-result-polish-after-1440.png | Bin
.../design/review-result-polish-after-390.png | Bin
.../design/review-result-polish-after-768.png | Bin
.../design/reviews}/crash-recovery.json | 0
.../design/reviews}/desktop-navigation-clarity.json | 0
.../reviews}/focus-desktop-product-surfaces.json | 0
.../design/reviews}/landing-page.json | 0
.../local-review-test-performance-check.json | 0
.../reviews}/review-inspector-readability.json | 0
.../design/reviews}/review-result-polish.json | 0
.../design/reviews/review-workbench-overhaul.json | 0
.../design/reviews}/sidebar.json | 0
.../trex-change-and-preview-verification.json | 0
.../design/sidebar-after-1440.png | Bin
.../design/sidebar-after-390.png | Bin
.../design/sidebar-after-768.png | Bin
.../design/structural-context-evaluation.html | 0
{artifacts => evidence}/design/trex-after-1440.png | Bin
{artifacts => evidence}/design/trex-after-390.png | Bin
{artifacts => evidence}/design/trex-after-768.png | Bin
{artifacts => evidence}/design/trex-before-1440.png | Bin
{artifacts => evidence}/design/trex-result-1440.png | Bin
.../design/usage-telemetry-after-1440.png | Bin
.../design/usage-telemetry-after-390.png | Bin
.../design/usage-telemetry-after-768.png | Bin
.../design/usage-telemetry-before-1440.png | Bin
.../calorie-exercise-guidance-2026-08-10.md | 0
.../performance/old-local-portfolio-manifest.json | 0
.../old-local-projects-results-2026-08-09.md | 0
.../reviews/pr157-codevetter-review.png | Bin
.../reviews/pr173-codevetter-review.png | Bin
89 files changed, 1 insertion(+), 1 deletion(-)
rename {artifacts => evidence}/design/after-1440.png (100%)
rename {artifacts => evidence}/design/after-390.png (100%)
rename {artifacts => evidence}/design/after-768.png (100%)
rename {.fleet/evidence => evidence/design}/changelog/after-1440.png (100%)
rename {.fleet/evidence => evidence/design}/changelog/after-390.png (100%)
rename {.fleet/evidence => evidence/design}/changelog/after-768.png (100%)
rename {.fleet/evidence => evidence/design}/changelog/before-1440.png (100%)
rename {artifacts => evidence}/design/content-cluster-after-1440.png (100%)
rename {artifacts => evidence}/design/content-cluster-after-390.png (100%)
rename {artifacts => evidence}/design/content-cluster-after-768.png (100%)
rename {artifacts => evidence}/design/content-cluster-before.png (100%)
rename {artifacts => evidence}/design/crash-recovery-after-1440.png (100%)
rename {artifacts => evidence}/design/crash-recovery-after-390.png (100%)
rename {artifacts => evidence}/design/crash-recovery-after-768.png (100%)
rename {artifacts => evidence}/design/crash-recovery-before-1440.png (100%)
rename {artifacts => evidence}/design/crash-recovery-final-1440.jpg (100%)
rename {artifacts => evidence}/design/crash-recovery-final-390.jpg (100%)
rename {artifacts => evidence}/design/crash-recovery-final-768.jpg (100%)
rename {artifacts => evidence}/design/design-review.json (100%)
rename {artifacts => evidence}/design/landing-audit/candidate-1440.png (100%)
rename {artifacts => evidence}/design/landing-audit/candidate-390.png (100%)
rename {artifacts => evidence}/design/landing-audit/candidate-768.png (100%)
rename {artifacts => evidence}/design/landing-audit/final-1440.png (100%)
rename {artifacts => evidence}/design/landing-audit/final-390.png (100%)
rename {artifacts => evidence}/design/landing-audit/final-768.png (100%)
rename {artifacts => evidence}/design/landing-audit/final-p1-1440.png (100%)
rename {artifacts => evidence}/design/landing-audit/final-p1-390.png (100%)
rename {artifacts => evidence}/design/landing-audit/final-p1-768.png (100%)
rename {.fleet/evidence => evidence/design}/landing-audit/performance.html (100%)
rename {artifacts => evidence}/design/landing-audit/rendered-1440.png (100%)
rename {artifacts => evidence}/design/landing-audit/rendered-390.png (100%)
rename {artifacts => evidence}/design/landing-audit/rendered-768.png (100%)
rename {.fleet/evidence => evidence/design}/landing-audit/scorecard.json (100%)
rename {artifacts => evidence}/design/landing-audit/scrolled-390.png (100%)
rename {artifacts => evidence}/design/probes/review-overhaul-directions.html (100%)
rename {artifacts => evidence}/design/probes/review-overhaul-evidence-brief.png (100%)
rename {artifacts => evidence}/design/probes/review-overhaul-inline-review.png (100%)
rename {artifacts => evidence}/design/probes/review-overhaul-triage-desk.png (100%)
rename {artifacts => evidence}/design/product-surfaces-after-1440.jpg (100%)
rename {artifacts => evidence}/design/product-surfaces-after-390.jpg (100%)
rename {artifacts => evidence}/design/product-surfaces-after-768.jpg (100%)
rename {artifacts => evidence}/design/product-surfaces-before-1440.jpg (100%)
rename {apps/desktop/artifacts => evidence}/design/product-surfaces-scope-1440.png (100%)
rename {apps/desktop/artifacts => evidence}/design/product-surfaces-scope-390.png (100%)
rename {apps/desktop/artifacts => evidence}/design/product-surfaces-scope-768.png (100%)
rename {artifacts => evidence}/design/review-agent-readiness-after-1440.png (100%)
rename {artifacts => evidence}/design/review-agent-readiness-after-390.png (100%)
rename {artifacts => evidence}/design/review-agent-readiness-after-768.png (100%)
rename {artifacts => evidence}/design/review-desktop-after-1440.png (100%)
rename {artifacts => evidence}/design/review-desktop-final-1440.png (100%)
rename {artifacts => evidence}/design/review-inline-overhaul-after-1280.png (100%)
rename {artifacts => evidence}/design/review-inline-overhaul-after-1440.png (100%)
rename {artifacts => evidence}/design/review-inline-overhaul-after-900.png (100%)
rename {artifacts => evidence}/design/review-inline-overhaul-audit-390.png (100%)
rename {artifacts => evidence}/design/review-inline-overhaul-audit-768.png (100%)
rename {artifacts => evidence}/design/review-inspector-readable-after-1440.png (100%)
rename {artifacts => evidence}/design/review-navigation-after-1440.png (100%)
rename {artifacts => evidence}/design/review-result-polish-after-1440.png (100%)
rename {artifacts => evidence}/design/review-result-polish-after-390.png (100%)
rename {artifacts => evidence}/design/review-result-polish-after-768.png (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/crash-recovery.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/desktop-navigation-clarity.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/focus-desktop-product-surfaces.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/landing-page.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/local-review-test-performance-check.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/review-inspector-readability.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/review-result-polish.json (100%)
rename .fleet/design-review.json => evidence/design/reviews/review-workbench-overhaul.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/sidebar.json (100%)
rename {.fleet/design-reviews => evidence/design/reviews}/trex-change-and-preview-verification.json (100%)
rename {artifacts => evidence}/design/sidebar-after-1440.png (100%)
rename {artifacts => evidence}/design/sidebar-after-390.png (100%)
rename {artifacts => evidence}/design/sidebar-after-768.png (100%)
rename {artifacts => evidence}/design/structural-context-evaluation.html (100%)
rename {artifacts => evidence}/design/trex-after-1440.png (100%)
rename {artifacts => evidence}/design/trex-after-390.png (100%)
rename {artifacts => evidence}/design/trex-after-768.png (100%)
rename {artifacts => evidence}/design/trex-before-1440.png (100%)
rename {artifacts => evidence}/design/trex-result-1440.png (100%)
rename {artifacts => evidence}/design/usage-telemetry-after-1440.png (100%)
rename {artifacts => evidence}/design/usage-telemetry-after-390.png (100%)
rename {artifacts => evidence}/design/usage-telemetry-after-768.png (100%)
rename {artifacts => evidence}/design/usage-telemetry-before-1440.png (100%)
rename {artifacts => evidence}/performance/calorie-exercise-guidance-2026-08-10.md (100%)
rename {artifacts => evidence}/performance/old-local-portfolio-manifest.json (100%)
rename {artifacts => evidence}/performance/old-local-projects-results-2026-08-09.md (100%)
rename {artifacts => evidence}/reviews/pr157-codevetter-review.png (100%)
rename {artifacts => evidence}/reviews/pr173-codevetter-review.png (100%)
diff --git a/docs/knowledge/performance-lab-publication.md b/docs/knowledge/performance-lab-publication.md
index b8a35f89..c40103c1 100644
--- a/docs/knowledge/performance-lab-publication.md
+++ b/docs/knowledge/performance-lab-publication.md
@@ -55,7 +55,7 @@ product's end game. Merge status does not upgrade evidence strength: the
directional, unverified, guardrail, and synthetic-stress entries are not
independent claims of proven customer impact. The full inactive-project
disposition is retained in
-[`artifacts/performance/old-local-projects-results-2026-08-09.md`](../../artifacts/performance/old-local-projects-results-2026-08-09.md).
+[`evidence/performance/old-local-projects-results-2026-08-09.md`](../../evidence/performance/old-local-projects-results-2026-08-09.md).
## External open-source work
diff --git a/artifacts/design/after-1440.png b/evidence/design/after-1440.png
similarity index 100%
rename from artifacts/design/after-1440.png
rename to evidence/design/after-1440.png
diff --git a/artifacts/design/after-390.png b/evidence/design/after-390.png
similarity index 100%
rename from artifacts/design/after-390.png
rename to evidence/design/after-390.png
diff --git a/artifacts/design/after-768.png b/evidence/design/after-768.png
similarity index 100%
rename from artifacts/design/after-768.png
rename to evidence/design/after-768.png
diff --git a/.fleet/evidence/changelog/after-1440.png b/evidence/design/changelog/after-1440.png
similarity index 100%
rename from .fleet/evidence/changelog/after-1440.png
rename to evidence/design/changelog/after-1440.png
diff --git a/.fleet/evidence/changelog/after-390.png b/evidence/design/changelog/after-390.png
similarity index 100%
rename from .fleet/evidence/changelog/after-390.png
rename to evidence/design/changelog/after-390.png
diff --git a/.fleet/evidence/changelog/after-768.png b/evidence/design/changelog/after-768.png
similarity index 100%
rename from .fleet/evidence/changelog/after-768.png
rename to evidence/design/changelog/after-768.png
diff --git a/.fleet/evidence/changelog/before-1440.png b/evidence/design/changelog/before-1440.png
similarity index 100%
rename from .fleet/evidence/changelog/before-1440.png
rename to evidence/design/changelog/before-1440.png
diff --git a/artifacts/design/content-cluster-after-1440.png b/evidence/design/content-cluster-after-1440.png
similarity index 100%
rename from artifacts/design/content-cluster-after-1440.png
rename to evidence/design/content-cluster-after-1440.png
diff --git a/artifacts/design/content-cluster-after-390.png b/evidence/design/content-cluster-after-390.png
similarity index 100%
rename from artifacts/design/content-cluster-after-390.png
rename to evidence/design/content-cluster-after-390.png
diff --git a/artifacts/design/content-cluster-after-768.png b/evidence/design/content-cluster-after-768.png
similarity index 100%
rename from artifacts/design/content-cluster-after-768.png
rename to evidence/design/content-cluster-after-768.png
diff --git a/artifacts/design/content-cluster-before.png b/evidence/design/content-cluster-before.png
similarity index 100%
rename from artifacts/design/content-cluster-before.png
rename to evidence/design/content-cluster-before.png
diff --git a/artifacts/design/crash-recovery-after-1440.png b/evidence/design/crash-recovery-after-1440.png
similarity index 100%
rename from artifacts/design/crash-recovery-after-1440.png
rename to evidence/design/crash-recovery-after-1440.png
diff --git a/artifacts/design/crash-recovery-after-390.png b/evidence/design/crash-recovery-after-390.png
similarity index 100%
rename from artifacts/design/crash-recovery-after-390.png
rename to evidence/design/crash-recovery-after-390.png
diff --git a/artifacts/design/crash-recovery-after-768.png b/evidence/design/crash-recovery-after-768.png
similarity index 100%
rename from artifacts/design/crash-recovery-after-768.png
rename to evidence/design/crash-recovery-after-768.png
diff --git a/artifacts/design/crash-recovery-before-1440.png b/evidence/design/crash-recovery-before-1440.png
similarity index 100%
rename from artifacts/design/crash-recovery-before-1440.png
rename to evidence/design/crash-recovery-before-1440.png
diff --git a/artifacts/design/crash-recovery-final-1440.jpg b/evidence/design/crash-recovery-final-1440.jpg
similarity index 100%
rename from artifacts/design/crash-recovery-final-1440.jpg
rename to evidence/design/crash-recovery-final-1440.jpg
diff --git a/artifacts/design/crash-recovery-final-390.jpg b/evidence/design/crash-recovery-final-390.jpg
similarity index 100%
rename from artifacts/design/crash-recovery-final-390.jpg
rename to evidence/design/crash-recovery-final-390.jpg
diff --git a/artifacts/design/crash-recovery-final-768.jpg b/evidence/design/crash-recovery-final-768.jpg
similarity index 100%
rename from artifacts/design/crash-recovery-final-768.jpg
rename to evidence/design/crash-recovery-final-768.jpg
diff --git a/artifacts/design/design-review.json b/evidence/design/design-review.json
similarity index 100%
rename from artifacts/design/design-review.json
rename to evidence/design/design-review.json
diff --git a/artifacts/design/landing-audit/candidate-1440.png b/evidence/design/landing-audit/candidate-1440.png
similarity index 100%
rename from artifacts/design/landing-audit/candidate-1440.png
rename to evidence/design/landing-audit/candidate-1440.png
diff --git a/artifacts/design/landing-audit/candidate-390.png b/evidence/design/landing-audit/candidate-390.png
similarity index 100%
rename from artifacts/design/landing-audit/candidate-390.png
rename to evidence/design/landing-audit/candidate-390.png
diff --git a/artifacts/design/landing-audit/candidate-768.png b/evidence/design/landing-audit/candidate-768.png
similarity index 100%
rename from artifacts/design/landing-audit/candidate-768.png
rename to evidence/design/landing-audit/candidate-768.png
diff --git a/artifacts/design/landing-audit/final-1440.png b/evidence/design/landing-audit/final-1440.png
similarity index 100%
rename from artifacts/design/landing-audit/final-1440.png
rename to evidence/design/landing-audit/final-1440.png
diff --git a/artifacts/design/landing-audit/final-390.png b/evidence/design/landing-audit/final-390.png
similarity index 100%
rename from artifacts/design/landing-audit/final-390.png
rename to evidence/design/landing-audit/final-390.png
diff --git a/artifacts/design/landing-audit/final-768.png b/evidence/design/landing-audit/final-768.png
similarity index 100%
rename from artifacts/design/landing-audit/final-768.png
rename to evidence/design/landing-audit/final-768.png
diff --git a/artifacts/design/landing-audit/final-p1-1440.png b/evidence/design/landing-audit/final-p1-1440.png
similarity index 100%
rename from artifacts/design/landing-audit/final-p1-1440.png
rename to evidence/design/landing-audit/final-p1-1440.png
diff --git a/artifacts/design/landing-audit/final-p1-390.png b/evidence/design/landing-audit/final-p1-390.png
similarity index 100%
rename from artifacts/design/landing-audit/final-p1-390.png
rename to evidence/design/landing-audit/final-p1-390.png
diff --git a/artifacts/design/landing-audit/final-p1-768.png b/evidence/design/landing-audit/final-p1-768.png
similarity index 100%
rename from artifacts/design/landing-audit/final-p1-768.png
rename to evidence/design/landing-audit/final-p1-768.png
diff --git a/.fleet/evidence/landing-audit/performance.html b/evidence/design/landing-audit/performance.html
similarity index 100%
rename from .fleet/evidence/landing-audit/performance.html
rename to evidence/design/landing-audit/performance.html
diff --git a/artifacts/design/landing-audit/rendered-1440.png b/evidence/design/landing-audit/rendered-1440.png
similarity index 100%
rename from artifacts/design/landing-audit/rendered-1440.png
rename to evidence/design/landing-audit/rendered-1440.png
diff --git a/artifacts/design/landing-audit/rendered-390.png b/evidence/design/landing-audit/rendered-390.png
similarity index 100%
rename from artifacts/design/landing-audit/rendered-390.png
rename to evidence/design/landing-audit/rendered-390.png
diff --git a/artifacts/design/landing-audit/rendered-768.png b/evidence/design/landing-audit/rendered-768.png
similarity index 100%
rename from artifacts/design/landing-audit/rendered-768.png
rename to evidence/design/landing-audit/rendered-768.png
diff --git a/.fleet/evidence/landing-audit/scorecard.json b/evidence/design/landing-audit/scorecard.json
similarity index 100%
rename from .fleet/evidence/landing-audit/scorecard.json
rename to evidence/design/landing-audit/scorecard.json
diff --git a/artifacts/design/landing-audit/scrolled-390.png b/evidence/design/landing-audit/scrolled-390.png
similarity index 100%
rename from artifacts/design/landing-audit/scrolled-390.png
rename to evidence/design/landing-audit/scrolled-390.png
diff --git a/artifacts/design/probes/review-overhaul-directions.html b/evidence/design/probes/review-overhaul-directions.html
similarity index 100%
rename from artifacts/design/probes/review-overhaul-directions.html
rename to evidence/design/probes/review-overhaul-directions.html
diff --git a/artifacts/design/probes/review-overhaul-evidence-brief.png b/evidence/design/probes/review-overhaul-evidence-brief.png
similarity index 100%
rename from artifacts/design/probes/review-overhaul-evidence-brief.png
rename to evidence/design/probes/review-overhaul-evidence-brief.png
diff --git a/artifacts/design/probes/review-overhaul-inline-review.png b/evidence/design/probes/review-overhaul-inline-review.png
similarity index 100%
rename from artifacts/design/probes/review-overhaul-inline-review.png
rename to evidence/design/probes/review-overhaul-inline-review.png
diff --git a/artifacts/design/probes/review-overhaul-triage-desk.png b/evidence/design/probes/review-overhaul-triage-desk.png
similarity index 100%
rename from artifacts/design/probes/review-overhaul-triage-desk.png
rename to evidence/design/probes/review-overhaul-triage-desk.png
diff --git a/artifacts/design/product-surfaces-after-1440.jpg b/evidence/design/product-surfaces-after-1440.jpg
similarity index 100%
rename from artifacts/design/product-surfaces-after-1440.jpg
rename to evidence/design/product-surfaces-after-1440.jpg
diff --git a/artifacts/design/product-surfaces-after-390.jpg b/evidence/design/product-surfaces-after-390.jpg
similarity index 100%
rename from artifacts/design/product-surfaces-after-390.jpg
rename to evidence/design/product-surfaces-after-390.jpg
diff --git a/artifacts/design/product-surfaces-after-768.jpg b/evidence/design/product-surfaces-after-768.jpg
similarity index 100%
rename from artifacts/design/product-surfaces-after-768.jpg
rename to evidence/design/product-surfaces-after-768.jpg
diff --git a/artifacts/design/product-surfaces-before-1440.jpg b/evidence/design/product-surfaces-before-1440.jpg
similarity index 100%
rename from artifacts/design/product-surfaces-before-1440.jpg
rename to evidence/design/product-surfaces-before-1440.jpg
diff --git a/apps/desktop/artifacts/design/product-surfaces-scope-1440.png b/evidence/design/product-surfaces-scope-1440.png
similarity index 100%
rename from apps/desktop/artifacts/design/product-surfaces-scope-1440.png
rename to evidence/design/product-surfaces-scope-1440.png
diff --git a/apps/desktop/artifacts/design/product-surfaces-scope-390.png b/evidence/design/product-surfaces-scope-390.png
similarity index 100%
rename from apps/desktop/artifacts/design/product-surfaces-scope-390.png
rename to evidence/design/product-surfaces-scope-390.png
diff --git a/apps/desktop/artifacts/design/product-surfaces-scope-768.png b/evidence/design/product-surfaces-scope-768.png
similarity index 100%
rename from apps/desktop/artifacts/design/product-surfaces-scope-768.png
rename to evidence/design/product-surfaces-scope-768.png
diff --git a/artifacts/design/review-agent-readiness-after-1440.png b/evidence/design/review-agent-readiness-after-1440.png
similarity index 100%
rename from artifacts/design/review-agent-readiness-after-1440.png
rename to evidence/design/review-agent-readiness-after-1440.png
diff --git a/artifacts/design/review-agent-readiness-after-390.png b/evidence/design/review-agent-readiness-after-390.png
similarity index 100%
rename from artifacts/design/review-agent-readiness-after-390.png
rename to evidence/design/review-agent-readiness-after-390.png
diff --git a/artifacts/design/review-agent-readiness-after-768.png b/evidence/design/review-agent-readiness-after-768.png
similarity index 100%
rename from artifacts/design/review-agent-readiness-after-768.png
rename to evidence/design/review-agent-readiness-after-768.png
diff --git a/artifacts/design/review-desktop-after-1440.png b/evidence/design/review-desktop-after-1440.png
similarity index 100%
rename from artifacts/design/review-desktop-after-1440.png
rename to evidence/design/review-desktop-after-1440.png
diff --git a/artifacts/design/review-desktop-final-1440.png b/evidence/design/review-desktop-final-1440.png
similarity index 100%
rename from artifacts/design/review-desktop-final-1440.png
rename to evidence/design/review-desktop-final-1440.png
diff --git a/artifacts/design/review-inline-overhaul-after-1280.png b/evidence/design/review-inline-overhaul-after-1280.png
similarity index 100%
rename from artifacts/design/review-inline-overhaul-after-1280.png
rename to evidence/design/review-inline-overhaul-after-1280.png
diff --git a/artifacts/design/review-inline-overhaul-after-1440.png b/evidence/design/review-inline-overhaul-after-1440.png
similarity index 100%
rename from artifacts/design/review-inline-overhaul-after-1440.png
rename to evidence/design/review-inline-overhaul-after-1440.png
diff --git a/artifacts/design/review-inline-overhaul-after-900.png b/evidence/design/review-inline-overhaul-after-900.png
similarity index 100%
rename from artifacts/design/review-inline-overhaul-after-900.png
rename to evidence/design/review-inline-overhaul-after-900.png
diff --git a/artifacts/design/review-inline-overhaul-audit-390.png b/evidence/design/review-inline-overhaul-audit-390.png
similarity index 100%
rename from artifacts/design/review-inline-overhaul-audit-390.png
rename to evidence/design/review-inline-overhaul-audit-390.png
diff --git a/artifacts/design/review-inline-overhaul-audit-768.png b/evidence/design/review-inline-overhaul-audit-768.png
similarity index 100%
rename from artifacts/design/review-inline-overhaul-audit-768.png
rename to evidence/design/review-inline-overhaul-audit-768.png
diff --git a/artifacts/design/review-inspector-readable-after-1440.png b/evidence/design/review-inspector-readable-after-1440.png
similarity index 100%
rename from artifacts/design/review-inspector-readable-after-1440.png
rename to evidence/design/review-inspector-readable-after-1440.png
diff --git a/artifacts/design/review-navigation-after-1440.png b/evidence/design/review-navigation-after-1440.png
similarity index 100%
rename from artifacts/design/review-navigation-after-1440.png
rename to evidence/design/review-navigation-after-1440.png
diff --git a/artifacts/design/review-result-polish-after-1440.png b/evidence/design/review-result-polish-after-1440.png
similarity index 100%
rename from artifacts/design/review-result-polish-after-1440.png
rename to evidence/design/review-result-polish-after-1440.png
diff --git a/artifacts/design/review-result-polish-after-390.png b/evidence/design/review-result-polish-after-390.png
similarity index 100%
rename from artifacts/design/review-result-polish-after-390.png
rename to evidence/design/review-result-polish-after-390.png
diff --git a/artifacts/design/review-result-polish-after-768.png b/evidence/design/review-result-polish-after-768.png
similarity index 100%
rename from artifacts/design/review-result-polish-after-768.png
rename to evidence/design/review-result-polish-after-768.png
diff --git a/.fleet/design-reviews/crash-recovery.json b/evidence/design/reviews/crash-recovery.json
similarity index 100%
rename from .fleet/design-reviews/crash-recovery.json
rename to evidence/design/reviews/crash-recovery.json
diff --git a/.fleet/design-reviews/desktop-navigation-clarity.json b/evidence/design/reviews/desktop-navigation-clarity.json
similarity index 100%
rename from .fleet/design-reviews/desktop-navigation-clarity.json
rename to evidence/design/reviews/desktop-navigation-clarity.json
diff --git a/.fleet/design-reviews/focus-desktop-product-surfaces.json b/evidence/design/reviews/focus-desktop-product-surfaces.json
similarity index 100%
rename from .fleet/design-reviews/focus-desktop-product-surfaces.json
rename to evidence/design/reviews/focus-desktop-product-surfaces.json
diff --git a/.fleet/design-reviews/landing-page.json b/evidence/design/reviews/landing-page.json
similarity index 100%
rename from .fleet/design-reviews/landing-page.json
rename to evidence/design/reviews/landing-page.json
diff --git a/.fleet/design-reviews/local-review-test-performance-check.json b/evidence/design/reviews/local-review-test-performance-check.json
similarity index 100%
rename from .fleet/design-reviews/local-review-test-performance-check.json
rename to evidence/design/reviews/local-review-test-performance-check.json
diff --git a/.fleet/design-reviews/review-inspector-readability.json b/evidence/design/reviews/review-inspector-readability.json
similarity index 100%
rename from .fleet/design-reviews/review-inspector-readability.json
rename to evidence/design/reviews/review-inspector-readability.json
diff --git a/.fleet/design-reviews/review-result-polish.json b/evidence/design/reviews/review-result-polish.json
similarity index 100%
rename from .fleet/design-reviews/review-result-polish.json
rename to evidence/design/reviews/review-result-polish.json
diff --git a/.fleet/design-review.json b/evidence/design/reviews/review-workbench-overhaul.json
similarity index 100%
rename from .fleet/design-review.json
rename to evidence/design/reviews/review-workbench-overhaul.json
diff --git a/.fleet/design-reviews/sidebar.json b/evidence/design/reviews/sidebar.json
similarity index 100%
rename from .fleet/design-reviews/sidebar.json
rename to evidence/design/reviews/sidebar.json
diff --git a/.fleet/design-reviews/trex-change-and-preview-verification.json b/evidence/design/reviews/trex-change-and-preview-verification.json
similarity index 100%
rename from .fleet/design-reviews/trex-change-and-preview-verification.json
rename to evidence/design/reviews/trex-change-and-preview-verification.json
diff --git a/artifacts/design/sidebar-after-1440.png b/evidence/design/sidebar-after-1440.png
similarity index 100%
rename from artifacts/design/sidebar-after-1440.png
rename to evidence/design/sidebar-after-1440.png
diff --git a/artifacts/design/sidebar-after-390.png b/evidence/design/sidebar-after-390.png
similarity index 100%
rename from artifacts/design/sidebar-after-390.png
rename to evidence/design/sidebar-after-390.png
diff --git a/artifacts/design/sidebar-after-768.png b/evidence/design/sidebar-after-768.png
similarity index 100%
rename from artifacts/design/sidebar-after-768.png
rename to evidence/design/sidebar-after-768.png
diff --git a/artifacts/design/structural-context-evaluation.html b/evidence/design/structural-context-evaluation.html
similarity index 100%
rename from artifacts/design/structural-context-evaluation.html
rename to evidence/design/structural-context-evaluation.html
diff --git a/artifacts/design/trex-after-1440.png b/evidence/design/trex-after-1440.png
similarity index 100%
rename from artifacts/design/trex-after-1440.png
rename to evidence/design/trex-after-1440.png
diff --git a/artifacts/design/trex-after-390.png b/evidence/design/trex-after-390.png
similarity index 100%
rename from artifacts/design/trex-after-390.png
rename to evidence/design/trex-after-390.png
diff --git a/artifacts/design/trex-after-768.png b/evidence/design/trex-after-768.png
similarity index 100%
rename from artifacts/design/trex-after-768.png
rename to evidence/design/trex-after-768.png
diff --git a/artifacts/design/trex-before-1440.png b/evidence/design/trex-before-1440.png
similarity index 100%
rename from artifacts/design/trex-before-1440.png
rename to evidence/design/trex-before-1440.png
diff --git a/artifacts/design/trex-result-1440.png b/evidence/design/trex-result-1440.png
similarity index 100%
rename from artifacts/design/trex-result-1440.png
rename to evidence/design/trex-result-1440.png
diff --git a/artifacts/design/usage-telemetry-after-1440.png b/evidence/design/usage-telemetry-after-1440.png
similarity index 100%
rename from artifacts/design/usage-telemetry-after-1440.png
rename to evidence/design/usage-telemetry-after-1440.png
diff --git a/artifacts/design/usage-telemetry-after-390.png b/evidence/design/usage-telemetry-after-390.png
similarity index 100%
rename from artifacts/design/usage-telemetry-after-390.png
rename to evidence/design/usage-telemetry-after-390.png
diff --git a/artifacts/design/usage-telemetry-after-768.png b/evidence/design/usage-telemetry-after-768.png
similarity index 100%
rename from artifacts/design/usage-telemetry-after-768.png
rename to evidence/design/usage-telemetry-after-768.png
diff --git a/artifacts/design/usage-telemetry-before-1440.png b/evidence/design/usage-telemetry-before-1440.png
similarity index 100%
rename from artifacts/design/usage-telemetry-before-1440.png
rename to evidence/design/usage-telemetry-before-1440.png
diff --git a/artifacts/performance/calorie-exercise-guidance-2026-08-10.md b/evidence/performance/calorie-exercise-guidance-2026-08-10.md
similarity index 100%
rename from artifacts/performance/calorie-exercise-guidance-2026-08-10.md
rename to evidence/performance/calorie-exercise-guidance-2026-08-10.md
diff --git a/artifacts/performance/old-local-portfolio-manifest.json b/evidence/performance/old-local-portfolio-manifest.json
similarity index 100%
rename from artifacts/performance/old-local-portfolio-manifest.json
rename to evidence/performance/old-local-portfolio-manifest.json
diff --git a/artifacts/performance/old-local-projects-results-2026-08-09.md b/evidence/performance/old-local-projects-results-2026-08-09.md
similarity index 100%
rename from artifacts/performance/old-local-projects-results-2026-08-09.md
rename to evidence/performance/old-local-projects-results-2026-08-09.md
diff --git a/artifacts/reviews/pr157-codevetter-review.png b/evidence/reviews/pr157-codevetter-review.png
similarity index 100%
rename from artifacts/reviews/pr157-codevetter-review.png
rename to evidence/reviews/pr157-codevetter-review.png
diff --git a/artifacts/reviews/pr173-codevetter-review.png b/evidence/reviews/pr173-codevetter-review.png
similarity index 100%
rename from artifacts/reviews/pr173-codevetter-review.png
rename to evidence/reviews/pr173-codevetter-review.png
From e960e643f68201dad64edb0cbd6f23b3a22095ff Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 13:41:06 +0530
Subject: [PATCH 05/37] docs: correct repo-structure and Blume paths to match
reality
The documented structure had drifted from the tree:
- agents.md's "Repo structure" block omitted benchmarks/, artifacts/,
docs-site/ and research/, and listed benchmark/ which has moved.
- README.md's "Monorepo Structure" listed openspec/, which does not exist.
- Both agents.md and docs/development/docs.md placed blume.config.ts at the
repo root. It actually lives at docs-site/blume.config.ts.
Also state the artifacts/ vs evidence/ split so the convention is discoverable
rather than folklore.
Verified with node scripts/check-docs.mjs (77 files, no broken links).
Co-Authored-By: Claude Opus 5 (1M context)
---
README.md | 6 ++++--
agents.md | 13 +++++++++----
docs/development/docs.md | 2 +-
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 3c61ff6d..79ff7365 100644
--- a/README.md
+++ b/README.md
@@ -106,8 +106,10 @@ apps/
desktop/ Tauri 2 + React 19 + Vite desktop app — the core product
landing-page-astro/ Astro marketing site (static export, deployed to Cloudflare Pages — codevetter.com)
docs/ Canonical knowledge system — see docs/index.md
-benchmark/ Public catch-rate benchmark cases + harness
-openspec/ Spec-driven workflow (specs + changes/archive)
+docs-site/ Blume presentation layer for docs/ (generated output is gitignored)
+benchmarks/ Evaluation corpora (public catch-rate, agent PRs, runtime challenges)
+evidence/ Committed run evidence (design, performance, reviews)
+scripts/ Benchmark + corpus + deploy + doc-validation scripts
```
> The legacy Next.js `apps/landing-page/` was removed on 2026-07-03. The
diff --git a/agents.md b/agents.md
index cd1bb055..ec65f709 100644
--- a/agents.md
+++ b/agents.md
@@ -56,14 +56,19 @@ apps/
tests/ # Playwright e2e tests
landing-page-astro/ # Astro marketing site → Cloudflare Pages (codevetter.com)
docs/ # Canonical knowledge system — see docs/index.md
-benchmark/ # Public catch-rate benchmark cases + harness
-scripts/ # Benchmark + deploy + doc-validation scripts
+docs-site/ # Blume presentation layer for docs/ (NOT the source of truth)
+benchmarks/ # Evaluation corpora — public-catch-rate/, agent-prs/,
+ # agent-tasks/, runtime-challenges/, context-*/, performance-lab/
+evidence/ # Committed run evidence: design/, performance/, reviews/
+scripts/ # Benchmark + corpus + deploy + doc-validation scripts
.github/workflows/ # ci, auto-release, release, deploy-landing, weekly, docs
-blume.config.ts # Blume presentation layer for docs/ (NOT the source of truth)
STATUS.md # Compatibility pointer
PROJECT_STATUS.md # Current/shipped product truth (fleet source of truth)
```
+`artifacts/` is gitignored scratch for CLI runs (`--out artifacts/...`).
+Committed evidence belongs in `evidence/`.
+
## Key commands
```bash
# From apps/desktop/
@@ -121,7 +126,7 @@ node scripts/check-docs.mjs # Validate docs (links, frontmatter, structure)
The committed Markdown under `docs/` is the **source of truth** for product
knowledge, architecture, decisions, workflows, operations, learnings, and
-failed approaches. Blume (`blume.config.ts`) is only the presentation/search
+failed approaches. Blume (`docs-site/blume.config.ts`) is only the presentation/search
layer — generated output (`.blume/`) is gitignored.
- **Navigation hub**: `docs/index.md`
diff --git a/docs/development/docs.md b/docs/development/docs.md
index 6fae096e..72081661 100644
--- a/docs/development/docs.md
+++ b/docs/development/docs.md
@@ -72,7 +72,7 @@ run `node_modules/.bin/blume validate`.
## Render with Blume
-Blume reads `blume.config.ts` at the repo root and renders `docs/` as a
+Blume reads `docs-site/blume.config.ts` and renders `docs/` as a
static site. It is **not** the source of truth — it only presents the
Markdown.
From d9f2b3659bc5711fd94534faa218e150c55035d3 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 13:41:07 +0530
Subject: [PATCH 06/37] chore(security): catch pk_ project keys in the pre-push
secret scan
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The scan covered sk-, ghp_, gho_, AKIA, AIzaSy, xoxb- and PEM headers but not
pk_, so the projectKey committed in foundry.json never tripped it. Add a
pk_[A-Za-z0-9]{32,} pattern so this class of key cannot leak again.
foundry.json is excluded for now, with a comment saying why: the key already in
it predates the pattern, and blocking every push until it is rotated would be
worse than tracking it. That exclusion should be removed once the key is
rotated at the provider and moved out of the tracked file — redacting it now
would not unpublish it, since it is already in committed history.
Also repoints the corpus exclusion at benchmarks/public-catch-rate/.
Co-Authored-By: Claude Opus 5 (1M context)
---
.husky/pre-push | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/.husky/pre-push b/.husky/pre-push
index 60232096..b0c49490 100755
--- a/.husky/pre-push
+++ b/.husky/pre-push
@@ -1,4 +1,8 @@
# Abort push if lint fails or a known secret pattern leaks into tracked files.
+#
+# NOTE: foundry.json is excluded below because it already contains a committed
+# projectKey (pk_...) that predates the pk_ pattern. Remove that exclusion once
+# the key is rotated and moved out of the tracked file.
set -e
if [ -f package.json ] && grep -q '"lint"' package.json; then
@@ -7,8 +11,8 @@ fi
SECRETS=$(git ls-files -z 2>/dev/null \
| xargs -0 grep -lE \
- 'sk-(proj-|ant-)?[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|gho_[A-Za-z0-9]{36}|AIzaSy[A-Za-z0-9_-]{33}|xoxb-[A-Za-z0-9-]+|-----BEGIN (RSA |EC )?PRIVATE KEY-----' 2>/dev/null \
- | grep -vE '(\.example$|\.sample$|/tests?/|/__tests__/|/fixtures?/|/mocks?/|/vendor/|/\.tmp-|^benchmark/|^apps/landing-page-astro/public/benchmark/|src/commands/secret_policy\.rs$)' \
+ 'sk-(proj-|ant-)?[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|gho_[A-Za-z0-9]{36}|AIzaSy[A-Za-z0-9_-]{33}|xoxb-[A-Za-z0-9-]+|pk_[A-Za-z0-9]{32,}|-----BEGIN (RSA |EC )?PRIVATE KEY-----' 2>/dev/null \
+ | grep -vE '(\.example$|\.sample$|/tests?/|/__tests__/|/fixtures?/|/mocks?/|/vendor/|/\.tmp-|^benchmarks/public-catch-rate/|^apps/landing-page-astro/public/benchmark/|src/commands/secret_policy\.rs$|^foundry\.json$)' \
|| true)
if [ -n "$SECRETS" ]; then
From 164e20ba70b4fdc14ad9cba5da0ebaf1ccefc432 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 14:45:18 +0530
Subject: [PATCH 07/37] docs(knowledge): record the third-party tooling
evaluations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bank the tooling research so it survives the session that produced it. Four
category pages plus a hub, all reachable from docs/index.md:
- tooling-decisions.md — adopt/reject summary and the constraints behind it
- tooling-secrets-and-supply-chain.md
- tooling-coverage.md
- tooling-agent-benchmarks.md
- tooling-documentation.md — the DeepWiki reject
Findings are dated 2026-08-30 and cite primary sources. Items the research
could not confirm are marked UNVERIFIED rather than stated as fact — notably
Devin/ACU pricing (429s on fetch), Socket pricing (403s), and whether
Grype/Syft carry telemetry.
Also adds a failed-approaches entry for the reason this was needed: the
DeepWiki question was researched twice, in April and August 2026, reaching the
same verdict both times, because the April survey sat in a top-level research/
directory that nothing linked to and check-docs never validated. That file is
now in docs/knowledge/ and indexed.
Co-Authored-By: Claude Opus 5 (1M context)
---
docs/index.md | 13 ++
docs/knowledge/failed-approaches.md | 15 ++
docs/knowledge/tooling-agent-benchmarks.md | 124 ++++++++++++++
docs/knowledge/tooling-coverage.md | 153 ++++++++++++++++++
docs/knowledge/tooling-decisions.md | 98 +++++++++++
docs/knowledge/tooling-documentation.md | 96 +++++++++++
.../tooling-secrets-and-supply-chain.md | 146 +++++++++++++++++
7 files changed, 645 insertions(+)
create mode 100644 docs/knowledge/tooling-agent-benchmarks.md
create mode 100644 docs/knowledge/tooling-coverage.md
create mode 100644 docs/knowledge/tooling-decisions.md
create mode 100644 docs/knowledge/tooling-documentation.md
create mode 100644 docs/knowledge/tooling-secrets-and-supply-chain.md
diff --git a/docs/index.md b/docs/index.md
index ddcb622d..7e3f4d39 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -81,6 +81,19 @@ is only the presentation and search layer.
- [competitive-landscape.md](./knowledge/competitive-landscape.md) — AI code review competitive landscape.
- [performance-lab-publication.md](./knowledge/performance-lab-publication.md) —
published optimization experiments, external PRs, and evidence boundaries.
+- [tooling-decisions.md](./knowledge/tooling-decisions.md) — what CodeVetter
+ embeds instead of building, what it refuses, and why. Hub for the four
+ evaluations below.
+- [tooling-secrets-and-supply-chain.md](./knowledge/tooling-secrets-and-supply-chain.md)
+ — secret scanners and dependency/vulnerability scanners.
+- [tooling-coverage.md](./knowledge/tooling-coverage.md) — coverage collection
+ across Rust/TS/Python, the LCOV transport decision, diff-coverage traps.
+- [tooling-agent-benchmarks.md](./knowledge/tooling-agent-benchmarks.md) —
+ public agent benchmark corpora, graded on determinism and licensing.
+- [tooling-documentation.md](./knowledge/tooling-documentation.md) — the
+ DeepWiki reject and what would fit instead.
+- [codebase-context-tools-landscape.md](./knowledge/codebase-context-tools-landscape.md)
+ — April 2026 survey of codebase indexing and context tooling.
### Learnings
diff --git a/docs/knowledge/failed-approaches.md b/docs/knowledge/failed-approaches.md
index 4b528312..02b3c3af 100644
--- a/docs/knowledge/failed-approaches.md
+++ b/docs/knowledge/failed-approaches.md
@@ -117,6 +117,21 @@ and the constraint it leaves behind. Link here when rejecting a similar idea.
- **Constraint**: do not reintroduce `tauri-driver`. See
[development/testing.md](../development/testing.md).
+## Research parked outside `docs/` gets re-done
+
+- **What broke**: the DeepWiki adoption question was researched twice — once in
+ April 2026, again in August 2026 — reaching the same reject verdict both
+ times.
+- **Root cause**: the April survey was committed to a top-level `research/`
+ directory that nothing linked to and `scripts/check-docs.mjs` never
+ validated. It was invisible at the moment the question was re-asked.
+- **Fix**: moved to
+ [codebase-context-tools-landscape.md](./codebase-context-tools-landscape.md)
+ and linked from `docs/index.md`; `research/` removed.
+- **Constraint**: evaluations and surveys go in `docs/knowledge/` with
+ frontmatter and an index entry. A finding that is not reachable from
+ `docs/index.md` will be paid for twice.
+
## More lessons
See also [`LESSONS.md`](https://github.com/Codevetter/codevetter/blob/main/docs/archive/LESSONS.md) for older entries
diff --git a/docs/knowledge/tooling-agent-benchmarks.md b/docs/knowledge/tooling-agent-benchmarks.md
new file mode 100644
index 00000000..a4ae6d88
--- /dev/null
+++ b/docs/knowledge/tooling-agent-benchmarks.md
@@ -0,0 +1,124 @@
+---
+title: Agent benchmark corpora
+description: Evaluation of public agent/web benchmarks for licensing, deterministic grading, and offline reproducibility.
+sidebar:
+ order: 13
+---
+
+# Agent benchmark corpora
+
+Verified **2026-08-30**. See [tooling-decisions.md](./tooling-decisions.md) for
+the cross-category summary.
+
+CodeVetter grades with **executable evidence, not LLM opinion**. That filter
+eliminates most of this field immediately: a benchmark whose scorer is a GPT
+judge cannot supply ground truth for a product built on determinism. The second
+filter is offline reproducibility — benchmarks driving live third-party websites
+decay silently as those sites change.
+
+## Adopt
+
+### τ³-bench (tau2-bench) — best licensing and determinism profile
+
+**MIT** for code and data, data shipped in-repo under `data/tau2/domains/`.
+1,909★, pushed 2026-08-27, very active.
+
+Grading is **deterministic by default**. `reward_basis` defaults to
+`["DB", "COMMUNICATE"]`: the DB evaluator replays the gold actions on a *fresh*
+environment to derive a target end state, then compares **by hash** — so any
+trajectory producing an equivalent end state passes. `COMMUNICATE` is substring
+match. The only LLM-judged evaluator, `NL_ASSERTION`, is marked experimental and
+is **off by default**.
+
+- **No websites, no Docker.** Everything is simulated local tool APIs.
+- Caveat: the **user simulator is an LLM** via LiteLLM. LiteLLM can point at a
+ local model, so this stays compatible with an offline deployment.
+- Task counts: airline 50, retail 114, telecom 114 base (2,285 full),
+ banking_knowledge 97. Use the `base` split.
+- Versioned grading discipline worth imitating: v1.0.1 (July 2026) fixed
+ `banking_knowledge` grading, and results below 1.0.1 are **not comparable**
+ with those at or above it. A `pre-v1.0.1` tag reproduces old behaviour.
+
+**τ-bench v1 is deprecated by its own authors** — its README directs users to
+τ³-bench. Do not adopt v1.
+
+### Terminal-Bench 4.0 (via Harbor) — cleanest deterministic grader
+
+**Apache-2.0** for the harness and all task sets. This is the strongest
+execution-backed grader in the survey: each task has `tests/test.sh` +
+`tests/test_outputs.py`; `test.sh` runs pytest and writes `1` or `0` to
+`/logs/verifier/reward.txt`. Verifiers run in their own container
+(`environment_mode = "separate"`). **No LLM judge anywhere.**
+
+The topology changed substantially, and stale knowledge here is likely:
+
+- The repo **moved orgs** — `laude-institute/terminal-bench` now redirects to
+ `harbor-framework/terminal-bench-1` (legacy v1).
+- **The harness is now Harbor** (`harbor-framework/harbor`, Apache-2.0,
+ 4,767★, v0.22.0 on 2026-08-22).
+- Task sets are **separate Apache-2.0 dataset repos**: terminal-bench-2 (89
+ tasks), terminal-bench-2-1 (91), and the continuous `terminal-bench` (68 live
+ + 90 archived, v4.0.0 on 2026-08-26). tbench.ai shows **4.0** as the active
+ leaderboard.
+- `terminal-bench-core` naming is legacy v1. The modern registry is the Harbor
+ Hub, addressed as `terminal-bench/terminal-bench@latest`.
+
+**The one real cost: it is not offline as shipped.** The task template sets
+`network_mode = "public"`, all 89 TB-2.0 tasks set `allow_internet = true`, and
+the verifier itself runs `apt-get update` and curls `astral.sh`. These are
+*package-registry* dependencies rather than live websites — far more tractable
+than the rejected benchmarks below, but pre-baking images and mirroring
+apt/PyPI is real work.
+
+Worth copying: oracle solutions ship with every task, and maintainers recommend
+`--agent oracle -k 5` to validate a sandbox before trusting any result.
+
+## Viable with work
+
+- **TheAgentCompany** (MIT, 175 tasks) has the **strongest offline environment**
+ of any multi-app benchmark — a whole simulated company running locally
+ (GitLab, Plane, ownCloud, RocketChat) with pre-baked data and no third-party
+ sites. But its grader is **hybrid**: deterministic checkpoints *plus* LLM
+ evaluators, and evaluation requires LiteLLM credentials. Usable only if the
+ deterministic checkpoints are isolated. Needs 30+ GB disk.
+- **Mind2Web (text)** — code MIT, dataset **CC-BY-4.0**, fully static cached
+ HTML traces, deterministic metrics. Genuinely offline. But it grades *action
+ prediction on frozen traces*, which is a different kind of evidence than
+ runtime behaviour. **Avoid `Multimodal-Mind2Web` — it is OpenRAIL**, a
+ use-restricted license, not CC-BY.
+- **WebArena-Verified + BrowserGym/MiniWoB** — Apache-2.0, self-hosted Docker
+ sites. A deterministic subset exists if `fuzzy_match`/`ua_match` tasks are
+ dropped (those call an LLM) and the map site is excluded (it needs a tile and
+ routing backend). MiniWoB is the only trivially-offline env in BrowserGym.
+ Prefer ServiceNow's cleaned `webarena-verified` over vanilla WebArena.
+- **OSWorld** — Apache-2.0 for code *and* data, active, 369 tasks, execution-
+ based metrics. Heavy: needs a VM. Use `test_nogdrive.json` (361 tasks) to
+ drop the Google-account dependency.
+
+## Reject
+
+| Benchmark | Reason |
+|---|---|
+| **WebVoyager** | GPT-4V judge; drives real Amazon/Booking/Google Flights. Last commit 2024-03-04. README admits time-sensitive tasks need manual date edits — not reproducible |
+| **Mind2Web 2** | Agent-as-a-Judge, requires `OPENAI_API_KEY`, live agentic search |
+| **WebCanvas / Mind2Web-Live** | Live web by design; dormant since 2025-02-06, so task validity has almost certainly decayed |
+| **WorkArena** | Requires a **live cloud ServiceNow instance**; instance dataset is `gated: manual` with **no license field** on the HF card |
+| **VisualWebArena** | MIT and usable, but no push since 2024-11-09 |
+| **WindowsAgentArena** | Requires each user to fetch their own Windows 11 Eval ISO (90-day expiry) — cannot be redistributed |
+
+## Licensing landmines
+
+These are the items where a reasonable assumption is wrong:
+
+- 🚨 **Meta OpenApps — CC-BY-NC-4.0.** Commercial use prohibited. Painful,
+ because it is exactly the self-hosted offline app suite this product wants.
+- 🚨 **TimeWarp — no LICENSE file at all.** All rights reserved by default.
+- ⚠️ **Multimodal-Mind2Web is OpenRAIL**, while the text Mind2Web is CC-BY-4.0.
+ It does not inherit the permissive terms.
+- ⚠️ **WorkArena-Instances** — HF card carries **no license field**.
+- ⚠️ **AgentBench** — the repo is Apache-2.0, but three environments recompile
+ third-party datasets (WebShop, Mind2Web, ALFWorld) **without restating their
+ upstream licenses**. Repo-level Apache-2.0 does not cover the bundled `data/`.
+- ℹ️ **BrowserGym and WorkArena report `NOASSERTION` via the GitHub API** —
+ this is a false negative caused by the Apache short-form header. Both LICENSE
+ files are Apache-2.0. Do not propagate the API's reading.
diff --git a/docs/knowledge/tooling-coverage.md b/docs/knowledge/tooling-coverage.md
new file mode 100644
index 00000000..fa3f40d1
--- /dev/null
+++ b/docs/knowledge/tooling-coverage.md
@@ -0,0 +1,153 @@
+---
+title: Code coverage tooling
+description: Coverage collection across Rust, TypeScript and Python, the LCOV transport decision, and the two traps that produce false verdicts.
+sidebar:
+ order: 12
+---
+
+# Code coverage tooling
+
+Verified **2026-08-30**. See [tooling-decisions.md](./tooling-decisions.md) for
+the cross-category summary.
+
+Coverage matters to CodeVetter for one specific question: **did the agent's
+change actually get exercised?** That is changed-line coverage, not project
+coverage, and it shapes every decision below.
+
+## The stack
+
+Collect with per-ecosystem native tooling, normalise everything to **LCOV**, and
+parse it in the Rust backend:
+
+| Layer | Choice | License |
+|---|---|---|
+| Rust collection | `cargo-llvm-cov` | MIT OR Apache-2.0 |
+| JS/TS collection | per-runner native (vitest/jest v8), `c8` as universal fallback | MIT / ISC |
+| Python collection | `coverage.py` | Apache-2.0 |
+| Transport | LCOV + a JSON summary | (format, unlicensed) |
+| Parsing | Rust `lcov` crate | MIT OR Apache-2.0 |
+| Diff coverage | **compute in-backend** | — |
+
+LCOV is the only format every ecosystem emits, which is the entire reason to
+choose it. It has **no formal specification** — the de-facto definition is the
+`geninfo(1)` man page, in prose, and lcov 2.x has extended it. Pin behaviour
+with your own fixtures rather than trusting a parser to match.
+
+## Rust — `cargo-llvm-cov`
+
+Dual MIT/Apache-2.0, v0.9.0 (2026-08-16). A thin wrapper over LLVM source-based
+coverage: `--lcov` is literally `llvm-cov export -format=lcov`, `--json` is
+`-format=text`.
+
+Best sidecar candidate in this whole evaluation: it publishes a
+**`universal-apple-darwin`** tarball per release, releases are immutable, and
+releases since 0.8.5 carry GitHub artifact attestations verifiable with
+`gh attestation verify`.
+
+- **Offline caveat:** requires the `llvm-tools-preview` rustup component. If
+ absent it may try to install it. **Pre-flight check for this component before
+ promising an offline run.**
+- `cargo llvm-cov show-env` → run any command → `cargo llvm-cov report --lcov`
+ is the right shape for "run the agent's own test command, then extract
+ evidence."
+- **Do not build verdicts on Rust branch coverage.** `--branch` is unstable and
+ nightly-only; `--doctests` is listed under known limitations. Both are
+ explicitly flagged upstream.
+- `cargo llvm-cov nextest` is first-class, but **nextest does not support
+ doctests** — run those separately and merge.
+
+**`cargo-tarpaulin` is a viable cross-check, and the "Linux x86_64 only" belief
+about it is out of date.** Its LLVM engine is the default on macOS and Windows,
+and 0.37.2 ships `aarch64-apple-darwin` and `universal-apple-darwin` binaries.
+The ptrace restriction is Linux-only. Position it as secondary — `cargo-llvm-cov`
+is closer to the LLVM metal with roughly 2.5× the download volume.
+
+## JavaScript / TypeScript
+
+`c8` (ISC) is **not stale** — v12.0.0 shipped 2026-07-14. Its value here is that
+it **wraps any command** (`c8 npm test`, `c8 node --test`, `c8 vitest`) with no
+instrumentation and no runner integration, which is exactly right for a harness
+that must run someone else's test command unmodified.
+
+Node's built-in `--experimental-test-coverage` is the zero-dependency baseline.
+Note it is still `Stability: 1 – Experimental` in Node 22, 24 and 26 despite the
+test runner itself being stable. There is **no `--test-coverage-lcov` flag** —
+LCOV comes from the reporter: `--test-reporter=lcov
+--test-reporter-destination=lcov.info`. That reporter emits no test results, so
+pair it with a second reporter. `NODE_V8_COVERAGE` auto-propagates to
+`child_process.spawn` subprocesses, which is genuinely useful when the agent's
+test command shells out.
+
+On the "istanbul is dead" claim — half wrong, and worth stating precisely.
+`nyc` shipped a v18.0.0 major on 2026-02-22. The **`istanbuljs` monorepo
+underneath it** is what stalled: last commit 2025-08-18, 201 open issues, and
+Vitest found it necessary to maintain its own fork. Either way, avoid `nyc` as a
+primary path — it requires injecting a Babel plugin into someone else's build,
+which is precisely the invasive change a verification harness should not make.
+
+Vitest's v8 provider has done AST-aware remapping since v3.2.0 and its docs
+claim parity with Istanbul, which removes the historical reason to pay the
+instrumentation tax.
+
+## Python — `coverage.py`
+
+Apache-2.0, v7.16.0. **The repo moved to
+`github.com/coveragepy/coveragepy`.** Prefer driving `coverage run -m pytest`
+directly over `pytest-cov` — one less layer, identical output, and it works for
+non-pytest suites.
+
+Relevant if runtime cost is part of your evidence: on **Python 3.14+ the
+`sysmon` (PEP 669) core is the default** and dramatically cheaper; 3.10–3.13 use
+the C tracer. The same repo will show very different overhead across Python
+versions, so **record the active core** in the bundle.
+
+Note `--fail-under` exits with status **2**, not 1.
+
+## Rejected — hosted services
+
+**Codecov and Coveralls both upload coverage data off-machine.** For a
+local-first product they are architecturally disqualified, not merely
+inconvenient. Their uploader binaries are permissively licensed, so they *could*
+be vendored — but every one exists solely to make that network call. There is
+nothing to salvage.
+
+Codecov specifically: their security page says they do not store source code,
+but archived raw uploads may contain it, and the Impact Analysis path sends
+per-line execution counts with file paths. Their self-hosted option is a trap —
+the commercial on-prem offering is end-of-lifed and bare-metal/HA deployments
+are no longer supported. Note also the 2021 Bash Uploader compromise: a coverage
+uploader was the supply-chain vector. Directly on point for why a verification
+tool should not phone home.
+
+**Do not bundle `lcov` / `genhtml` / `geninfo`** — the Perl toolchain is
+GPL-2.0. The format carries no license; the Rust `lcov` crate reads and writes
+it under MIT/Apache-2.0.
+
+## Diff coverage — own this
+
+`diff-cover` (Apache-2.0, active) is the best external option and reads LCOV
+directly. **Use it as a cross-check oracle in the test suite, not as a runtime
+dependency** — it is Python, and this metric is core product logic.
+
+The computation is small and fully deterministic:
+
+```
+git diff -U0 .. → {file: set}
+lcov crate parse(lcov.info) → {file: {line_no: hit_count}}
+intersect → covered_changed / total_changed
+ + the exact uncovered line list
+```
+
+## Two traps that produce false verdicts
+
+1. **V8 coverage only reports files that were *loaded*.** A source file the
+ tests never import is simply **absent**, which is indistinguishable from 0%.
+ An agent that adds a brand-new untested module would therefore score
+ *better*. Force never-loaded files into the report: `--all --src` (c8),
+ `--test-coverage-include-all` (Node), `coverage.all` (vitest),
+ `collectCoverageFrom` (jest).
+2. **Line-granular LCOV under-reports on dense lines.** For "did this exact
+ changed expression run?", `DA:` records lose sub-line detail. Store the
+ high-precision artifact alongside LCOV where available —
+ `cargo-llvm-cov --json` is LLVM region-level; monocart's `v8-json` preserves
+ byte ranges.
diff --git a/docs/knowledge/tooling-decisions.md b/docs/knowledge/tooling-decisions.md
new file mode 100644
index 00000000..b717a940
--- /dev/null
+++ b/docs/knowledge/tooling-decisions.md
@@ -0,0 +1,98 @@
+---
+title: Third-party tooling decisions
+description: What CodeVetter embeds instead of building, what it refuses, and why — the hub page for per-category evaluations.
+sidebar:
+ order: 10
+---
+
+# Third-party tooling decisions
+
+CodeVetter should embed proven tools rather than reimplement them, but the
+product's positioning narrows the field hard. Two constraints disqualify most
+of the market before features are even considered:
+
+1. **Privacy is the product.** CodeVetter verifies code on the user's machine.
+ Any tool that transmits source, manifests, or lockfiles to a third party is
+ rejected regardless of quality.
+2. **Local-first and offline.** The desktop app works without a network. Tools
+ requiring a hosted engine, an account, or a live API are rejected.
+
+A third constraint governs licensing: this is a commercial desktop product that
+**redistributes** what it bundles. AGPL, SSPL, and non-commercial licenses are
+blockers. MPL and GPL are subprocess-only at best.
+
+Research verified **2026-08-30**. Licensing, pricing, and maintenance facts
+decay — re-check before acting on anything here. Items the research could not
+confirm are marked UNVERIFIED on the detail pages and should be treated as open
+questions, not findings.
+
+## Adopt
+
+| Tool | License | Surface | Category detail |
+|---|---|---|---|
+| `cargo-audit` (via `rustsec` crate) | MIT OR Apache-2.0 | In-process in `src-tauri/` | [supply chain](./tooling-secrets-and-supply-chain.md) |
+| `gitleaks` | MIT | Sidecar binary | [supply chain](./tooling-secrets-and-supply-chain.md) |
+| `cargo-llvm-cov` | MIT OR Apache-2.0 | Sidecar binary | [coverage](./tooling-coverage.md) |
+| `lcov` crate | MIT OR Apache-2.0 | In-process parser | [coverage](./tooling-coverage.md) |
+| τ³-bench (tau2-bench) | MIT | Corpus under `benchmarks/` | [agent benchmarks](./tooling-agent-benchmarks.md) |
+| Terminal-Bench 4.0 (Harbor) | Apache-2.0 | Corpus under `benchmarks/` | [agent benchmarks](./tooling-agent-benchmarks.md) |
+
+`cargo-audit` is the highest-leverage item: the `rustsec` crate runs inside the
+existing Rust backend with no new process boundary, no sidecar to codesign, and
+no subprocess. Its SARIF 2.1.0 output is real but undocumented in the README and
+absent from the changelog — pin `>= 0.22.0` and trust the source, not the docs.
+
+## Reject
+
+| Tool | Reason |
+|---|---|
+| TruffleHog | AGPL-3.0, **and** verifies secrets against live provider APIs by default |
+| ggshield | Hosted detection engine; file content necessarily transmitted |
+| socket.dev | Hosted; uploads manifests and lockfiles |
+| Codecov / Coveralls | Exist to upload coverage data off-machine |
+| npm / pnpm audit | No offline mode; npm's fallback path uploads the full dependency tree plus machine metadata |
+| `lcov` / `genhtml` Perl tooling | GPL-2.0 — do not bundle (the *format* is unencumbered) |
+| Meta OpenApps | CC-BY-NC-4.0, commercial use prohibited |
+| DeepWiki | Hosted; private repos need a paid Devin account — see [documentation tooling](./tooling-documentation.md) |
+| WorkArena, WebVoyager | Require live third-party websites or hosted SaaS |
+| detect-secrets | Dormant since 2024; no SARIF |
+| Nosey Parker | Archived 2026-04-24, superseded by Titus |
+
+## Adopt only with explicit configuration
+
+- **Trivy** ships telemetry **on by default**, contacting `check.trivy.dev`.
+ Requires `--skip-version-check --disable-telemetry`. Separately,
+ `--offline-scan` does *not* mean offline — it only suppresses
+ dependency-identification API calls, not DB downloads or telemetry.
+- **Terminal-Bench** needs network access **at verification time**. Its task
+ template sets `network_mode = "public"`, all 89 TB-2.0 tasks set
+ `allow_internet = true`, and the verifier's own `test.sh` runs `apt-get
+ update` and curls `astral.sh`. These are package-registry dependencies rather
+ than live websites, so pre-baking images is tractable — but it is real work,
+ not a flag.
+- **cdxgen v13** requires `pnpm >= 11` and `node >= 24`, which conflicts with
+ this repo's `pnpm@10.33.2`. Pin `@cyclonedx/cdxgen@12.x`, or prefer Syft.
+
+## What not to outsource
+
+Changed-line coverage — the metric that answers "did the agent's change
+actually get exercised?" — should be computed in the Rust backend, not
+delegated. It is a small deterministic join: `git diff -U0` yields changed
+lines, LCOV yields hit counts, intersect them. It is the core verdict input, it
+must be reproducible and explainable inside the evidence bundle, and it must not
+depend on a Python install existing on the user's machine. Use `diff-cover`
+(Apache-2.0) as a cross-check oracle in the test suite instead of a runtime
+dependency.
+
+Two traps that produce false verdicts if ignored are documented in
+[coverage](./tooling-coverage.md): V8's loaded-files-only blind spot, and
+LCOV's line-granularity loss on dense lines.
+
+## Related
+
+- [codebase-context-tools-landscape.md](./codebase-context-tools-landscape.md)
+ — April 2026 survey of codebase indexing and context tooling. Its DeepWiki
+ assessment was independently reconfirmed in August 2026.
+- [failed-approaches.md](./failed-approaches.md) — constraints left behind by
+ things that broke. Check before adopting anything that touches the package
+ manager or the data layer.
diff --git a/docs/knowledge/tooling-documentation.md b/docs/knowledge/tooling-documentation.md
new file mode 100644
index 00000000..7e014b72
--- /dev/null
+++ b/docs/knowledge/tooling-documentation.md
@@ -0,0 +1,96 @@
+---
+title: Documentation tooling — the DeepWiki decision
+description: Why DeepWiki is not adopted for CodeVetter's documentation, and what would fit if auto-generated architecture docs are wanted.
+sidebar:
+ order: 14
+---
+
+# Documentation tooling — the DeepWiki decision
+
+Verified **2026-08-30**. See [tooling-decisions.md](./tooling-decisions.md) for
+the cross-category summary.
+
+**Verdict: reject** DeepWiki as a documentation pipeline dependency. The only
+form that composes with the existing stack is a passive outbound link (a README
+or landing badge to `deepwiki.com/Codevetter/codevetter`), not an integration.
+
+## Why
+
+### The privacy question is subtler than it first appears
+
+CodeVetter's own repository is **public**, so the free hosted deepwiki.com and
+its MCP server (`https://mcp.deepwiki.com/mcp`) already work on it today with
+zero setup. The private-repo blocker does not bite *this* repo.
+
+It bites hard the moment DeepWiki-style indexing touches the product's actual
+privacy-sensitive surface: **the user repositories being reviewed**. Adopting
+the pattern for our own docs normalises a dependency that cannot be extended to
+the product itself without contradicting its central promise.
+
+### Private repos are paid, and nothing runs offline
+
+Private repositories require a **paid Devin account** (ACU-billed). The free
+public MCP server and web UI work only on public repos.
+
+**Exact pricing is UNVERIFIED** — both `devin.ai/pricing` and
+`cognition.com/pricing` returned HTTP 429 to every fetch attempt.
+
+Nothing about the deepwiki.com product runs offline. The only offline-capable
+option is a **different, independent project** (`AsyncFuncAI/deepwiki-open`),
+not the hosted product.
+
+### It fails on process grounds independently of privacy
+
+Even setting privacy aside, DeepWiki conflicts with this repo's own documented
+rules:
+
+- **"Markdown under `docs/` is the source of truth."** A hosted generated wiki
+ is a second, non-authoritative home for the same facts.
+- **"One canonical home per fact."** It duplicates by construction.
+- It is invisible to `scripts/check-docs.mjs` and to Blume's navigation, so
+ nothing validates its links or keeps it in the sidebar.
+
+## This was already known
+
+[`codebase-context-tools-landscape.md`](./codebase-context-tools-landscape.md)
+assessed DeepWiki in **April 2026** and reached the same conclusion. That
+document sat in a top-level `research/` directory that nothing linked to, so the
+finding was effectively lost and the question got asked again.
+
+The August 2026 re-check confirmed the April verdict still holds, and that the
+three self-hosted alternatives it named remain active:
+
+| Project | Stars | License | Last push |
+|---|---|---|---|
+| `AsyncFuncAI/deepwiki-open` | 17.8k | MIT | 2026-08-16 |
+| `AIDotNet/OpenDeepWiki` | 3.5k | MIT | 2026-08-27 |
+| `sopaco/deepwiki-rs` | 1.7k | MIT | 2026-08-14 |
+
+The reusable lesson is filed in
+[failed-approaches.md](./failed-approaches.md): research that lives outside
+`docs/` gets re-done.
+
+## If auto-generated architecture docs are still wanted
+
+**`sopaco/deepwiki-rs`** (MIT) is the closest fit. Use it as a **generator, not
+a service**:
+
+1. Run it locally to produce Mermaid/C4 markdown.
+2. Commit the output into `docs/architecture/`.
+3. Let it go through normal PR review like any other change.
+
+That keeps markdown as the source of truth, keeps `check-docs.mjs` and Blume in
+control of validation and navigation, and adds no runtime dependency or network
+call. **Never embed it as a live service** — that reintroduces every problem
+listed above.
+
+`AsyncFuncAI/deepwiki-open` ships Ollama Docker configs and is the option to
+look at if fully local model-driven generation is ever wanted, at the cost of
+running a container stack.
+
+## Method note
+
+WebSearch was already at its session budget cap when this was verified, so all
+facts came from direct fetches of primary sources (deepwiki.com, docs.devin.ai)
+and `gh api` / `gh search` against GitHub. No claims here come from model
+memory. Pricing remains the one unverified item.
diff --git a/docs/knowledge/tooling-secrets-and-supply-chain.md b/docs/knowledge/tooling-secrets-and-supply-chain.md
new file mode 100644
index 00000000..ebfbb8c4
--- /dev/null
+++ b/docs/knowledge/tooling-secrets-and-supply-chain.md
@@ -0,0 +1,146 @@
+---
+title: Secret scanning and supply-chain tooling
+description: Evaluation of secret scanners and dependency/vulnerability scanners against CodeVetter's offline and privacy constraints.
+sidebar:
+ order: 11
+---
+
+# Secret scanning and supply-chain tooling
+
+Verified **2026-08-30**. See [tooling-decisions.md](./tooling-decisions.md) for
+the cross-category summary and the constraints that drive these calls.
+
+The headline: a common assumption going in was that several core scanners had
+relicensed to something restrictive. Checked against LICENSE files at HEAD, that
+is **wrong** — Trivy, Grype, Syft, osv-scanner, cdxgen, Dependency-Track,
+detect-secrets, Titus, and Kingfisher are all Apache-2.0, and Gitleaks is still
+MIT. TruffleHog is AGPL-3.0, but has been since v3.0 in 2021.
+
+What actually matters is different and less obvious: **default network
+behaviour**. Several tools phone home or validate credentials against live
+provider APIs unless told not to.
+
+## Recommended
+
+### `cargo-audit` — embed in the Rust backend
+
+Dual **MIT OR Apache-2.0**. The highest-leverage item in this category because
+the underlying `rustsec` crate is a **library**: it runs in-process in
+`src-tauri/` with no sidecar binary to codesign and notarize, and no subprocess.
+
+- **SARIF 2.1.0 output exists but is undocumented.** It is absent from the
+ README and the CHANGELOG stops before it landed (~Sept 2025). Verified in
+ `cargo-audit/src/sarif.rs`. Pin `>= 0.22.0`.
+- Offline: `--no-fetch --stale`, or `database.fetch = false` in `audit.toml`.
+- The advisory DB is a git clone of
+ [RustSec/advisory-db](https://github.com/RustSec/advisory-db) at
+ `~/.cargo/advisory-db` — trivially vendorable and shippable.
+- Pair with **cargo-deny** (`--offline`) for SPDX license-policy enforcement,
+ which nothing else here does for Rust. Note its output is structured JSON log
+ lines, **not SARIF** — the mapping would be yours to write.
+
+### `gitleaks` — bundle as a sidecar
+
+**MIT**, and the core scanner's license is unchanged. Fully offline: no DB, no
+network, rules embedded or from `.gitleaks.toml`. Emits SARIF. Static Go binary,
+same integration shape as the existing `ccusage` sidecar.
+
+One licensing nuance worth stating precisely, because it is widely misreported:
+the commercial relicensing applies **only to `gitleaks/gitleaks-action` v2.0.0+**
+(MIT → proprietary EULA). Invoking the MIT Go binary directly is unencumbered.
+
+Caution: v8.30.1 shipped 2026-03-21 and recent commits are largely Dependabot.
+Not stale, but feature velocity has slowed.
+
+## Rejected
+
+### TruffleHog — two independent blockers
+
+**AGPL-3.0** (LICENSE at `main` verified). Bundling an AGPL binary in a
+distributed proprietary desktop app is a genuine legal question — subprocessing
+an unmodified binary is the lowest-risk posture, but redistribution still
+carries source-offer obligations. Get counsel before shipping.
+
+The second blocker is worse and is about defaults: "verified" in TruffleHog
+means it **tested the candidate credential against the live provider API** — the
+AWS detector performs a real `GetCallerIdentity` call. In practice, strings from
+the user's private source are transmitted to AWS, GitHub, Slack and hundreds of
+others **by default**. Mitigable with `--no-verification`, but it is opt-out, and
+one missing flag is a privacy incident.
+
+### ggshield and socket.dev — hosted engines
+
+`ggshield`'s MIT license covers **the client only**; detection runs server-side
+and requires a GitGuardian API key. Their docs are precisely worded — "your
+files and secrets won't be stored" is a statement about *retention*, not
+transmission. File content necessarily crosses the wire. No offline mode.
+
+socket.dev uploads manifests and lockfiles (not full source, per their docs).
+Also note: `SocketDev/socket-cli` has **no LICENSE file at repo root** while the
+published npm packages declare MIT — do not rely on the MIT claim.
+Pricing is **UNVERIFIED** (`socket.dev/pricing` returns 403 to automated fetch).
+
+### npm / pnpm audit — the fallback is the hazard
+
+The default bulk path sends package names and versions, which is acceptable. But
+npm's **Quick Audit fallback**, triggered automatically when bulk fails, submits
+*"the full package tree as found in `package-lock.json`"* plus `npm_version`,
+`node_version`, `platform`, `arch`, `node_env`. A complete dependency graph and
+machine fingerprint, triggered by a transient failure outside your control.
+
+**No offline mode exists for either.** For an offline story, read the lockfile
+locally with osv-scanner or grype instead.
+
+### Others
+
+- **detect-secrets** — Apache-2.0 and fully offline, but last release
+ 2024-05-06, 178 open issues, no SARIF, and it is Python (a runtime to bundle).
+- **Nosey Parker** — **archived 2026-04-24**; README directs users to Titus.
+- **Dependency-Track** — Apache-2.0 and active, but it is a **JVM API server
+ plus separate frontend** needing 8GB RAM and external Postgres. A non-starter
+ inside a Tauri app. Plausible only as an optional external SBOM sink.
+
+## Viable alternatives, with eyes open
+
+- **Grype + Syft** (Apache-2.0) have the cleanest offline story in the vuln set:
+ single static Go binaries, no daemon, `GRYPE_DB_AUTO_UPDATE=false` for
+ air-gap, and Syft needs no DB at all. Grype emits SARIF.
+ **UNVERIFIED:** whether either has telemetry. None was found, but their source
+ was not audited the way Trivy's was — confirm before making any "zero outbound
+ connections" claim.
+- **Kingfisher** (MongoDB, Apache-2.0) is **written in Rust and exposes library
+ crates**, so it could scan in-process like `cargo-audit`. Uniquely, its
+ network validators are behind optional cargo features, meaning they can be
+ **compiled out entirely** — a compile-time guarantee stronger than any runtime
+ flag. Two caveats: validation is **on by default** (opt out via
+ `--no-validate`), and it is **not on crates.io** — use a git dependency; the
+ unrelated `kingfisher` crate on crates.io is a different package.
+- **Titus** (Praetorian, Apache-2.0) is the Nosey Parker successor with the best
+ defaults in the category — **validation is opt-in**. Risk: created 2026-01-25,
+ ~7 months old.
+
+## Trivy — usable, but not as-is
+
+Apache-2.0, no relicensing, excellent format support including SARIF. Two
+corrections to common belief:
+
+1. **Telemetry is on by default**, sending an install identifier (one-way hash
+ of a machine fingerprint), version, and OS to `check.trivy.dev`. No scan
+ results or file paths. Not a code leak — but an unsolicited outbound
+ connection from a privacy-positioned app is a positioning problem regardless
+ of payload. Disable with `--skip-version-check --disable-telemetry`.
+2. **`--offline-scan` does not mean offline.** Its actual usage string is *"do
+ not issue API requests to identify dependencies"*. True air-gap additionally
+ needs `--download-db-only` once to seed, then `--skip-db-update
+ --skip-java-db-update`.
+
+Useful detail: the misconfiguration checks bundle is **embedded in the binary at
+build time**, so that scanning survives with zero network.
+
+## SBOM formats
+
+Target **CycloneDX 1.7** (ECMA-424 2nd Edition, patch 1.7.1 2026-06-02) and
+**SPDX 3.0.1** (3.1 is still RC). Prefer **Syft** as the generator — bigger, Go
+binary, no Node floor. Reach for cdxgen only where Syft's ecosystem coverage
+falls short, and pin `@cyclonedx/cdxgen@12.x`: v13 moved npm scope and requires
+`node >= 24` / `pnpm >= 11`.
From bf5f1b75fc1c812a0ebe053ba2f38d64dd50872f Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 14:49:04 +0530
Subject: [PATCH 08/37] docs(knowledge): record sandboxed-execution and
static-analysis evaluation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Completes the tooling research the first agent died before delivering. Adds
tooling-sandboxing.md and wires it into the hub and index.
Recommendation: libkrun (Apache-2.0, Rust, Hypervisor.framework) embedded
in-process in src-tauri/, with apple/containerization as the upgrade path once
a Swift sidecar is acceptable — it is the only option with native VM state
save/restore, the actual warm-start mechanism.
Three findings that overturn common assumptions, all recorded:
- Firecracker and gVisor do not run on macOS at all (KVM / Linux platforms
only). Any plan built on them is dead on arrival.
- Docker Desktop is a licensing gate, not just an install burden — free only
under 250 employees AND under $10M revenue.
- CodeQL is legally disqualified for this product: its license forbids use on
non-open-source codebases and automated analysis without paid GHAS, and
CodeVetter exists to run against private repos.
Also notes that Semgrep's engine (LGPL-2.1) and its registry rules (a separate
restrictive license forbidding redistribution) are licensed differently, and
that observability needs no new dependency — the existing SQLite tables cover
per-run cost and latency.
Open questions are marked UNVERIFIED, notably the Virtualization.framework
entitlement question, which needs a direct check against Apple's docs.
Co-Authored-By: Claude Opus 5 (1M context)
---
docs/index.md | 4 +-
docs/knowledge/tooling-decisions.md | 4 +
docs/knowledge/tooling-sandboxing.md | 168 +++++++++++++++++++++++++++
3 files changed, 175 insertions(+), 1 deletion(-)
create mode 100644 docs/knowledge/tooling-sandboxing.md
diff --git a/docs/index.md b/docs/index.md
index 7e3f4d39..a4e75995 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -82,7 +82,7 @@ is only the presentation and search layer.
- [performance-lab-publication.md](./knowledge/performance-lab-publication.md) —
published optimization experiments, external PRs, and evidence boundaries.
- [tooling-decisions.md](./knowledge/tooling-decisions.md) — what CodeVetter
- embeds instead of building, what it refuses, and why. Hub for the four
+ embeds instead of building, what it refuses, and why. Hub for the five
evaluations below.
- [tooling-secrets-and-supply-chain.md](./knowledge/tooling-secrets-and-supply-chain.md)
— secret scanners and dependency/vulnerability scanners.
@@ -92,6 +92,8 @@ is only the presentation and search layer.
public agent benchmark corpora, graded on determinism and licensing.
- [tooling-documentation.md](./knowledge/tooling-documentation.md) — the
DeepWiki reject and what would fit instead.
+- [tooling-sandboxing.md](./knowledge/tooling-sandboxing.md) — isolation for
+ running untrusted agent code, determinism controls, SARIF analyzers.
- [codebase-context-tools-landscape.md](./knowledge/codebase-context-tools-landscape.md)
— April 2026 survey of codebase indexing and context tooling.
diff --git a/docs/knowledge/tooling-decisions.md b/docs/knowledge/tooling-decisions.md
index b717a940..61057b85 100644
--- a/docs/knowledge/tooling-decisions.md
+++ b/docs/knowledge/tooling-decisions.md
@@ -36,6 +36,7 @@ questions, not findings.
| `lcov` crate | MIT OR Apache-2.0 | In-process parser | [coverage](./tooling-coverage.md) |
| τ³-bench (tau2-bench) | MIT | Corpus under `benchmarks/` | [agent benchmarks](./tooling-agent-benchmarks.md) |
| Terminal-Bench 4.0 (Harbor) | Apache-2.0 | Corpus under `benchmarks/` | [agent benchmarks](./tooling-agent-benchmarks.md) |
+| `libkrun` | Apache-2.0 | In-process VMM in `src-tauri/` | [sandboxing](./tooling-sandboxing.md) |
`cargo-audit` is the highest-leverage item: the `rustsec` crate runs inside the
existing Rust backend with no new process boundary, no sidecar to codesign, and
@@ -54,6 +55,9 @@ absent from the changelog — pin `>= 0.22.0` and trust the source, not the docs
| `lcov` / `genhtml` Perl tooling | GPL-2.0 — do not bundle (the *format* is unencumbered) |
| Meta OpenApps | CC-BY-NC-4.0, commercial use prohibited |
| DeepWiki | Hosted; private repos need a paid Devin account — see [documentation tooling](./tooling-documentation.md) |
+| CodeQL | License forbids use on non-open-source codebases without paid GHAS — see [sandboxing](./tooling-sandboxing.md) |
+| Firecracker, gVisor | Linux-kernel only; no macOS host mode exists |
+| Docker Desktop | Proprietary GUI app, license-gated at 250 employees / $10M revenue |
| WorkArena, WebVoyager | Require live third-party websites or hosted SaaS |
| detect-secrets | Dormant since 2024; no SARIF |
| Nosey Parker | Archived 2026-04-24, superseded by Titus |
diff --git a/docs/knowledge/tooling-sandboxing.md b/docs/knowledge/tooling-sandboxing.md
new file mode 100644
index 00000000..597ce8f1
--- /dev/null
+++ b/docs/knowledge/tooling-sandboxing.md
@@ -0,0 +1,168 @@
+---
+title: Sandboxed execution and static analysis
+description: Isolation options for running untrusted agent code on Apple Silicon, determinism controls, SARIF-emitting analyzers, and the CodeQL licensing blocker.
+sidebar:
+ order: 15
+---
+
+# Sandboxed execution and static analysis
+
+Verified **2026-08-30**. See [tooling-decisions.md](./tooling-decisions.md) for
+the cross-category summary.
+
+Sandboxed execution is the mechanism CodeVetter's verdicts rest on: if the
+isolation is not reproducible, the evidence is not either. This page covers
+isolation on Apple Silicon, the determinism controls that make runs comparable,
+and static analyzers that emit SARIF.
+
+## Recommended: `libkrun`, with a VZ upgrade path
+
+**`libkrun`** (Apache-2.0, `containers/libkrun`, 2,643★) is a small VMM
+**library** written in Rust and built on Apple's `Hypervisor.framework`. It is
+not Docker, not a daemon, and not a subprocess — it links into the existing Rust
+backend via its C API, boots a minimal Linux microVM per verification run, and
+tears it down after. That matches the local-first, no-server constraint without
+requiring the user to install and license a GUI application.
+
+**`apple/containerization`** (Apache-2.0, Swift, 8.9k★) is the follow-on once a
+Swift sidecar is acceptable. It claims **sub-second** boot and is the only
+option here with **native VM state save/restore** — the actual warm-start
+mechanism. It requires **macOS 26** and Apple Silicon.
+
+**Colima + Lima** (MIT / Apache-2.0) is the pragmatic fallback for pre-macOS-26
+or Intel machines: a one-time Homebrew install rather than a bundled component.
+
+## Comparison
+
+| Option | License | Daemon? | Bundleable? | macOS ARM? |
+|---|---|---|---|---|
+| **libkrun** | Apache-2.0 | No — in-process C API | Yes, as a Rust dependency | Yes, explicit HVF backend |
+| **apple/containerization** | Apache-2.0 | No (the `container` CLI wrapping it does) | Via a Swift sidecar | Apple Silicon, **macOS 26 only** |
+| **Colima + Lima** | MIT / Apache-2.0 | CLI-managed VM, no GUI daemon | Prerequisite only | Yes (`vz` driver, default since Lima v1.0) |
+| **Podman** | Apache-2.0 | `podman machine` VM | Prerequisite only | Yes |
+| **Docker Desktop** | Engine Apache-2.0; **Desktop app proprietary** | Yes, GUI app + background VM | No | Yes, but license-gated |
+| **Firecracker** | Apache-2.0 | — | — | **No — KVM only** |
+| **gVisor** | Apache-2.0 | — | — | **No — Linux platforms only** |
+| **Wasmtime / WasmEdge** | Apache-2.0 | No | Yes, trivially | Yes |
+
+### Three findings that overturn common assumptions
+
+1. **Firecracker and gVisor do not run on macOS at all.** Firecracker's own
+ production-host docs state it relies on KVM, which is Linux-only. gVisor's
+ platform docs list KVM, Systrap and Ptrace — all Linux-specific. There is no
+ ARM-macOS host mode for either. Any plan built around them is dead on
+ arrival.
+2. **Docker Desktop is a licensing gate, not just an install burden.** The
+ engine (moby) is Apache-2.0, but the Desktop app is proprietary and metered:
+ free only under 250 employees **and** under $10M revenue. That becomes a
+ legal problem the moment the company crosses either threshold.
+3. **WASM cannot be the primary sandbox.** It is fast and trivially embeddable,
+ but only runs workloads compiled to WASI. CodeVetter's actual core workload
+ is TypeScript/Node web tasks with real browser and API behaviour. Keep WASM
+ for pure-computation graders only.
+
+## Determinism controls
+
+These are mostly **guest/application-layer** concerns, so they transfer across
+whichever isolation option is chosen:
+
+| Control | Mechanism |
+|---|---|
+| Frozen clock | `libfaketime` via `LD_PRELOAD` inside the guest |
+| Seeded RNG | Runtime-level shims, not a hypervisor feature |
+| Network isolation | `--network none` or equivalent on all container/VM options |
+| Filesystem rollback | Copy-on-write layers (recreate per run, not a memory snapshot) |
+| CPU/memory limits | cgroups-equivalent flags; WASM adds fuel/instruction limits |
+| **VM state save/restore** | **VZ/HVF family only** — see below |
+
+**Warm start is the strongest argument for the VZ/HVF family.** True memory-state
+snapshotting is confirmed only for `Virtualization.framework`-based options.
+Lima's `vz: implement auto save/restore` ([PR #2900](https://github.com/lima-vm/lima/pull/2900))
+measured **37s → 13s** boot-to-ready, and notes `saveOnStop` requires macOS 14+
+and is arm64-only. Docker's and containerd's copy-on-write layer model does not
+give you this.
+
+## Rust crates for driving isolation in-process
+
+- **`libkrun`** — the VMM itself, Rust, Apache-2.0, consumable via `bindgen`
+ FFI. The most direct no-shell-out path.
+- **`bollard`** — async Docker Engine API client, Apache-2.0, v0.21.1
+ (2026-08-16). Avoids shelling out to the `docker` CLI but still needs a
+ running daemon.
+- **`testcontainers`** (Rust) — MIT/Apache-2.0, v0.28.0. Higher-level, same
+ daemon prerequisite.
+- Direct Rust bindings to `Virtualization.framework` exist
+ (`virtualization-rs`, `apple-virtualization`, `virt-fwk`) but are all
+ low-star, thinly maintained side projects. **Do not depend on them.**
+
+## Static analysis with SARIF
+
+| Tool | License | Offline | Native SARIF | Verdict |
+|---|---|---|---|---|
+| **Biome** | Apache-2.0 | Yes | Present, fidelity **UNVERIFIED** | **Check first** — already the repo's linter |
+| **ast-grep** | MIT | Yes | Present, fidelity **UNVERIFIED** | Rust-native, good stack fit |
+| **Ruff** | MIT | Yes | Yes (`--output-format=sarif`) | Python scope only |
+| **Semgrep** | CLI is LGPL-2.1 | Yes | Yes | Engine fine; **rules are the problem** |
+| **Clippy** | Apache-2.0 | Yes | **No** | Needs `clippy-sarif` converter |
+| **ESLint** | MIT | Yes | No | Third-party formatter |
+| **CodeQL** | Custom | Yes | Yes | 🚫 **Legally disqualified** |
+
+### 🚫 CodeQL is a hard blocker for this product
+
+The CLI license prohibits use *"in connection with any codebase that is not an
+Open Source Codebase"* and prohibits automated analysis, CI or CD on such code,
+absent a paid GitHub Advanced Security agreement.
+
+CodeVetter's entire purpose is running against users' **private** repositories.
+CodeQL therefore cannot be a default engine unless every user separately holds a
+commercial GHAS license. This is a legal blocker, not a preference.
+
+### ⚠️ Semgrep — the engine and the rules have different licenses
+
+The CLI is LGPL-2.1 and runs offline. But the **registry rulesets** (`p/default`,
+`p/security-audit`, …) are under a separate *Semgrep Rules License v1.0*:
+*"You may use the rules only for your own internal business purposes. This
+license does not allow you to distribute the rules, or to make them available to
+others as a service."*
+
+Running Semgrep against a user's own code is internal use and fine.
+**Bundling a vendored copy of the registry rules into every install is the gray
+area** — that needs counsel before shipping, and is not cleared by the engine's
+LGPL alone.
+
+**Lowest-friction path: verify Biome's own SARIF fidelity first.** The repo
+already runs Biome for `pnpm lint`, so if its SARIF output is adequate, no
+second linter is needed at all.
+
+## Observability — do not add a dependency
+
+**Use the existing SQLite database.** Cost, latency and tokens per run are a
+handful of columns on the existing run/verification tables: `cost_usd`,
+`latency_ms`, `tokens_in`, `tokens_out`, `provider`, `model`.
+
+- **OpenTelemetry Rust** (Apache-2.0) is well-maintained but built for exporting
+ to a collector. Running it in-process purely to write rows you could write
+ directly is dependency accumulation.
+- **Langfuse** core is MIT and self-hostable, but it is a server product
+ (Postgres + web app) — a flat mismatch with "Tauri desktop binary, no server."
+
+Revisit OTel only if CodeVetter grows a genuine multi-process or remote-agent
+topology needing distributed tracing.
+
+## Open questions
+
+Flagged UNVERIFIED and worth closing before committing engineering time:
+
+- **The `Virtualization.framework` entitlement question.** Apple's docs are
+ JS-rendered and could not be fetched. Circumstantial evidence is strong —
+ Lima, Colima and `apple/container` all ship as notarized, non-App-Store
+ binaries using `vz` without incident, supporting the common understanding that
+ `com.apple.security.virtualization` is required only for **sandboxed Mac App
+ Store** apps, not Developer-ID-signed builds. Confirm directly against Apple
+ before relying on it.
+- **`libkrun` cold-boot time on Apple Silicon.** "Smallest possible boot time"
+ is a stated design goal; no published benchmark was found.
+- **Biome and ast-grep SARIF fidelity.** Both have SARIF code in-repo; neither
+ was validated against real output.
+- **Podman's default macOS backend** (applehv vs libkrun vs QEMU) and its exact
+ network/CPU/memory flags.
From e97430900c027eb337e786224876a239d52e8fb5 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 14:57:22 +0530
Subject: [PATCH 09/37] docs: correct the nav claim in agents.md to the 6
shipped tabs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
agents.md still advertised "Nav (7 tabs)" including Work (/agents) and Board
(/board). Both were retired on 2026-08-16 — docs/product/surfaces.md records
the retirement audit — and App.tsx now redirects them to "/". The sidebar ships
six tabs, and Performance (/performance) was missing from the list entirely.
This is the same block corrected earlier in this branch for repo structure; the
nav line three rows below it was missed on that pass.
Co-Authored-By: Claude Opus 5 (1M context)
---
agents.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents.md b/agents.md
index ec65f709..38610c44 100644
--- a/agents.md
+++ b/agents.md
@@ -97,7 +97,7 @@ node scripts/check-docs.mjs # Validate docs (links, frontmatter, structure)
- **`isTauriAvailable()` guard**: all IPC calls wrapped so React code also works in plain browser.
- **DB is `rusqlite`, not `@tauri-apps/plugin-sql`.** Do not re-add `plugin-sql` (removed in the 2026-07-11 desloppification sweep). See `docs/architecture/data-model.md`.
- **Single package manager: pnpm.** Do not reintroduce `package-lock.json` — dual-lockfile drift broke Cloudflare Pages in May 2026. See `docs/knowledge/failed-approaches.md`.
-- **Nav (7 tabs)**: Usage (`/`), Repo Unpack (`/unpack`), Work (`/agents`), Board (`/board`), Review (`/review`), Testing (`/trex`), Settings (`/settings`). Full surface map in `docs/product/surfaces.md`.
+- **Nav (6 tabs)**: Usage (`/`), Repo Unpack (`/unpack`), Review (`/review`), Testing (`/trex`), Performance (`/performance`), Settings (`/settings`). Work (`/agents`) and Board (`/board`) were retired 2026-08-16 and now redirect. Full surface map in `docs/product/surfaces.md`.
- **GH Actions**: `ci.yml` (lint + typecheck + unit + MCP + build), `auto-release.yml` → `release.yml` (Tauri binaries), `deploy-landing.yml` (Cloudflare Pages), `weekly.yml` (Mon cron canary), `docs.yml` (doc validation). See `docs/operations/`.
- Husky pre-commit runs lint-staged on `apps/desktop/src/**/*.{ts,tsx}`; pre-push runs lint + secret scan.
From 225480e5b6a018014bef1c190ed8ac3914a472e7 Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Sun, 30 Aug 2026 16:47:45 +0530
Subject: [PATCH 10/37] refactor: remove shared AI gateway preset
---
.../business_rule_archaeology/synthesis_command.rs | 1 -
.../business_rule_archaeology/synthesis_runtime.rs | 10 ++--------
apps/desktop/src/lib/review-service.test.ts | 2 +-
apps/desktop/src/lib/review-service.ts | 4 ----
4 files changed, 3 insertions(+), 14 deletions(-)
diff --git a/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_command.rs b/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_command.rs
index 1582eb97..db2c40c9 100644
--- a/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_command.rs
+++ b/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_command.rs
@@ -154,7 +154,6 @@ impl ArchaeologyProviderFactory for EnvironmentArchaeologyProviderFactory {
ArchaeologyProviderKind::Local => None,
ArchaeologyProviderKind::Hosted => {
let variable = match descriptor.provider_identity.as_str() {
- "free-ai" => "FREE_AI_API_KEY",
"openai" => "OPENAI_API_KEY",
"anthropic" => "ANTHROPIC_API_KEY",
"openrouter" => "OPENROUTER_API_KEY",
diff --git a/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_runtime.rs b/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_runtime.rs
index abd92838..e3c6a97a 100644
--- a/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_runtime.rs
+++ b/apps/desktop/src-tauri/src/commands/business_rule_archaeology/synthesis_runtime.rs
@@ -554,10 +554,6 @@ pub(crate) fn resolve_trusted_provider_configuration(
validate_provider_descriptor(&descriptor)?;
descriptor
}
- "free-ai" => canonical_hosted_descriptor(
- "free-ai",
- "https://ai-gateway.sassmaker.com/v1/chat/completions",
- ),
"openai" => canonical_hosted_descriptor("openai", "https://api.openai.com/v1/responses"),
"anthropic" => {
canonical_hosted_descriptor("anthropic", "https://api.anthropic.com/v1/messages")
@@ -572,8 +568,7 @@ pub(crate) fn resolve_trusted_provider_configuration(
return Err("Hosted archaeology synthesis cannot accept a local endpoint".into());
}
- let expected_cost = if user.provider_identity == "local" || user.provider_identity == "free-ai"
- {
+ let expected_cost = if user.provider_identity == "local" {
ArchaeologyCostClass::Free
} else {
ArchaeologyCostClass::Paid
@@ -2231,7 +2226,6 @@ fn validate_provider_descriptor(descriptor: &ArchaeologyProviderDescriptor) -> R
}
(ArchaeologyProviderKind::Hosted, ArchaeologyNetworkScope::Remote) => {
let allowed = match descriptor.provider_identity.as_str() {
- "free-ai" => "https://ai-gateway.sassmaker.com/v1/chat/completions",
"openai" => "https://api.openai.com/v1/responses",
"anthropic" => "https://api.anthropic.com/v1/messages",
"openrouter" => "https://openrouter.ai/api/v1/chat/completions",
@@ -2381,7 +2375,7 @@ fn validate_selection_identity(
return Err("Archaeology synthesis provider selection is invalid or unbounded".into());
}
let expected_cost = match selection.provider_identity.as_str() {
- "local" | "free-ai" => ArchaeologyCostClass::Free,
+ "local" => ArchaeologyCostClass::Free,
"openai" | "anthropic" | "openrouter" => ArchaeologyCostClass::Paid,
_ if descriptor.kind == ArchaeologyProviderKind::Local => ArchaeologyCostClass::Free,
_ => return Err("Archaeology synthesis provider cost class is unknown".into()),
diff --git a/apps/desktop/src/lib/review-service.test.ts b/apps/desktop/src/lib/review-service.test.ts
index d8d70467..19c1677d 100644
--- a/apps/desktop/src/lib/review-service.test.ts
+++ b/apps/desktop/src/lib/review-service.test.ts
@@ -125,7 +125,7 @@ describe('buildActiveStandardsContext', () => {
describe('PROVIDER_PRESETS', () => {
it('exposes a base url and model for each known provider', () => {
- for (const key of ['free-ai', 'anthropic', 'openai', 'openrouter']) {
+ for (const key of ['anthropic', 'openai', 'openrouter']) {
const preset = PROVIDER_PRESETS[key];
assert.ok(preset, `missing preset for ${key}`);
assert.match(preset.baseUrl, /^https:\/\//);
diff --git a/apps/desktop/src/lib/review-service.ts b/apps/desktop/src/lib/review-service.ts
index df4ed392..d5b3839a 100644
--- a/apps/desktop/src/lib/review-service.ts
+++ b/apps/desktop/src/lib/review-service.ts
@@ -125,10 +125,6 @@ export function getActiveStandardsPackId(): string | null {
}
export const PROVIDER_PRESETS: Record = {
- 'free-ai': {
- baseUrl: 'https://ai-gateway.sassmaker.com/v1',
- model: 'auto',
- },
anthropic: {
baseUrl: 'https://api.anthropic.com/v1',
model: 'claude-sonnet-4-20250514',
From 855202998b56c1658b9decda22298a1b63fb5caf Mon Sep 17 00:00:00 2001
From: Sarthak Agrawal
Date: Mon, 31 Aug 2026 03:17:09 +0530
Subject: [PATCH 11/37] chore: harden repository verification tooling
---
.github/dependabot.yml | 4 +
.github/workflows/auto-release.yml | 24 +-
.github/workflows/ci.yml | 27 +-
.github/workflows/deploy-landing.yml | 21 +-
.github/workflows/docs.yml | 11 +-
.github/workflows/osv-offline.yml | 84 +
.github/workflows/release.yml | 30 +-
.github/workflows/repository-security.yml | 169 ++
.github/workflows/weekly.yml | 64 +-
.gitleaksignore | 10 +
.husky/pre-commit | 8 +-
.husky/pre-push | 16 +-
apps/desktop/src-tauri/Cargo.lock | 5 +-
apps/desktop/src-tauri/Cargo.toml | 1 +
apps/desktop/src-tauri/deny.toml | 40 +
.../src-tauri/src/commands/agent_terminal.rs | 4 +-
.../desktop/src-tauri/src/commands/history.rs | 7 +-
apps/desktop/src/lib/review-service.test.ts | 56 +-
apps/desktop/src/lib/review-service.ts | 67 +-
apps/desktop/src/pages/Rubrics.tsx | 4 -
apps/desktop/src/pages/Settings.tsx | 124 -
docs-site/blume.config.ts | 4 +-
docs-site/package.json | 2 +-
docs-site/pnpm-lock.yaml | 2280 ++++++++++++++---
docs/architecture/data-model.md | 6 +-
docs/development/performance.md | 6 +-
docs/development/verification-receipts.md | 4 +-
docs/knowledge/performance-lab-publication.md | 2 +-
docs/knowledge/tooling-decisions.md | 63 +-
docs/knowledge/tooling-documentation.md | 25 +-
docs/operations/ci.md | 39 +-
.../actionlint-baseline-2026-08-31.md | 45 +
...ast-grep-sarif-qualification-2026-08-31.md | 40 +
.../cargo-deny-baseline-2026-08-31.md | 54 +
evidence/security/osv-baseline-2026-08-31.md | 55 +
.../trivy-config-qualification-2026-08-31.md | 45 +
.../stryker-accounting-oracle-2026-08-31.md | 30 +
knip.json | 3 +
package.json | 7 +
scripts/merge-landing-docs.mjs | 13 +-
.../qualify-codex-accounting-oracle.test.mjs | 199 +-
scripts/run-biome-sarif.mjs | 22 +
scripts/run-osv-offline.mjs | 191 ++
scripts/run-osv-offline.test.mjs | 70 +
scripts/stryker-accounting.config.mjs | 33 +
45 files changed, 3394 insertions(+), 620 deletions(-)
create mode 100644 .github/workflows/osv-offline.yml
create mode 100644 .github/workflows/repository-security.yml
create mode 100644 .gitleaksignore
create mode 100644 apps/desktop/src-tauri/deny.toml
create mode 100644 evidence/security/actionlint-baseline-2026-08-31.md
create mode 100644 evidence/security/ast-grep-sarif-qualification-2026-08-31.md
create mode 100644 evidence/security/cargo-deny-baseline-2026-08-31.md
create mode 100644 evidence/security/osv-baseline-2026-08-31.md
create mode 100644 evidence/security/trivy-config-qualification-2026-08-31.md
create mode 100644 evidence/verification/stryker-accounting-oracle-2026-08-31.md
create mode 100644 scripts/run-biome-sarif.mjs
create mode 100644 scripts/run-osv-offline.mjs
create mode 100644 scripts/run-osv-offline.test.mjs
create mode 100644 scripts/stryker-accounting.config.mjs
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index dc150637..9b8b11d2 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,6 +4,10 @@ updates:
directory: /
schedule:
interval: weekly
+ # Let ecosystem fixes settle before routine version PRs. Dependabot
+ # security updates are explicitly not delayed by this setting.
+ cooldown:
+ default-days: 7
groups:
ccusage-runtime:
patterns:
diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml
index 224e1f98..2163a2b1 100644
--- a/.github/workflows/auto-release.yml
+++ b/.github/workflows/auto-release.yml
@@ -18,9 +18,7 @@ on:
- "apps/desktop/src-tauri/tauri.conf.json"
workflow_dispatch:
-permissions:
- contents: write
- actions: write
+permissions: {}
concurrency:
group: auto-release-${{ github.ref }}
@@ -28,11 +26,16 @@ concurrency:
jobs:
publish:
+ name: Publish release and dispatch build
runs-on: ubuntu-latest
+ permissions:
+ contents: write # Create the versioned GitHub release.
+ actions: write # Dispatch the separate signed-build workflow.
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0
+ persist-credentials: false
- name: Read version from tauri.conf.json
id: ver
@@ -50,12 +53,13 @@ jobs:
id: check
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RELEASE_TAG: ${{ steps.ver.outputs.tag }}
run: |
set -euo pipefail
- if gh release view "${{ steps.ver.outputs.tag }}" \
+ if gh release view "$RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
- echo "Release ${{ steps.ver.outputs.tag }} already exists — skipping."
+ echo "Release $RELEASE_TAG already exists — skipping."
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
@@ -64,21 +68,23 @@ jobs:
if: steps.check.outputs.exists != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RELEASE_TAG: ${{ steps.ver.outputs.tag }}
run: |
set -euo pipefail
- gh release create "${{ steps.ver.outputs.tag }}" \
+ gh release create "$RELEASE_TAG" \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
- --title "CodeVetter ${{ steps.ver.outputs.tag }}" \
+ --title "CodeVetter $RELEASE_TAG" \
--generate-notes
- name: Dispatch release build workflow
if: steps.check.outputs.exists != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ RELEASE_TAG: ${{ steps.ver.outputs.tag }}
run: |
set -euo pipefail
gh workflow run release.yml \
--repo "$GITHUB_REPOSITORY" \
--ref main \
- -f tag="${{ steps.ver.outputs.tag }}"
+ -f tag="$RELEASE_TAG"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ea6d5de5..69bae25f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,19 +4,29 @@ on:
branches: [main]
pull_request:
workflow_dispatch:
+permissions: {}
+
+concurrency:
+ group: ci-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
lint-and-typecheck:
+ name: Lint, test, and build
runs-on: ubuntu-latest
+ permissions:
+ contents: read
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 2
- - uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v6
+ persist-credentials: false
+ - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
cache: 'pnpm'
- - uses: dtolnay/rust-toolchain@stable
+ - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
- name: Install Tauri Linux dependencies
run: |
sudo apt-get update
@@ -25,7 +35,7 @@ jobs:
libayatana-appindicator3-dev \
librsvg2-dev \
libxdo-dev
- - uses: Swatinem/rust-cache@v2
+ - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
with:
workspaces: apps/desktop/src-tauri
- name: Install Dependencies
@@ -35,7 +45,9 @@ jobs:
run: pnpm run lint
- name: Fetch code-health base
if: github.event_name != 'workflow_dispatch'
- run: git fetch --depth=1 origin ${{ github.event.pull_request.base.sha || github.event.before || 'HEAD^' }}
+ env:
+ CODE_HEALTH_BASE: ${{ github.event.pull_request.base.sha || github.event.before || 'HEAD^' }}
+ run: git fetch --depth=1 origin "$CODE_HEALTH_BASE"
- name: Code health
env:
CODE_HEALTH_BASE: ${{ github.event.pull_request.base.sha || github.event.before || 'HEAD^' }}
@@ -83,7 +95,8 @@ jobs:
run: |
pnpm run test:ccusage-sidecar
pnpm run prepare:ccusage-sidecar
- src-tauri/binaries/ccusage-$(rustc -vV | sed -n 's/^host: //p') --version
+ CCUSAGE_TARGET="$(rustc -vV | sed -n 's/^host: //p')"
+ "src-tauri/binaries/ccusage-$CCUSAGE_TARGET" --version
- name: Qualify CLI artifact
working-directory: apps/desktop
run: |
diff --git a/.github/workflows/deploy-landing.yml b/.github/workflows/deploy-landing.yml
index 629d8339..787eff44 100644
--- a/.github/workflows/deploy-landing.yml
+++ b/.github/workflows/deploy-landing.yml
@@ -7,9 +7,8 @@ name: Deploy Landing Page
# apps/landing-page-astro/.
on:
workflow_dispatch:
-permissions:
- contents: read
- deployments: write
+
+permissions: {}
concurrency:
group: deploy-landing-${{ github.ref }}
@@ -17,16 +16,22 @@ concurrency:
jobs:
deploy:
+ name: Build and deploy landing page
runs-on: ubuntu-latest
timeout-minutes: 20
+ permissions:
+ contents: read
+ deployments: write # Record the Cloudflare Pages deployment.
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
+ with:
+ persist-credentials: false
- - uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v6
+ - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "22"
- cache: pnpm
+ package-manager-cache: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
@@ -58,7 +63,7 @@ jobs:
- name: Deploy to Cloudflare Pages
if: steps.cloudflare.outputs.deploy_enabled == 'true'
- uses: cloudflare/wrangler-action@v3
+ uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 21d75599..a59fc946 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -5,12 +5,19 @@ on: [push, pull_request]
permissions:
contents: read
+concurrency:
+ group: docs-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
validate:
+ name: Validate documentation
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6
- - uses: actions/setup-node@v6
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
+ with:
+ persist-credentials: false
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "22"
- name: Validate docs (links, frontmatter, structure)
diff --git a/.github/workflows/osv-offline.yml b/.github/workflows/osv-offline.yml
new file mode 100644
index 00000000..26e263d0
--- /dev/null
+++ b/.github/workflows/osv-offline.yml
@@ -0,0 +1,84 @@
+name: OSV Offline Scan
+
+on:
+ workflow_dispatch:
+
+permissions: {}
+
+concurrency:
+ group: osv-offline-${{ github.ref }}
+ cancel-in-progress: false
+
+jobs:
+ refresh-databases:
+ name: Refresh OSV databases
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download ecosystem databases
+ env:
+ OSV_CACHE_ROOT: ${{ runner.temp }}/osv-db/osv-scalibr
+ run: |
+ mkdir -p "$OSV_CACHE_ROOT/npm" "$OSV_CACHE_ROOT/crates.io" "$OSV_CACHE_ROOT/Go"
+ curl --fail --silent --show-error --location \
+ https://osv-vulnerabilities.storage.googleapis.com/npm/all.zip \
+ --output "$OSV_CACHE_ROOT/npm/all.zip"
+ curl --fail --silent --show-error --location \
+ https://osv-vulnerabilities.storage.googleapis.com/crates.io/all.zip \
+ --output "$OSV_CACHE_ROOT/crates.io/all.zip"
+ curl --fail --silent --show-error --location \
+ https://osv-vulnerabilities.storage.googleapis.com/Go/all.zip \
+ --output "$OSV_CACHE_ROOT/Go/all.zip"
+ cd "$OSV_CACHE_ROOT"
+ sha256sum npm/all.zip crates.io/all.zip Go/all.zip > SHA256SUMS
+ - name: Upload database snapshot
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: osv-databases-${{ github.run_id }}
+ path: ${{ runner.temp }}/osv-db
+ retention-days: 7
+
+ offline-scan:
+ name: Scan with network-disabled mode
+ needs: refresh-databases
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Download database snapshot
+ uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
+ with:
+ name: osv-databases-${{ github.run_id }}
+ path: ${{ runner.temp }}/osv-db
+ - name: Install checksum-pinned OSV-Scanner
+ env:
+ OSV_BINARY: osv-scanner_linux_amd64
+ OSV_SHA256: f9f25499a2c8cc367b3af45df2ea7eeca7fbccceab9c35079968f4b3652194be
+ OSV_URL: https://github.com/google/osv-scanner/releases/download/v2.5.1/osv-scanner_linux_amd64
+ run: |
+ curl --fail --silent --show-error --location "$OSV_URL" --output "$RUNNER_TEMP/$OSV_BINARY"
+ echo "$OSV_SHA256 $RUNNER_TEMP/$OSV_BINARY" | sha256sum --check --strict
+ chmod 0755 "$RUNNER_TEMP/$OSV_BINARY"
+ mkdir -p "$RUNNER_TEMP/osv-bin"
+ mv "$RUNNER_TEMP/$OSV_BINARY" "$RUNNER_TEMP/osv-bin/osv-scanner"
+ echo "$RUNNER_TEMP/osv-bin" >> "$GITHUB_PATH"
+ - name: Run offline scan
+ id: scan
+ continue-on-error: true
+ env:
+ XDG_CACHE_HOME: ${{ runner.temp }}/osv-db
+ run: node scripts/run-osv-offline.mjs
+ - name: Upload scan evidence
+ if: always()
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+ with:
+ name: osv-offline-evidence-${{ github.run_id }}
+ path: artifacts/tooling/osv
+ if-no-files-found: error
+ retention-days: 30
+ - name: Enforce scan result
+ if: always() && steps.scan.outcome == 'failure'
+ run: exit 1
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 235c30d4..fd596879 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,47 +10,51 @@ on:
required: true
type: string
-permissions:
- contents: write
+permissions: {}
+
+concurrency:
+ group: release-${{ github.event.release.tag_name || inputs.tag || github.ref }}
+ cancel-in-progress: false
jobs:
build:
+ name: Build, sign, and upload desktop artifacts
strategy:
matrix:
platform: [macos-latest]
runs-on: ${{ matrix.platform }}
+ permissions:
+ contents: write # Upload signed artifacts and updater metadata.
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
# On workflow_dispatch we want the commit the tag points at, not
# the head of main — checkout the tag explicitly.
ref: ${{ github.event.release.tag_name || inputs.tag }}
+ persist-credentials: false
- name: Setup pnpm
- uses: pnpm/action-setup@v6
+ uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
# Don't specify version here — it reads "packageManager" from
# package.json (pnpm@10.33.2). Specifying both causes
# "Multiple versions of pnpm specified" error.
- name: Setup Node
- uses: actions/setup-node@v6
+ uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 22
- cache: pnpm
+ package-manager-cache: false
- name: Setup Rust
- uses: dtolnay/rust-toolchain@stable
+ uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
targets: aarch64-apple-darwin
- name: Setup Bun
- uses: oven-sh/setup-bun@v2
-
- - name: Cache Rust
- uses: Swatinem/rust-cache@v2
+ uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
- workspaces: apps/desktop/src-tauri
+ no-cache: true
- name: Install dependencies
run: pnpm install --ignore-scripts
@@ -102,7 +106,7 @@ jobs:
- name: Build Tauri app
id: tauri
- uses: tauri-apps/tauri-action@v0
+ uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_ENV_TARGET_TRIPLE: aarch64-apple-darwin
diff --git a/.github/workflows/repository-security.yml b/.github/workflows/repository-security.yml
new file mode 100644
index 00000000..9386106f
--- /dev/null
+++ b/.github/workflows/repository-security.yml
@@ -0,0 +1,169 @@
+name: Repository Security
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ workflow_dispatch:
+
+permissions: {}
+
+concurrency:
+ group: repository-security-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ actionlint:
+ name: GitHub Actions semantics
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Install pinned workflow analyzers
+ env:
+ ACTIONLINT_ARCHIVE: actionlint_1.7.12_linux_amd64.tar.gz
+ ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
+ ACTIONLINT_URL: https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz
+ SHELLCHECK_ARCHIVE: shellcheck-v0.11.0.linux.x86_64.tar.gz
+ SHELLCHECK_SHA256: b7af85e41cc99489dcc21d66c6d5f3685138f06d34651e6d34b42ec6d54fe6f6
+ SHELLCHECK_URL: https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.gz
+ run: |
+ mkdir -p "$RUNNER_TEMP/workflow-tools"
+ curl --fail --silent --show-error --location "$ACTIONLINT_URL" --output "$RUNNER_TEMP/$ACTIONLINT_ARCHIVE"
+ echo "$ACTIONLINT_SHA256 $RUNNER_TEMP/$ACTIONLINT_ARCHIVE" | sha256sum --check --strict
+ tar -xzf "$RUNNER_TEMP/$ACTIONLINT_ARCHIVE" -C "$RUNNER_TEMP/workflow-tools" actionlint
+ curl --fail --silent --show-error --location "$SHELLCHECK_URL" --output "$RUNNER_TEMP/$SHELLCHECK_ARCHIVE"
+ echo "$SHELLCHECK_SHA256 $RUNNER_TEMP/$SHELLCHECK_ARCHIVE" | sha256sum --check --strict
+ tar -xzf "$RUNNER_TEMP/$SHELLCHECK_ARCHIVE" -C "$RUNNER_TEMP"
+ mv "$RUNNER_TEMP/shellcheck-v0.11.0/shellcheck" "$RUNNER_TEMP/workflow-tools/shellcheck"
+ echo "$RUNNER_TEMP/workflow-tools" >> "$GITHUB_PATH"
+ - name: Validate workflow syntax and shell fragments
+ run: |
+ actionlint -version
+ shellcheck --version
+ actionlint -color
+
+ biome-sarif:
+ name: Biome SARIF
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ security-events: write # Publish the generated Biome report.
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Set up pnpm
+ uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
+ - name: Set up Node.js
+ uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
+ with:
+ node-version: '22'
+ cache: pnpm
+ - name: Install dependencies
+ run: pnpm install --frozen-lockfile
+ - name: Generate Biome SARIF
+ env:
+ BIOME_SARIF_PATH: artifacts/tooling/biome.sarif
+ run: pnpm run quality:sarif
+ - name: Upload Biome SARIF
+ if: always()
+ uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
+ with:
+ sarif_file: artifacts/tooling/biome.sarif
+ category: biome
+
+ cargo-deny:
+ name: Rust dependency policy
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ security-events: write # Publish license and source-policy findings.
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Install pinned cargo-deny binary
+ env:
+ CARGO_DENY_ARCHIVE: cargo-deny-0.20.2-x86_64-unknown-linux-musl.tar.gz
+ CARGO_DENY_SHA256: 9f12ed4c49936e09b48bf862b595cde2fe64fcbd9d74dfacac6131ca824c8d5f
+ CARGO_DENY_URL: https://github.com/EmbarkStudios/cargo-deny/releases/download/0.20.2/cargo-deny-0.20.2-x86_64-unknown-linux-musl.tar.gz
+ run: |
+ curl --fail --silent --show-error --location "$CARGO_DENY_URL" --output "$RUNNER_TEMP/$CARGO_DENY_ARCHIVE"
+ echo "$CARGO_DENY_SHA256 $RUNNER_TEMP/$CARGO_DENY_ARCHIVE" | sha256sum --check --strict
+ tar -xzf "$RUNNER_TEMP/$CARGO_DENY_ARCHIVE" -C "$RUNNER_TEMP"
+ echo "$RUNNER_TEMP/cargo-deny-0.20.2-x86_64-unknown-linux-musl" >> "$GITHUB_PATH"
+ - name: Check licenses, sources, and wildcard requirements
+ id: policy
+ continue-on-error: true
+ run: |
+ mkdir -p artifacts/tooling
+ cargo-deny --format sarif --manifest-path apps/desktop/src-tauri/Cargo.toml --config apps/desktop/src-tauri/deny.toml --frozen check licenses sources > artifacts/tooling/cargo-deny.sarif
+ cargo-deny --manifest-path apps/desktop/src-tauri/Cargo.toml --config apps/desktop/src-tauri/deny.toml --frozen check --hide-inclusion-graph bans
+ - name: Upload cargo-deny SARIF
+ if: always()
+ uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
+ with:
+ sarif_file: artifacts/tooling/cargo-deny.sarif
+ category: cargo-deny
+ - name: Enforce cargo-deny result
+ if: always() && steps.policy.outcome == 'failure'
+ run: exit 1
+
+ gitleaks:
+ name: Gitleaks
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ security-events: write # Publish the redacted Gitleaks report.
+ steps:
+ - name: Checkout complete history
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+ persist-credentials: false
+ - name: Install pinned Gitleaks binary
+ env:
+ GITLEAKS_ARCHIVE: gitleaks_8.30.1_linux_x64.tar.gz
+ GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
+ GITLEAKS_URL: https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz
+ run: |
+ curl --fail --silent --show-error --location "$GITLEAKS_URL" --output "$RUNNER_TEMP/$GITLEAKS_ARCHIVE"
+ echo "$GITLEAKS_SHA256 $RUNNER_TEMP/$GITLEAKS_ARCHIVE" | sha256sum --check --strict
+ mkdir -p "$RUNNER_TEMP/gitleaks-bin"
+ tar -xzf "$RUNNER_TEMP/$GITLEAKS_ARCHIVE" -C "$RUNNER_TEMP/gitleaks-bin" gitleaks
+ echo "$RUNNER_TEMP/gitleaks-bin" >> "$GITHUB_PATH"
+ - name: Scan repository history
+ id: scan
+ continue-on-error: true
+ run: >-
+ gitleaks git --no-banner --redact=100 --report-format sarif
+ --report-path "$RUNNER_TEMP/gitleaks.sarif" .
+ - name: Upload Gitleaks SARIF
+ if: always()
+ uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
+ with:
+ sarif_file: ${{ runner.temp }}/gitleaks.sarif
+ category: gitleaks
+ - name: Enforce Gitleaks result
+ if: always() && steps.scan.outcome == 'failure'
+ run: exit 1
+
+ zizmor:
+ name: zizmor
+ runs-on: ubuntu-latest
+ permissions:
+ security-events: write # zizmor-action uploads its SARIF report.
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Audit GitHub Actions
+ uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2
diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml
index c0f7cecb..cb36ed8e 100644
--- a/.github/workflows/weekly.yml
+++ b/.github/workflows/weekly.yml
@@ -4,24 +4,35 @@ on:
- cron: '0 9 * * 1'
workflow_dispatch:
+permissions: {}
+
+concurrency:
+ group: weekly-quality-${{ github.ref }}
+ cancel-in-progress: true
+
jobs:
quality:
+ name: Run weekly quality canary
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
+ with:
+ persist-credentials: false
- name: Record source revision
id: rev
run: |
- echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- echo "short=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- echo "ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
+ {
+ echo "sha=$(git rev-parse HEAD)"
+ echo "short=$(git rev-parse --short HEAD)"
+ echo "ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
+ } >> "$GITHUB_OUTPUT"
- - uses: actions/setup-node@v6
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'
@@ -72,24 +83,29 @@ jobs:
- name: Emit canary evidence
if: always()
+ env:
+ JOB_STATUS: ${{ job.status }}
+ SOURCE_REVISION: ${{ steps.rev.outputs.sha }}
+ SOURCE_REVISION_SHORT: ${{ steps.rev.outputs.short }}
+ STARTED_AT: ${{ steps.rev.outputs.ts }}
run: |
set -euo pipefail
mkdir -p canary-out
# The conclusion is only known after the quality step; read it
# from the job status env that GitHub sets for `if: always()` steps.
# We treat any non-success quality step as a failure.
- CONCLUSION="${{ job.status }}"
+ CONCLUSION="$JOB_STATUS"
# `job.status` is the *job* status at the point this step starts;
# because this step runs with `if: always()`, the prior step's
# failure has already propagated to the job status.
cat > canary-out/canary-evidence.json <> "$GITHUB_STEP_SUMMARY"
- echo "" >> "$GITHUB_STEP_SUMMARY"
- echo "| Field | Value |" >> "$GITHUB_STEP_SUMMARY"
- echo "|---|---|" >> "$GITHUB_STEP_SUMMARY"
- echo "| Revision | \`${{ steps.rev.outputs.short }}\` |" >> "$GITHUB_STEP_SUMMARY"
- echo "| Started | ${{ steps.rev.outputs.ts }} |" >> "$GITHUB_STEP_SUMMARY"
- echo "| Conclusion | ${CONCLUSION} |" >> "$GITHUB_STEP_SUMMARY"
- echo "| Timeout | 20 minutes |" >> "$GITHUB_STEP_SUMMARY"
- echo "| Run | [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) |" >> "$GITHUB_STEP_SUMMARY"
- echo "" >> "$GITHUB_STEP_SUMMARY"
- echo "If this run failed, the previous failed run's conclusion + URL are the unresolved failure evidence. Foundry reads this artifact to compute freshness against the 8-day window." >> "$GITHUB_STEP_SUMMARY"
+ {
+ echo "### Weekly canary evidence"
+ echo ""
+ echo "| Field | Value |"
+ echo "|---|---|"
+ echo "| Revision | \`$SOURCE_REVISION_SHORT\` |"
+ echo "| Started | $STARTED_AT |"
+ echo "| Conclusion | ${CONCLUSION} |"
+ echo "| Timeout | 20 minutes |"
+ echo "| Run | [$GITHUB_RUN_ID]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) |"
+ echo ""
+ echo "If this run failed, the previous failed run's conclusion + URL are the unresolved failure evidence. Foundry reads this artifact to compute freshness against the 8-day window."
+ } >> "$GITHUB_STEP_SUMMARY"
cat canary-out/canary-evidence.json
- name: Upload canary evidence
if: always()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: canary-evidence
path: canary-out/canary-evidence.json
diff --git a/.gitleaksignore b/.gitleaksignore
new file mode 100644
index 00000000..2bd3815f
--- /dev/null
+++ b/.gitleaksignore
@@ -0,0 +1,10 @@
+# Exact historical false positives retained for auditability. Each entry is
+# scoped to one commit, path, rule, and line; future findings in the same files
+# remain visible.
+# PostHog browser ingestion key, public by design (see tooling docs).
+930c8952a3c80edd61c06c2f49106e616c8dde9a:apps/desktop/src/lib/analytics.ts:generic-api-key:25
+39f414d063cac9ebe9258c69a81c05348f3e4b89:apps/desktop/src/lib/analytics.ts:generic-api-key:25
+# Historical Foundry public project identifier.
+81df29eebf1d724d2939cbfd8123b86e9848a940:foundry.json:generic-api-key:4
+# Historical database migration fixture value.
+ac5d18ee9b33811accec2df5d7bc33b69f9bb6c3:apps/desktop/src-tauri/src/db/schema.rs:generic-api-key:23
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 2312dc58..f46c0171 100644
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1 +1,7 @@
-npx lint-staged
+pnpm exec lint-staged
+
+if command -v gitleaks >/dev/null 2>&1; then
+ pnpm run quality:secrets:staged
+else
+ echo "gitleaks is not installed; repository security CI will enforce the history scan" >&2
+fi
diff --git a/.husky/pre-push b/.husky/pre-push
index b0c49490..f7bb930f 100755
--- a/.husky/pre-push
+++ b/.husky/pre-push
@@ -1,14 +1,18 @@
-# Abort push if lint fails or a known secret pattern leaks into tracked files.
-#
-# NOTE: foundry.json is excluded below because it already contains a committed
-# projectKey (pk_...) that predates the pk_ pattern. Remove that exclusion once
-# the key is rotated and moved out of the tracked file.
+# Abort push if lint fails or Gitleaks finds a secret in repository history.
+# Keep the narrow regex fallback for contributors who do not have Gitleaks.
set -e
if [ -f package.json ] && grep -q '"lint"' package.json; then
- npm run lint || { echo "lint failed — fix before pushing" >&2; exit 1; }
+ pnpm run lint || { echo "lint failed — fix before pushing" >&2; exit 1; }
fi
+if command -v gitleaks >/dev/null 2>&1; then
+ pnpm run quality:secrets
+ exit 0
+fi
+
+echo "gitleaks is not installed; using the limited tracked-file fallback" >&2
+
SECRETS=$(git ls-files -z 2>/dev/null \
| xargs -0 grep -lE \
'sk-(proj-|ant-)?[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|gho_[A-Za-z0-9]{36}|AIzaSy[A-Za-z0-9_-]{33}|xoxb-[A-Za-z0-9-]+|pk_[A-Za-z0-9]{32,}|-----BEGIN (RSA |EC )?PRIVATE KEY-----' 2>/dev/null \
diff --git a/apps/desktop/src-tauri/Cargo.lock b/apps/desktop/src-tauri/Cargo.lock
index a605276f..dbb15484 100644
--- a/apps/desktop/src-tauri/Cargo.lock
+++ b/apps/desktop/src-tauri/Cargo.lock
@@ -1278,11 +1278,10 @@ dependencies = [
[[package]]
name = "event-listener"
-version = "5.4.1"
+version = "5.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
+checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
dependencies = [
- "concurrent-queue",
"parking",
"pin-project-lite",
]
diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml
index 22ba15c3..07699fea 100644
--- a/apps/desktop/src-tauri/Cargo.toml
+++ b/apps/desktop/src-tauri/Cargo.toml
@@ -2,6 +2,7 @@
name = "codevetter-desktop"
version = "0.1.0"
edition = "2021"
+publish = false
description = "CodeVetter Desktop — code review + agent management"
default-run = "codevetter-desktop"
diff --git a/apps/desktop/src-tauri/deny.toml b/apps/desktop/src-tauri/deny.toml
new file mode 100644
index 00000000..b8813bbe
--- /dev/null
+++ b/apps/desktop/src-tauri/deny.toml
@@ -0,0 +1,40 @@
+[graph]
+targets = ["aarch64-apple-darwin"]
+all-features = false
+no-default-features = false
+
+[licenses]
+allow = [
+ "0BSD",
+ "Apache-2.0",
+ "Apache-2.0 WITH LLVM-exception",
+ "BSD-2-Clause",
+ "BSD-3-Clause",
+ "BSL-1.0",
+ "CC0-1.0",
+ "CDLA-Permissive-2.0",
+ "ISC",
+ "MIT",
+ "MIT-0",
+ "MPL-2.0",
+ "Unicode-3.0",
+ "Unlicense",
+ "Zlib",
+]
+confidence-threshold = 0.8
+
+[licenses.private]
+ignore = true
+
+[bans]
+multiple-versions = "warn"
+wildcards = "deny"
+highlight = "simplest-path"
+workspace-default-features = "allow"
+external-default-features = "allow"
+
+[sources]
+unknown-registry = "deny"
+unknown-git = "deny"
+allow-registry = ["https://github.com/rust-lang/crates.io-index"]
+allow-git = []
diff --git a/apps/desktop/src-tauri/src/commands/agent_terminal.rs b/apps/desktop/src-tauri/src/commands/agent_terminal.rs
index 54c91aba..9cbe0a40 100644
--- a/apps/desktop/src-tauri/src/commands/agent_terminal.rs
+++ b/apps/desktop/src-tauri/src/commands/agent_terminal.rs
@@ -570,9 +570,7 @@ fn start_agent_terminal_impl(
) {
Ok(result) => return Ok(result),
Err(error) => {
- eprintln!(
- "Codex app-server unavailable for {session_id}; falling back to PTY: {error}"
- );
+ eprintln!("Codex app-server unavailable; falling back to PTY: {error}");
}
}
}
diff --git a/apps/desktop/src-tauri/src/commands/history.rs b/apps/desktop/src-tauri/src/commands/history.rs
index 004cf20b..24c30f15 100644
--- a/apps/desktop/src-tauri/src/commands/history.rs
+++ b/apps/desktop/src-tauri/src/commands/history.rs
@@ -1565,12 +1565,11 @@ fn upsert_adapter_summary_session(
let archive_messages = summary.archive_messages.clone();
let parse_warnings = summary.parse_warnings.clone();
- for warning in &summary.parse_warnings {
+ if !summary.parse_warnings.is_empty() {
log::warn!(
- "{} session adapter warning for {}: {}",
+ "{} session adapter reported {} parse warning(s)",
summary.adapter_id,
- source_ref,
- warning
+ summary.parse_warnings.len()
);
}
diff --git a/apps/desktop/src/lib/review-service.test.ts b/apps/desktop/src/lib/review-service.test.ts
index 19c1677d..647c3888 100644
--- a/apps/desktop/src/lib/review-service.test.ts
+++ b/apps/desktop/src/lib/review-service.test.ts
@@ -7,7 +7,6 @@ import {
getActiveStandardsPack,
getStandardsPacks,
loadReviewConfig,
- PROVIDER_PRESETS,
type ReviewConfig,
saveReviewConfig,
} from './review-service';
@@ -29,10 +28,8 @@ class MemoryStorage {
}
const validConfig: ReviewConfig = {
- gatewayBaseUrl: 'https://gateway.example/v1',
- gatewayApiKey: 'sk-test',
- gatewayModel: 'auto',
- reviewTone: 'direct',
+ activeStandardsPack: 'product-safety',
+ customRules: ['Check authorization'],
};
beforeEach(() => {
@@ -45,20 +42,48 @@ describe('loadReviewConfig', () => {
assert.equal(loadReviewConfig(), null);
});
- it('returns null when required credentials are missing', () => {
- saveReviewConfig({ ...validConfig, gatewayApiKey: '' });
- assert.equal(loadReviewConfig(), null);
- });
-
it('returns null on malformed JSON', () => {
localStorage.setItem('codevetter_review_config', '{not json');
assert.equal(loadReviewConfig(), null);
+ assert.equal(localStorage.getItem('codevetter_review_config'), null);
});
it('round-trips a valid config', () => {
saveReviewConfig(validConfig);
assert.deepEqual(loadReviewConfig(), validConfig);
});
+
+ it('migrates legacy provider config without retaining the credential', () => {
+ localStorage.setItem(
+ 'codevetter_review_config',
+ JSON.stringify({
+ ...validConfig,
+ gatewayApiKey: 'sk-legacy-secret',
+ gatewayBaseUrl: 'https://api.example.test/v1',
+ gatewayModel: 'legacy-model',
+ reviewTone: 'direct',
+ })
+ );
+
+ assert.deepEqual(loadReviewConfig(), validConfig);
+ const stored = localStorage.getItem('codevetter_review_config') ?? '';
+ assert.equal(stored.includes('sk-legacy-secret'), false);
+ assert.equal(stored.includes('gatewayApiKey'), false);
+ assert.equal(stored.includes('gatewayBaseUrl'), false);
+ assert.equal(stored.includes('gatewayModel'), false);
+ });
+
+ it('persists only allowlisted review-standard fields', () => {
+ saveReviewConfig({
+ ...validConfig,
+ gatewayApiKey: 'sk-should-not-persist',
+ } as ReviewConfig & { gatewayApiKey: string });
+
+ const stored = localStorage.getItem('codevetter_review_config');
+ assert.ok(stored);
+ assert.deepEqual(JSON.parse(stored), validConfig);
+ assert.equal(stored.includes('sk-should-not-persist'), false);
+ });
});
describe('getStandardsPacks', () => {
@@ -122,14 +147,3 @@ describe('buildActiveStandardsContext', () => {
assert.equal((context.match(/Custom rule:/g) ?? []).length, 1);
});
});
-
-describe('PROVIDER_PRESETS', () => {
- it('exposes a base url and model for each known provider', () => {
- for (const key of ['anthropic', 'openai', 'openrouter']) {
- const preset = PROVIDER_PRESETS[key];
- assert.ok(preset, `missing preset for ${key}`);
- assert.match(preset.baseUrl, /^https:\/\//);
- assert.ok(preset.model.length > 0);
- }
- });
-});
diff --git a/apps/desktop/src/lib/review-service.ts b/apps/desktop/src/lib/review-service.ts
index d5b3839a..1905812c 100644
--- a/apps/desktop/src/lib/review-service.ts
+++ b/apps/desktop/src/lib/review-service.ts
@@ -1,13 +1,6 @@
-/**
- * Review config persistence and provider presets.
- * Used by the Settings page to configure AI provider credentials.
- */
+/** Review-standards persistence. Provider credentials are never stored here. */
export interface ReviewConfig {
- gatewayBaseUrl: string;
- gatewayApiKey: string;
- gatewayModel: string;
- reviewTone: string;
customRules?: string[];
activeStandardsPack?: string;
standardsPacks?: StandardsPack[];
@@ -55,20 +48,57 @@ export const DEFAULT_STANDARDS_PACKS: StandardsPack[] = [
},
];
+function isStandardsPack(value: unknown): value is StandardsPack {
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
+ const candidate = value as Partial;
+ return (
+ typeof candidate.id === 'string' &&
+ typeof candidate.name === 'string' &&
+ typeof candidate.focus === 'string' &&
+ Array.isArray(candidate.checks) &&
+ candidate.checks.every((check) => typeof check === 'string')
+ );
+}
+
+function sanitizeReviewConfig(value: unknown): ReviewConfig | null {
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
+ const candidate = value as Partial;
+ const config: ReviewConfig = {};
+
+ if (Array.isArray(candidate.customRules)) {
+ config.customRules = candidate.customRules.filter(
+ (rule): rule is string => typeof rule === 'string'
+ );
+ }
+ if (typeof candidate.activeStandardsPack === 'string') {
+ config.activeStandardsPack = candidate.activeStandardsPack;
+ }
+ if (Array.isArray(candidate.standardsPacks)) {
+ config.standardsPacks = candidate.standardsPacks.filter(isStandardsPack);
+ }
+ return config;
+}
+
export function loadReviewConfig(): ReviewConfig | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
- const config = JSON.parse(raw) as ReviewConfig;
- if (!config.gatewayApiKey || !config.gatewayBaseUrl) return null;
+ const config = sanitizeReviewConfig(JSON.parse(raw));
+ if (!config) {
+ localStorage.removeItem(STORAGE_KEY);
+ return null;
+ }
+ const sanitized = JSON.stringify(config);
+ if (sanitized !== raw) localStorage.setItem(STORAGE_KEY, sanitized);
return config;
} catch {
+ localStorage.removeItem(STORAGE_KEY);
return null;
}
}
export function saveReviewConfig(config: ReviewConfig): void {
- localStorage.setItem(STORAGE_KEY, JSON.stringify(config));
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(sanitizeReviewConfig(config) ?? {}));
}
export function getStandardsPacks(config: ReviewConfig | null): StandardsPack[] {
@@ -123,18 +153,3 @@ export function getActiveStandardsPackId(): string | null {
if (!config?.activeStandardsPack) return null;
return getActiveStandardsPack(config).id;
}
-
-export const PROVIDER_PRESETS: Record = {
- anthropic: {
- baseUrl: 'https://api.anthropic.com/v1',
- model: 'claude-sonnet-4-20250514',
- },
- openai: {
- baseUrl: 'https://api.openai.com/v1',
- model: 'gpt-4o',
- },
- openrouter: {
- baseUrl: 'https://openrouter.ai/api/v1',
- model: 'anthropic/claude-sonnet-4-20250514',
- },
-};
diff --git a/apps/desktop/src/pages/Rubrics.tsx b/apps/desktop/src/pages/Rubrics.tsx
index 41eaada9..3e2bdc72 100644
--- a/apps/desktop/src/pages/Rubrics.tsx
+++ b/apps/desktop/src/pages/Rubrics.tsx
@@ -27,10 +27,6 @@ import { getStandardsPackUsage, isTauriAvailable } from '@/lib/tauri-ipc';
function fallbackConfig(): ReviewConfig {
return {
- gatewayBaseUrl: '',
- gatewayApiKey: '',
- gatewayModel: 'auto',
- reviewTone: 'direct',
activeStandardsPack: DEFAULT_STANDARDS_PACKS[0].id,
standardsPacks: [],
};
diff --git a/apps/desktop/src/pages/Settings.tsx b/apps/desktop/src/pages/Settings.tsx
index 0d0eca8d..8557710d 100644
--- a/apps/desktop/src/pages/Settings.tsx
+++ b/apps/desktop/src/pages/Settings.tsx
@@ -6,12 +6,6 @@ import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Separator } from '@/components/ui/separator';
-import {
- loadReviewConfig,
- PROVIDER_PRESETS,
- type ReviewConfig,
- saveReviewConfig,
-} from '@/lib/review-service';
import type {
GitHubAuthStatus,
LinearUser,
@@ -590,48 +584,6 @@ export default function Settings() {
const [claudeCodePath, setClaudeCodePath] = usePref('claude_cli_path', '');
const [codexPath, setCodexPath] = usePref('codex_cli_path', '');
- // AI Provider
- const [aiProvider, setAiProvider] = useState('anthropic');
- const [aiBaseUrl, setAiBaseUrl] = useState('');
- const [aiApiKey, setAiApiKey] = useState('');
- const [aiModel, setAiModel] = useState('');
- const [aiConfigSaved, setAiConfigSaved] = useState(false);
-
- useEffect(() => {
- const existing = loadReviewConfig();
- if (existing) {
- setAiBaseUrl(existing.gatewayBaseUrl);
- setAiApiKey(existing.gatewayApiKey);
- setAiModel(existing.gatewayModel);
- // Detect provider from URL
- if (existing.gatewayBaseUrl.includes('anthropic')) setAiProvider('anthropic');
- else if (existing.gatewayBaseUrl.includes('openai.com')) setAiProvider('openai');
- else if (existing.gatewayBaseUrl.includes('openrouter')) setAiProvider('openrouter');
- else setAiProvider('custom');
- }
- }, []);
-
- function handleProviderChange(provider: string) {
- setAiProvider(provider);
- setAiConfigSaved(false);
- if (provider !== 'custom' && PROVIDER_PRESETS[provider]) {
- setAiBaseUrl(PROVIDER_PRESETS[provider].baseUrl);
- setAiModel(PROVIDER_PRESETS[provider].model);
- }
- }
-
- function handleSaveAiConfig() {
- const config: ReviewConfig = {
- gatewayBaseUrl: aiBaseUrl,
- gatewayApiKey: aiApiKey,
- gatewayModel: aiModel,
- reviewTone: defaultTone,
- };
- saveReviewConfig(config);
- setAiConfigSaved(true);
- setTimeout(() => setAiConfigSaved(false), 2000);
- }
-
// Notifications
const [notifyReviewDone, toggleNotifyReviewDone] = useBoolPref('notify_review_done', true);
const [notifyAgentError, toggleNotifyAgentError] = useBoolPref('notify_agent_error', true);
@@ -1500,82 +1452,6 @@ export default function Settings() {