@adlc/review-calibration

中文文档
1.12.0发布于 2026/10/10MITES Module构建来源已验证近 30 天下载 8129

Measures reviewer recall via planted bugs — who reviews the reviewer (P5 meta-gate).

原始使用文档
文档目录11 节
  1. How it works
  2. Scorer modes ( --scorer )
  3. Safety
  4. Usage
  5. Options
  6. Exit codes
  7. Examples
  8. JSON output shape
  9. Scoring logic
  10. Relationship to sibling tools
  11. Core gaps

@adlc/review-calibration

ADLC phase: P5 meta-gate — "who reviews the reviewer"

Measures reviewer recall via planted bugs. Turns "we do adversarial review" from a vibe into a number, exposes category-level blind spots, and re-runs on every model change — catching the silent regressions everyone currently absorbs unknowingly.

This is mutation testing aimed at the reviewer instead of the code (ADLC C8).

How it works

  1. Target files: Files changed in --commit (git diff-tree) filtered to non-test, non-config source code. Falls back to --files if the commit touches no eligible files.
  2. Plant selection: mutate.generateMutants runs over each target file's full content. Up to --plants mutants are selected by round-robining across operators for coverage. Each plant carries a real bug category (off-by-one, logic-inversion, null-handling, …) and a defect description. --plants-file plants may also carry a witness.
  3. Equivalent-mutant filter: a plant with a witness must DISCRIMINATE (pass on the original, fail on the mutant). Plants whose witness does not discriminate are equivalent mutants — there is no bug to find, so they are excluded from the denominator rather than scored as missed. Each exclusion is printed to stderr with its reason; a witness that fails on the ORIGINAL (a broken witness rather than an equivalent mutant) includes the tail of that run's output, and one that cannot start says so instead of "timed out".
  4. Control self-test (scorer): before scoring, two reference reviewers run through the deterministic referenceJudge — an echoer (must score ~0) and an oracle (must score 1.0). If either is wrong the scorer itself is broken and the tool exits 1. This bounds the scorer's aggregation — that it has no non-semantic shortcut — and nothing else. 4b. Control self-test (judge): the number you actually get is produced by the configured judge, not referenceJudge, so the echo control runs a second time through that judge whenever it rendered at least one verdict. In the default judge mode an unbounded judge is an operational failure (exit 1) — a judge that cannot reject an echoing reviewer cannot certify a recall figure. --scorer string sets the judge to "match everything" by construction, so it can never be bounded: that run still completes, and reports configuredJudgeBounded: false so the uncertified number is visible to a machine consumer rather than only to a stderr warning. When no finding located a plant the judge was never consulted, and both configuredJudgeBounded and configuredJudgeEchoRecall are null — it contributed nothing to the score, so there was nothing to bound.
  5. Apply all plants, run --review-cmd ({base} → commit ref), restore (atomically, via finally + SIGINT handler; a killed run is restored by the next one — see Safety).
  6. Parse findings: the reviewer's output is parsed as structured findings (adversarial-review --json shape, or a weak prose fallback).
  7. Score: a plant is CAUGHT only when a finding LOCATES it (file + line ±3) AND the configured judge (a cheap model) confirms it identifies the defect. A repro field on a finding is parsed but never run: the CLI does not execute commands supplied by the reviewer it is measuring. There is no string-match shortcut: a reviewer that echoes changed lines scores ~0. Recall = caught / valid plants. Precision = true / (true + spurious findings), where a finding that locates a plant without identifying it is spurious.
  8. Gate: Exit 2 if recall < --min-recall (or precision < --min-precision when set); exit 0 otherwise. Exit 1 on operational error or a failed control.

Scorer modes (--scorer)

  • judge (default) — cheap-model semantic match. Requires an LLM provider (ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY). With no provider the tool fails closed (exit 1) rather than emit an untrustworthy number. Every locating finding is judged, including one that carries a repro.
  • string — LEGACY location-only matching. Gameable by a reviewer that echoes changed lines; prints a warning and is not a trustworthy recall number. Provided only as an offline escape hatch.

See REDESIGN.md for the full design and the rationale for each decision.

Safety

  • Refuses to run on a dirty working tree (opError, exit 1). Commit or stash first.
  • Plants are written and restored atomically (temp file + rename), so no source file is ever left truncated.
  • On a normal exit, an error or Ctrl-C, files are restored by the runner's finally block (and the CLI's SIGINT handler).
  • A run killed mid-review (SIGTERM from a CI cancel, docker stop, SIGKILL) cannot restore anything itself — the review runs inside spawnSync, where no signal handler runs. Before planting, the CLI writes an in-flight record of each file's original and planted contents to the git dir (.git/adlc-review-calibration-inflight.json). The next run restores those files before its dirty-tree check and says so on stderr. It only restores a file that still holds exactly the planted content; if the file has changed since, it refuses (exit 1), writes nothing and keeps the record, which then holds the only copy of the original. A record owned by a process that is still running is left alone (exit 1).
  • Exit codes from the review command: 0 and 2 are valid (pass / gate-fail). Any other exit code is treated as a crash (opError, exit 1).

Usage

review-calibration --review-cmd "cmd with {base} placeholder" [options]

Options

FlagDefaultDescription
--review-cmd <cmd>(required)Shell command to run the reviewer. {base} is substituted with the commit ref.
--commit <ref>HEADCommit whose changed files are used as plant targets.
--plants <n>8Number of bugs to plant.
--min-recall <f>0.5Minimum recall fraction required to pass (0–1).
--files <list>—Comma-separated fallback file list when commit has no eligible code files.
--jsonfalseMachine-readable JSON output.
--help—Show help.

Exit codes

CodeMeaning
0Gate passes — recall ≥ --min-recall
1Operational error — dirty tree, no plants generatable, review command crashed (exit ∉ {0,2}), or bad arguments
2Gate fails — recall < --min-recall

Examples

Basic calibration with adversarial-review:

review-calibration \
  --review-cmd "adversarial-review --base {base} --json" \
  --commit HEAD \
  --plants 8 \
  --min-recall 0.6

JSON output for orchestrators:

review-calibration \
  --review-cmd "my-reviewer {base}" \
  --json

Custom file fallback (when commit has no eligible source files):

review-calibration \
  --review-cmd "my-reviewer {base}" \
  --commit HEAD \
  --files "src/auth.mjs,src/api.mjs"

Testing with a trivial fake reviewer (CI smoke test):

review-calibration \
  --review-cmd 'node -e "process.stdout.write(\"LGTM\\n\")"' \
  --min-recall 0 \
  --json

JSON output shape

{
  "recall": 0.625,
  "caught": 5,
  "total": 8,
  "precision": 0.83,
  "truePositives": 5,
  "falsePositives": 1,
  "minRecall": 0.5,
  "minPrecision": null,
  "gatePass": true,
  "scorer": "judge",
  "judgeAgreement": null,
  "equivalentExcluded": 0,
  "commit": "HEAD",
  "reviewExitCode": 0,
  "perCategory": {
    "off-by-one":      { "caught": 2, "total": 2, "recall": 1.0 },
    "logic-inversion": { "caught": 2, "total": 4, "recall": 0.5 },
    "null-handling":   { "caught": 1, "total": 2, "recall": 0.5 }
  },
  "plants": [
    {
      "file": "src/auth.mjs",
      "line": 42,
      "category": "logic-inversion",
      "operator": "invert-comparison",
      "status": "caught",
      "original": "  if (user.role === 'admin') {",
      "mutated":  "  if (user.role !== 'admin') {"
    }
  ]
}

precision is real: truePositives / (truePositives + falsePositives), where a false positive is a finding that locates no plant (in a clean base + only-our-plants tree, nothing else is broken) or one that locates a plant but identifies no plant's defect — an unsubstantiated claim such as an echo of the changed line. Every locating finding gets its own verdict, so padding a real catch with echoes lowers precision. unsubstantiated reports how many of the false positives were of the second kind. When truePositives + falsePositives === 0 (the reviewer produced no findings), precision is null (not 1.0) because precision cannot be evaluated; configuring --min-precision will fail the gate if precision is null.

Scoring logic

Caught — a plant is caught only when a finding does BOTH:

  1. Locates it — mentions the file's basename and a line within ±3.
  2. Identifies it — a cheap-model judge confirms the finding describes this defect. (scorePlants accepts an injected verifyRepro for library callers; the CLI does not supply one.)

There is no "output contains a substring of the changed line" rule: that is exactly what let a line-echoing reviewer score 1.0. Echoing locates but does not identify, so it scores ~0 — enforced by the built-in echo control on every run.

Per-category recall — the catch rate broken down by real bug category (off-by-one, logic-inversion, null-handling, …), so low recall on a category points at a specific reviewer blind spot.

Relationship to sibling tools

ToolRole
hollow-test (C4)Mutation testing aimed at tests — kills mutants via the test suite
review-calibration (C8)Mutation testing aimed at the reviewer — measures reviewer recall
adversarial-reviewThe reviewer under test; wire its output to --review-cmd
gate-manifest (C11)Records the calibration score alongside each review verdict

Core gaps

None — all required functionality (mutate.generateMutants, mutate.applyMutant, isDirty, isGitRepo, git, parseArgs, pass, gateFail, opError, printJson) is available in @adlc/core.

版本与发布记录

@adlc/review-calibration 共发布 18 个版本,首次发布于 2026/06/14;过去 12 个月发布了 18 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.12.0latest2026/10/1027 天前
1.11.12026/09/091 个月前
1.11.02026/08/252 个月前
1.10.02026/08/112 个月前
1.9.02026/08/092 个月前
1.8.02026/08/082 个月前

关于 @adlc/review-calibration 的常见问题

@adlc/review-calibration 是什么?

Measures reviewer recall via planted bugs — who reviews the reviewer (P5 meta-gate).

如何安装 @adlc/review-calibration?

在项目目录运行 npm install @adlc/review-calibration,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 review-calibration,可以用 npx review-calibration 直接运行。

@adlc/review-calibration 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/adlc__review-calibration 是否存在。

@adlc/review-calibration 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@adlc/review-calibration 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@adlc/review-calibration 可以商用吗?

@adlc/review-calibration 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@adlc/review-calibration 的下载量有多少?

根据 npm 官方下载统计,@adlc/review-calibration 在 2026/10/05 – 2026/11/03 这 30 天内被下载 8,129 次,日均约 271 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@adlc/review-calibration 还在维护吗?

最新版本 1.12.0 发布于 2026/10/10(27 天前);至今共发布 18 个版本,其中过去 12 个月发布了 18 个;首次发布于 2026/06/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。