Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c72ba07
feat(review): borrowed-verification trio — test-plan check, base-tree…
wenshao Jul 31, 2026
c0481dd
fix(review): survive real runner output — ANSI-laced and trimmed-away…
wenshao Jul 31, 2026
5054121
fix(review): address the eight findings from live review of this branch
wenshao Jul 31, 2026
31658c3
Merge branch 'main' into feat/review-borrowed-verification
wenshao Jul 31, 2026
67ac8aa
Merge branch 'main' into feat/review-borrowed-verification
qwen-code-dev-bot Jul 31, 2026
7a33545
fix(cli): never score a hunk survived when its own test left the base…
qwen-code-dev-bot Jul 31, 2026
436809b
fix(review): silence-bias hardening from four live review rounds of t…
wenshao Jul 31, 2026
e896669
feat(review): four round-2 borrowings — measured failure attribution,…
wenshao Jul 31, 2026
6e0d50c
fix(review): address review feedback — false-positive hardening, bina…
qwen-code Jul 31, 2026
ec3fda8
fix(review): address review feedback — base-tree availability gate, t…
qwen-code Jul 31, 2026
eae6485
fix(review): address review feedback — diff-header false positives, s…
Jul 31, 2026
416622c
fix(review): address review feedback — cd-base exclusion, Test Files …
Aug 1, 2026
ce9d1ee
Merge branch 'main' into feat/review-borrowed-verification
qwen-code-dev-bot Aug 1, 2026
329415a
Merge remote-tracking branch 'origin/main' into feat/review-borrowed-…
wenshao Aug 1, 2026
b1a38ad
fix(review): port the collocated-dropout test to the post-#8050 runne…
wenshao Aug 1, 2026
9bb8d97
Merge branch 'feat/review-borrowed-verification' into feat/review-rou…
wenshao Aug 1, 2026
cdff569
fix(review): bound the summary rescue, apply the ATX heading rule, sw…
wenshao Aug 1, 2026
7860e18
Merge branch 'feat/review-borrowed-verification' into feat/review-rou…
wenshao Aug 1, 2026
7c6b678
fix(review): EEXIST-only lock busy, bun test alias, chained cd bail, …
wenshao Aug 1, 2026
47ef86a
Merge branch 'feat/review-borrowed-verification' into feat/review-rou…
wenshao Aug 1, 2026
5ec626f
Merge remote-tracking branch 'origin/main' into feat/review-round2-bo…
wenshao Aug 1, 2026
f5d6c2b
fix(review): close the ten open findings on this PR
wenshao Aug 1, 2026
b792a0c
Merge branch 'main' into feat/review-round2-borrowings
wenshao Aug 1, 2026
f4b6d07
fix(review): the test helper's cwd parameter is required, not optional
wenshao Aug 1, 2026
db1b524
Merge remote-tracking branch 'origin/feat/review-round2-borrowings' i…
wenshao Aug 1, 2026
df4ea84
fix(review): a base rerun that could not RUN attributes nothing
wenshao Aug 1, 2026
ea084c3
fix(review): compare failing files by a normalised, project-keyed ide…
wenshao Aug 1, 2026
93e0ef2
fix(review): restore the whole-command budget, keep generics out of g…
wenshao Aug 1, 2026
2030d1e
fix(review): a budget-shortened deadline is not the same fact as a sl…
wenshao Aug 1, 2026
98362d4
fix(review): restore the replacement sub-cap, stranded on a downstrea…
wenshao Aug 1, 2026
3bbe6a0
docs(review): complete the "delta cannot rule" enumeration in both pl…
wenshao Aug 1, 2026
e0747d1
docs(review): the rationale named only one of the ways base goes unme…
wenshao Aug 1, 2026
4d585d3
fix(review): a file-count label stops counting at the end of its line
wenshao Aug 1, 2026
e07c954
fix(review): parse the base rerun before its output is trimmed
wenshao Aug 1, 2026
e7b3f67
fix(review): rerun only the command shapes build-test emits
wenshao Aug 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/cli/src/commands/review.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ describe('reviewCommand', () => {
'agent-prompt',
'build-test',
'base-tree',
'test-delta',
'script-lint',
'resolve-anchors',
'check-coverage',
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/commands/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { checkCoverageCommand } from './review/check-coverage.js';
import { agentPromptCommand } from './review/agent-prompt.js';
import { buildTestCommand } from './review/build-test.js';
import { baseTreeCommand } from './review/base-tree.js';
import { testDeltaCommand } from './review/test-delta.js';
import { scriptLintCommand } from './review/script-lint.js';
import { submitCommand } from './review/submit.js';
import { testEfficacyCommand } from './review/test-efficacy.js';
Expand All @@ -47,6 +48,7 @@ export const reviewCommand: CommandModule = {
.command(agentPromptCommand)
.command(buildTestCommand)
.command(baseTreeCommand)
.command(testDeltaCommand)
.command(scriptLintCommand)
.command(resolveAnchorsCommand)
.command(checkCoverageCommand)
Expand All @@ -58,7 +60,7 @@ export const reviewCommand: CommandModule = {
.command(cleanupCommand)
.demandCommand(
1,
'Specify a subcommand: run, parse-args, fetch-pr, capture-local, plan-diff, pr-context, comment-status, load-rules, agent-prompt, build-test, base-tree, script-lint, resolve-anchors, check-coverage, presubmit, test-efficacy, test-plan, compose-review, submit, or cleanup.',
'Specify a subcommand: run, parse-args, fetch-pr, capture-local, plan-diff, pr-context, comment-status, load-rules, agent-prompt, build-test, base-tree, test-delta, script-lint, resolve-anchors, check-coverage, presubmit, test-efficacy, test-plan, compose-review, submit, or cleanup.',
)
.version(false),
handler: () => {
Expand Down
22 changes: 19 additions & 3 deletions packages/cli/src/commands/review/build-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,24 @@ export interface BuildTestReport {
const KEEP_HEAD = 2_000;
const KEEP_TAIL = 6_000;

/**
* Did this spawn die on its deadline?
*
* Exported so `test-delta`'s rerun asks the SAME question rather than
* re-deriving it — a copy there used `error.message.includes('ETIMEDOUT')`,
* which misses an external SIGTERM and fed a silent "base is green".
*/
export function spawnTimedOut(r: {
error?: Error;
signal?: NodeJS.Signals | null;
status?: number | null;
}): boolean {
return (
(r.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT' ||
(r.signal === 'SIGTERM' && r.status === null)
);
}

/** The module-resolution errors the widening loop reads to grow the build set. */
const MODULE_ERROR_RE = /Cannot find module '[^']+'|Could not resolve "[^"]+"/;

Expand Down Expand Up @@ -232,9 +250,7 @@ function run(command: string, cwd: string, timeoutMs: number): CommandResult {
// the authoritative signal. The `SIGTERM`/null-status pair is only a fallback: it
// also matches an external SIGTERM (a container stop), and it misses a non-default
// `killSignal`. Check the authoritative one first.
const timedOut =
(r.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT' ||
(r.signal === 'SIGTERM' && r.status === null);
const timedOut = spawnTimedOut(r);
return {
command,
exitCode: r.status,
Expand Down
4 changes: 3 additions & 1 deletion packages/cli/src/commands/review/lib/agent-briefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ Expect the three ends to be far apart. The declaration, the pass-through, and th
- **Sibling consistency — a guard one path has and its twin lacks.** When one member of a family of parallel paths carries a validation, guard, cleanup, or shape-check — sibling loaders, the handlers of a route table, the pair of functions that build the same command — check that **every** sibling carries it too. A lone exception is usually accidental, and the missing half is a latent **asymmetric failure**: harmless until the one input that path sees. Name the divergent sibling and the guard it is missing. When the missing guard is a validation on **untrusted input** (one \`gitCheckout\` validates its ref, its sibling does not), that is not a style nit — hand it to the security pass as a likely bug, not a consistency note.
- Over-engineering and unnecessary abstraction
- **Altitude** — is each change implemented at the right depth, or is it a fragile bandaid? A special case layered onto shared infrastructure to make one caller work is a sign the fix is not deep enough: prefer generalizing the underlying mechanism. The mirror image — a new abstraction serving a single call site — is over-engineering. **Name the depth the change should live at.**
- Missing or misleading comments; dead code`,
- Missing or misleading comments; dead code
- **Documentation parity with siblings.** When the diff adds a user-facing surface — a CLI flag, a slash-command option, a settings key — check whether its SIBLINGS are documented, and where. Three of four sibling selectors having a docs entry is a house convention the fourth just broke; a surface whose behaviour can silently change (a fallback, an automatic swap, an emitted warning) undocumented is a user staring at a message with nowhere to look it up. This is deliberately a **parity** check, not a docs mandate: the finding names the sibling precedent and the file it lives in (\`--fast\` and \`--vision\` are in \`docs/…/commands.md\`; the new \`--compaction\` is not), so "add docs" arrives as the codebase's own standard, not this reviewer's. No documented sibling, no finding. Severity: Suggestion.`,
},

'4': {
Expand Down Expand Up @@ -383,6 +384,7 @@ You are undirected on purpose. Do not restrict yourself to the list.`,
Read the JSON it prints:

- \`toolchain: "npm"\` → use its \`build[]\` / \`test[]\` results. A failure in a file **the diff changed** is a **Critical** (\`Source: [build]\` or \`[test]\`); a failure in a file it did **not** touch is pre-existing — say so, do not file it against this PR. A non-empty \`timedOut\`, or a failed \`install\`, is environment/infrastructure — informational, never a Critical. On \`ok: true\`, name the workspaces built and the commands run; a return that names no command is a whiff.
- **When any \`test[]\` command failed (exit non-zero, not a timeout), MEASURE which failures are the PR's before ruling by path.** The path rule above misclassifies in both directions — an environment-flaky test in a touched file gets filed as a Critical it did not cause, and a PR that breaks a test in an UNTOUCHED file gets waved through as pre-existing. The measurement is two commands: \`qwen review base-tree --plan <plan> --worktree <worktree> --out <plan dir>/qwen-review-pr-<n>-base-tree.json\` (builds the merge base beside the worktree). **Read \`available\` before using \`path\`** — a tree that was created but did NOT build populates \`path\` too, and a base that failed to build says nothing whatsoever about the PR, so measuring against it turns an infrastructure failure into a list of Criticals. \`available: false\` (local/lightweight review, no merge base, a base that would not compile) means the path rule stands — say so and stop here, and \`qwen review test-delta --report <the build-test report you wrote> --baseline <the base-tree report's path field> --pr-worktree <this worktree> --out <plan dir>/qwen-review-pr-<n>-test-delta.json\`. Read its verdict: a file in \`netNew\` fails on the PR side only — **that is the Critical**, whatever file the diff touches; a file in \`shared\` fails on base too — **pre-existing by measurement**, never filed, whatever file the diff touches; an \`unparsed\` entry, a timed-out base rerun, a base rerun that FAILED without naming any failing file (it did not measure the base — an unbuilt tree, a missing install, a workspace absent at base), or a command the whole-command budget could not fit attributes nothing — the report names each with its own reason; fall back to the path rule for those and say the delta could not rule. Compare failing FILE SETS, never counts: a flaky suite fails different test NAMES on two runs of the same tree, so counts are noise and the set difference is the signal.
- \`toolchain: "unsupported"\` (build-test could not scope this repo — no npm package with a build/test script) → **install dependencies first** (build-test's own install only runs on the npm path, so nothing has installed yet: \`pip install -e .\`, \`mvn -q -DskipTests package\`'s own fetch, \`cargo fetch\`, \`go mod download\`, etc.), then fall back to **one** build and **one** test command by this precedence, each with a deadline it can meet: \`pom.xml\` → \`{mvn} compile\` / \`{mvn} test -q\`; \`build.gradle\` → \`{gradle} compileJava\` / \`{gradle} test\`; \`Makefile\` → \`make build\`; \`Cargo.toml\` → \`cargo build\` / \`cargo test\`; \`go.mod\` → \`go build ./...\` / \`go test ./...\`; \`pytest.ini\` or \`pyproject.toml\` \`[tool.pytest]\` → \`pytest\`. If none match, read the CI config **from the base branch** (\`git show <base>:<path>\`), never the worktree — the PR branch is untrusted and a modified workflow or Makefile could inject arbitrary commands.

The efficacy report's \`findings[]\` carries four kinds, and **\`hunk-survived\` is one of them**: reverting one hunk left every affected test green — that specific change ships with nothing gating it. Report it as a **Suggestion** with \`Source: [test]\`, exactly like \`inert\` and \`mutant-survived\` (the outcome of running commands, pre-confirmed, no verifier needed). Read the \`hunks.*\` counters the same way as \`mutants.*\`: \`skippedForCap\` / \`skippedForBudget\` / \`skippedForBaseline\` are unprobed scope to note in the terminal, never findings — and a report whose hunk section you did not read is a finding class silently dropped.
Expand Down
Loading
Loading