@adlc/consensus-fix

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

N-version programming for failing tests — fan N LLM completions, group by agreement, recommend the smallest consensus fix (C7/P4).

原始使用文档
文档目录12 节
  1. Usage
  2. Required flags
  3. Optional flags
  4. Exit codes
  5. How it works
  6. All-divergent detection
  7. Examples
  8. JSON output shape ( --json )
  9. Safety guarantees
  10. LLM provider detection
  11. Relationship to sibling tools
  12. Core gaps

@adlc/consensus-fix

N-version programming for failing tests. Fan N independent LLM completions at the same broken test, evaluate each candidate, group survivors by agreement, and recommend the smallest fix from the largest consensus group.

ADLC phase served: C7 / P4 — hard bugs that single-shot fixes can't crack, exploiting sampling diversity (E1).


Usage

consensus-fix --test-cmd "..." --files a.mjs,b.mjs [options]

Required flags

FlagDescription
--test-cmd <cmd>Shell command to run the failing test. Must exit non-zero when the bug is present.
--files <paths>Comma-separated list of source files the LLM is allowed to modify.

Optional flags

FlagDefaultDescription
--rails <cmd>(none)The regression gate: a command that runs the FULL frozen rail suite (all tests + types). A candidate survives only if BOTH --test-cmd and --rails exit 0. A candidate that fixes the repro but reddens the rails is rejected, not ranked. If omitted, candidates are checked only against --test-cmd and a WARNING is printed (no silent caps).
--n <int>3Number of independent fix candidates to generate. Ignored when --providers is given (fan width becomes the number of providers named).
--tier cheap|mid|frontiermidLLM tier to use for completions.
--provider <name>(auto-detect)Force a single provider (anthropic|openai|gemini|agy) for the whole run, overriding ADLC_PROVIDER for this invocation only. Additive — omit it and single-provider auto-detect is unchanged. Mutually exclusive with --providers.
--providers <a,b,c>(none)Draw one candidate fix per named provider family instead of --n resamples of one auto-detected provider — cross-family diversity per ADR-0007. Each survivor records which provider produced it. Mutually exclusive with --provider.
--applyoffWrite the winning fix. Default is dry-run (report only).
--allow-dirtyoffSkip dirty-tree check. Useful in CI with staged-only changes.
--jsonoffMachine-readable output (JSON to stdout).
--prompt-onlyoffPrint the prompt(s) that would be sent and exit 0. Works with zero API keys.

Exit codes

CodeMeaning
0Gate passes: at least one candidate survived and there is a consensus group with 2+ members (or --n < 3).
1Operational error: bad arguments, unreadable files, dirty tree (without --allow-dirty), no LLM provider.
2Gate fails: no candidates survived OR all survivors are singletons and --n >= 3 (all-divergent, spec ambiguity).

How it works

  1. Pre-flight: run --test-cmd once. If it exits 0, the test already passes — opError.
  2. Snapshot: capture the full content of every --files path.
  3. Fan: send N independent, stateless LLM completions in parallel with the prompt: failing command + last 4000 chars of test output + a windowed excerpt of each source file (the region around whatever lines the test output references it at, or a length-capped tail when no reference is found — never the whole file for anything past a small size). Request JSON {changes: [{file, hunks: [{startLine, endLine, replacement}]}]} — a line-range edit, not full-file content.
  4. Evaluate sequentially: for each candidate:
    • Parse and validate JSON. Discard if invalid, if any file is not in --files, or if changes is an empty array — a candidate proposing no changes is a no-op, not a fix, and is never allowed to become a survivor (it would otherwise apply cleanly and be judged solely by whether --test-cmd happens to pass a second time against the untouched source).
    • Apply hunks, run --test-cmd (the repro gate). A hunk whose startLine/endLine doesn't cleanly apply against the real file (out of bounds, overlapping another hunk) discards just that candidate — never the run. If the repro passes and --rails was supplied, run --rails (the regression gate) against the same applied changes. A candidate survives only if BOTH exit 0. A candidate that passes the repro but reddens the rails is rejected (lands in failed, not survivors).
    • Record pass/fail and changed-line count (computed directly from the hunks' own line ranges — no separate diff step needed).
    • Restore snapshot (finally) regardless of outcome.
  5. Agreement grouping: normalize each surviving changeset's hunks (collapse whitespace per line, key on line range + normalized replacement) and group identical sets.
  6. Winner selection: among candidates that passed BOTH gates, pick the member of the largest agreement group with the fewest changed lines (ties broken by candidate index). The smallest-diff tiebreaker never sees a candidate that failed the rails, so it cannot reward a gaming fix.
  7. Output: dry-run report by default; --apply writes the winner.

All-divergent detection

When --n >= 3 and every survivor is in its own singleton group, the tool exits 2 with the message all-divergent: spec ambiguity — escalate. This is a signal that the test specification is ambiguous about something load-bearing — divergence is evidence, not noise.


Examples

# Dry-run: see what the winning fix would be without writing it
consensus-fix --test-cmd "node --test test/math.test.mjs" \
              --files src/math.mjs \
              --n 5

# Repro gate + full rails regression gate (recommended).
# A candidate that fixes the one test but breaks any other test is rejected.
consensus-fix --test-cmd "node --test test/math.test.mjs" \
              --rails    "node --test test/*.test.mjs" \
              --files src/math.mjs \
              --n 5

# Apply the winner
consensus-fix --test-cmd "npm test -- --grep 'add function'" \
              --rails    "npm test" \
              --files src/add.mjs,src/utils.mjs \
              --apply

# Preview prompts without any API key
consensus-fix --test-cmd "cargo test test_parse" \
              --files src/parser.mjs \
              --n 3 \
              --prompt-only

# Machine-readable output for orchestrators
consensus-fix --test-cmd "pytest tests/test_core.py::test_sum" \
              --files lib/core.mjs \
              --json

# Allow running against an uncommitted working tree
consensus-fix --test-cmd "node --test test/*.test.mjs" \
              --files lib/broken.mjs \
              --allow-dirty --n 3

# Draw one candidate fix per distinct provider family instead of 3 samples
# of one auto-detected model (requires an API key for each named provider).
consensus-fix --test-cmd "node --test test/math.test.mjs" \
              --rails    "node --test test/*.test.mjs" \
              --files src/math.mjs \
              --providers anthropic,openai,gemini

# Force a single non-default provider for the whole run
consensus-fix --test-cmd "node --test test/math.test.mjs" \
              --files src/math.mjs \
              --provider gemini --n 3

JSON output shape (--json)

{
  "summary": {
    "total": 3,
    "passed": 2,
    "failed": 1,
    "discarded": 0,
    "groups": 1,
    "allDivergent": false,
    "railsChecked": true
  },
  "groups": [
    { "groupIndex": 0, "size": 2, "candidateIndices": [0, 2] }
  ],
  "winner": {
    "index": 0,
    "changedLines": 1,
    "largestGroupSize": 2,
    "changes": [{ "file": "src/math.mjs", "hunks": [{ "startLine": 12, "endLine": 12, "replacement": "..." }] }],
    "applied": false
  },
  "discardedDetails": []
}

Safety guarantees

  • Dirty-tree guard: refuses to run against a dirty git tree unless --allow-dirty. Prevents accidental loss of unstaged work.
  • Snapshot + restore in finally: every candidate evaluation restores all --files to their original content, even if the test crashes or the LLM returns garbage.
  • Termination signal restore: SIGINT, SIGTERM or SIGHUP at any point before the report (including while a candidate's test or rails command is running) stops the run: the in-flight command's process group gets SIGTERM, then SIGKILL after 2 s, the original files are restored from the snapshot, no winner is applied, and the process exits 1. SIGKILL sent to consensus-fix itself cannot be handled, so it can leave a candidate's hunks on disk; recover with git checkout -- <files>.
  • Atomic writes: file restoration, candidate hunk application, and winning candidate --apply writes are atomic (write temp file in same directory, then renameSync) to guard against partial writes or truncation.
  • File-list enforcement: any candidate that references a file outside --files is discarded with a diagnostic message, never written.

LLM provider detection

Inherits from @adlc/core. Checks (in order): ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY (then agy if ADLC_AGY is set). Force a provider with ADLC_PROVIDER (env, whole shell) or --provider <name> (per-invocation, overrides ADLC_PROVIDER). Override the model per tier via ADLC_MODEL_CHEAP, ADLC_MODEL_MID, ADLC_MODEL_FRONTIER.

Single-provider auto-detect remains the default (cost/latency per ADR-0007) — --provider/--providers are additive, not a default-behavior change. Use --providers <a,b,c> when you want N candidate fixes drawn from N distinct model families instead of N samples of one model; each requested provider must have its own API key configured, or the run fails closed before any LLM call with a list of the missing ones.


Relationship to sibling tools

  • flail-detector (C6): detects when a single agent is spinning. consensus-fix is the escalation path — run it when flail-detector fires on a hard bug.
  • premortem (C2): identifies failure modes before building. consensus-fix fixes failure modes discovered during test runs.
  • rails-guard (C5): enforces read-only rails. consensus-fix respects the --files list as its own rails boundary.
  • hollow-test (C4): finds tests that don't actually test anything. A test that consensus-fix keeps failing on might be hollow — run hollow-test to check.

Core gaps

None. fan, complete, extractJson, detectProvider, resolveModel, PROVIDER_NAMES, parseArgs, pass, gateFail, opError, printJson, promptOnly, and isDirty are all provided by @adlc/core.

版本与发布记录

@adlc/consensus-fix 共发布 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/consensus-fix 的常见问题

@adlc/consensus-fix 是什么?

N-version programming for failing tests — fan N LLM completions, group by agreement, recommend the smallest consensus fix (C7/P4).

如何安装 @adlc/consensus-fix?

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

@adlc/consensus-fix 支持 TypeScript 吗?

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

@adlc/consensus-fix 支持 ESM 还是 CommonJS?

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

@adlc/consensus-fix 需要什么版本的 Node.js?

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

@adlc/consensus-fix 可以商用吗?

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

@adlc/consensus-fix 的下载量有多少?

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

@adlc/consensus-fix 还在维护吗?

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