Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 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
c50547c
feat(review): render adjudication, workflow step extraction, three ve…
wenshao Jul 31, 2026
1cfff3e
feat(review): sibling-entrance discipline for the fixed verdict
wenshao Jul 31, 2026
efe9582
feat(review): three measured-verification lenses from live rounds 803…
wenshao Jul 31, 2026
15a4560
feat(review): carry the round ledger in the posted review body
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
ddf227c
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
3008454
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
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
b0c0a74
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
452bade
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
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
20899a6
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
058a3b5
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
wenshao Aug 1, 2026
5ec626f
Merge remote-tracking branch 'origin/main' into feat/review-round2-bo…
wenshao Aug 1, 2026
e915dc2
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
de522e0
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
wenshao Aug 1, 2026
554aac1
fix(review): make the ledger marker actually reach the posted body
wenshao Aug 1, 2026
f5d6c2b
fix(review): close the ten open findings on this PR
wenshao Aug 1, 2026
8579d3a
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
ccf3052
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
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
12a9eae
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
0caa34c
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
wenshao Aug 1, 2026
df4ea84
fix(review): a base rerun that could not RUN attributes nothing
wenshao Aug 1, 2026
3b317b4
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
4d9ccd0
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
wenshao Aug 1, 2026
1748fce
fix(review): extract-step resolves all three env/defaults levels, and…
wenshao Aug 1, 2026
ea084c3
fix(review): compare failing files by a normalised, project-keyed ide…
wenshao Aug 1, 2026
4b39b99
Merge branch 'feat/review-round2-borrowings' into feat/review-render-…
wenshao Aug 1, 2026
5cff748
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
wenshao Aug 1, 2026
0e5bd00
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
8835bf3
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
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
f4a13ec
fix(review): brace-tolerant stub list, pipefail fidelity, and extract…
wenshao Aug 1, 2026
98362d4
fix(review): restore the replacement sub-cap, stranded on a downstrea…
wenshao Aug 1, 2026
11bdcac
fix(review): one severity predicate, carried ids, and a lossless marker
wenshao Aug 1, 2026
3bbe6a0
docs(review): complete the "delta cannot rule" enumeration in both pl…
wenshao Aug 1, 2026
0e78efa
fix(review): the invokes list was mostly prose, not commands
wenshao Aug 1, 2026
e0747d1
docs(review): the rationale named only one of the ways base goes unme…
wenshao Aug 1, 2026
c777a36
fix(review): a quoted `<<EOF` is not a heredoc, and a continued line …
wenshao Aug 1, 2026
12c2f62
Merge remote-tracking branch 'origin/feat/review-round2-borrowings' i…
wenshao Aug 1, 2026
2721a3a
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
d16bf28
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
82fd3b6
fix(review): case labels, a second heredoc, and an expression in comm…
wenshao Aug 1, 2026
56652fd
fix(review): annotate the continuation accumulator so tsc can type it
wenshao Aug 1, 2026
0d97c3c
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
4d585d3
fix(review): a file-count label stops counting at the end of its line
wenshao Aug 1, 2026
6c474d0
Merge remote-tracking branch 'origin/feat/review-round2-borrowings' i…
wenshao Aug 1, 2026
067c993
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
e07c954
fix(review): parse the base rerun before its output is trimmed
wenshao Aug 1, 2026
0f15b61
Merge remote-tracking branch 'origin/feat/review-round2-borrowings' i…
wenshao Aug 1, 2026
dff65f4
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
0af039e
test(review): pin the `sh` set-line to exactly what the runner uses
wenshao Aug 1, 2026
b5800c1
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
e7b3f67
fix(review): rerun only the command shapes build-test emits
wenshao Aug 1, 2026
b5d10f7
Merge remote-tracking branch 'origin/feat/review-round2-borrowings' i…
wenshao Aug 1, 2026
40afca9
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
7e33f06
Merge branch 'main' into feat/review-render-and-step-harness
wenshao Aug 1, 2026
f337980
Merge branch 'feat/review-render-and-step-harness' into feat/review-p…
wenshao Aug 1, 2026
06b7831
Merge remote-tracking branch 'origin/main' into feat/review-render-an…
wenshao Aug 1, 2026
b4ebd3b
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
4201e23
fix(review): the working directory is a setting the extraction was lo…
wenshao Aug 1, 2026
1eb300c
fix(review): $(( )) is arithmetic, and a heredoc's form decides where…
wenshao Aug 1, 2026
8acc1d2
fix(review): refuse an ambiguous step name, and report errors like th…
wenshao Aug 1, 2026
698d08d
docs(review): the brief's list of limits was one short
wenshao Aug 1, 2026
ffc71d9
chore(review): drop a scratch probe file that reached the branch
wenshao Aug 1, 2026
9251a5f
Merge remote-tracking branch 'origin/feat/review-render-and-step-harn…
wenshao Aug 1, 2026
81898af
Merge branch 'main' into feat/review-persistent-ledger
wenshao Aug 1, 2026
2ebb18c
fix(review): bound the whole ledger marker, not just each of its fields
wenshao Aug 1, 2026
051b204
fix(review): a partial ledger must not render as a complete one
wenshao Aug 1, 2026
e89508e
fix(review): an empty ledger title is a cap the next round cannot lift
wenshao Aug 1, 2026
24c6d3e
fix(review): count both caps as dropped, not just the byte one
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
200 changes: 200 additions & 0 deletions packages/cli/src/commands/review/compose-review.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import { join } from 'node:path';
import { createHash } from 'node:crypto';
import { promptRecordDir, briefPath } from './lib/prompt-record.js';
import { getGhHost, setGhHost } from './lib/gh.js';
import { parseLedger } from './lib/ledger.js';
import { countInlineFindings } from './lib/inline-counts.js';
import {
composeReview,
buildLedger,
scriptLintGate,
testPlanGate,
composeReviewCommand,
Expand Down Expand Up @@ -3122,3 +3125,200 @@ describe('testPlanGate — Test Plan rulings, disclosed but never capping', () =
expect(notes[5]).toBe('and 3 more');
});
});

describe('buildLedger', () => {
it('gives a text-less finding a locating title instead of an empty one', () => {
// A comment that is nothing but its severity marker used to yield an empty
// title, and an empty title jams the review rather than merely degrading
// the entry: the next round is told every ledger entry is owed a ruling,
// has no claim to rule on, answers `cannot tell`, and that is
// `cannot-tell-existing-critical` — a cap that nothing between rounds can
// lift. Keep the entry (the Critical really was posted) and hand over the
// one handle there is.
const l = buildLedger(
2,
[{ path: 'packages/cli/src/a.ts', line: 42, body: '**[Critical]**' }],
[' '],
);
expect(l.findings[0].title).toContain('packages/cli/src/a.ts:42');
expect(l.findings[0].title).not.toBe('');
expect(l.findings[1].title).toContain('the review body');
// A finding that DID carry text is untouched.
expect(
buildLedger(
2,
[{ path: 'a.ts', line: 1, body: '**[Critical]** real claim' }],
[],
).findings[0].title,
).toBe('real claim');
});

it('numbers findings round-scoped, inline first then body Criticals', () => {
const l = buildLedger(
3,
[
{
path: 'src/a.ts',
line: 12,
body: '**[Critical]**: double free\ndetail',
},
{ path: 'src/b.ts', line: 4, body: '**[Suggestion]** untested guard' },
{ path: 'src/c.ts', body: 'no marker — not a finding' },
],
['`src/d.ts` unanchorable blocker'],
);
expect(l.round).toBe(3);
expect(l.findings).toEqual([
{
id: 'R3-1',
sev: 'C',
file: 'src/a.ts',
line: 12,
title: 'double free',
},
{
id: 'R3-2',
sev: 'S',
file: 'src/b.ts',
line: 4,
title: 'untested guard',
},
{
id: 'R3-3',
sev: 'C',
file: '(body)',
title: '`src/d.ts` unanchorable blocker',
},
]);
});

it('classifies through `severityOf`, whitespace and all', () => {
// The ledger restated the severity predicate as a bare `startsWith`, while
// `countInlineFindings` — the count the VERDICT is computed from — trims
// first. A Critical whose body opened with a newline was therefore counted,
// posted, blocked the merge, and was silently missing from the ledger,
// shifting the id of every finding after it.
const drafted = [
{ path: 'src/a.ts', line: 1, body: '\n **[Critical]** leading space' },
{ path: 'src/b.ts', line: 2, body: '**[Suggestion]** plain' },
];
expect(countInlineFindings(drafted)).toEqual({
criticalsInline: 1,
suggestionsInline: 1,
});
expect(buildLedger(1, drafted, []).findings).toEqual([
{
id: 'R1-1',
sev: 'C',
file: 'src/a.ts',
line: 1,
title: 'leading space',
},
{ id: 'R1-2', sev: 'S', file: 'src/b.ts', line: 2, title: 'plain' },
]);
});

it('keeps a carried-forward id instead of renumbering it by position', () => {
// Step 6 re-reports a still-standing finding under its ORIGINAL id, so the
// report says `R1-2 still stands` — and a ledger that renumbered it `R3-1`
// handed the next round a work list keyed by ids the report never used,
// which is the whole thing `R1-2 names the same claim every round` promised.
const l = buildLedger(
3,
[
{ path: 'a.ts', line: 4, body: '**[Critical]** R1-2: still leaking' },
{ path: 'b.ts', body: '**[Suggestion]** brand new this round' },
{ path: 'c.ts', body: '**[Critical]** R2-1 — moved but the same' },
],
['R1-5) the unanchorable one, still open'],
);
expect(l.findings.map((f) => `${f.id}|${f.title}`)).toEqual([
'R1-2|still leaking',
'R3-1|brand new this round',
'R2-1|— moved but the same',
'R1-5|the unanchorable one, still open',
]);
});

it('never issues one id twice, however the comments are worded', () => {
// A duplicated carried id (a copy-paste, or a title that merely opens like
// one) must not collapse two claims onto one ledger entry.
const l = buildLedger(
2,
[
{ path: 'a.ts', body: '**[Critical]** R1-1: one' },
{ path: 'b.ts', body: '**[Critical]** R1-1: two, same id' },
],
[],
);
expect(l.findings.map((f) => f.id)).toEqual(['R1-1', 'R2-1']);
});
});

describe('the ledger marker reaches the POSTED body', () => {
// The feature was inert end to end: the marker was appended in the CLI
// handler, after composeReview() returned, so it reached only the composed
// JSON on disk — and `submit` posts what the PURE function returns. Every
// assertion here goes through composeReview, the path GitHub receives.
let dir: string;
beforeEach(() => {
dir = mkdtempSync(join(tmpdir(), 'ledger-e2e-'));
});
afterEach(() => rmSync(dir, { recursive: true, force: true }));

const plan = (over: Record<string, unknown> = {}) => {
const p = join(dir, 'plan.json');
writeFileSync(p, JSON.stringify({ prNumber: 8255, ...over }));
return p;
};

it('appends the marker to the body composeReview returns', () => {
const r = composeReview({
planPath: plan(),
modelId: 'm',
criticalsInline: 0,
suggestionsInline: 0,
draftedComments: [
{ path: 'src/a.ts', line: 3, body: '**[Suggestion]** untested guard' },
],
});
expect(r.body).toContain('<!-- qwen-review-ledger ');
const ledger = parseLedger(r.body)!;
expect(ledger.round).toBe(1);
expect(ledger.findings).toEqual([
{
id: 'R1-1',
sev: 'S',
file: 'src/a.ts',
line: 3,
title: 'untested guard',
},
]);
});

it('counts the round from the side file pr-context recovered, +1', () => {
writeFileSync(
join(dir, 'qwen-review-pr-8255-prev-ledger.json'),
JSON.stringify({ v: 1, round: 4, findings: [] }),
);
const r = composeReview({
planPath: plan(),
modelId: 'm',
criticalsInline: 0,
suggestionsInline: 0,
draftedComments: [{ path: 'a.ts', body: '**[Critical]** boom' }],
});
expect(parseLedger(r.body)?.round).toBe(5);
});

it('carries NO marker on a local review — there is no PR to hold it', () => {
const r = composeReview({
planPath: plan({ prNumber: undefined }),
modelId: 'm',
criticalsInline: 0,
suggestionsInline: 0,
draftedComments: [{ path: 'a.ts', body: '**[Critical]** boom' }],
});
expect(r.body).not.toContain('qwen-review-ledger');
});
});
Loading
Loading