Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9ee83bf
fix(review): gate decided stops on a composed re-rule verdict
wenshao Aug 27, 2026
e8d20fd
Merge branch 'main' into fix/review-stop-composed-verdict-v2
wenshao Aug 27, 2026
601bdae
Merge branch 'main' into fix/review-stop-composed-verdict-v2
wenshao Aug 28, 2026
03a2d2b
Merge branch 'main' into fix/review-stop-composed-verdict-v2
wenshao Aug 28, 2026
d417343
Merge remote-tracking branch 'origin/main' into fix/review-stop-compo…
qwen-code-dev-bot Aug 28, 2026
c124bd2
fix(review): harden the decided-stop re-rule gate on review feedback …
qwen-code-dev-bot Aug 28, 2026
b1d898d
fix(review): fail closed on malformed stop ledgers and bind re-assert…
qwen-code-dev-bot Aug 28, 2026
92044e6
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 29, 2026
667622d
fix(review): bind the stop fence to the capture's own sidecar and gat…
qwen-code-dev-bot Aug 29, 2026
259be0c
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 29, 2026
41db3d6
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 29, 2026
56bac11
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 30, 2026
e0d5d99
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 30, 2026
c1a2eda
Merge branch 'main' into fix/review-stop-composed-verdict-v2
wenshao Aug 30, 2026
873f933
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 31, 2026
4c76363
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 31, 2026
21647f6
Merge branch 'main' into fix/review-stop-composed-verdict-v2
qwen-code-dev-bot Aug 31, 2026
ec2b9e2
fix(review): validate the stop grant against one plan/cache snapshot
wenshao Aug 31, 2026
553cc0f
fix(review): stamp the ledger the stop decision actually read
wenshao Aug 31, 2026
35afdb6
fix(review): fence the composed artifact and scope the sidecar-alone …
wenshao Aug 31, 2026
7b73687
fix(review): key the unchanged stop's nothing-open branch on Criticals
wenshao Aug 31, 2026
1d10e4f
fix(review): give the stop round its own disclosure line and verdict …
wenshao Aug 31, 2026
6004462
fix(review): certify the split, the decision bytes, and the stop opener
wenshao Aug 31, 2026
2865215
fix(review): refuse duplicate ledger ids and the census on a stop re-…
wenshao Sep 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
129 changes: 129 additions & 0 deletions packages/cli/src/commands/review/compose-review.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15515,3 +15515,132 @@ describe('draftedFindingsOf — the drafts as the convergence diagnosis reads th
expect(idOf('**[Critical]** R1-2: (fix-induced) x')).toBe('R1-2');
});
});

describe('composeReview — the decided-stop re-rule', () => {
let cwd0: string;
beforeEach(() => {
cwd0 = process.cwd();
process.chdir(dir);
});
afterEach(() => {
process.chdir(cwd0);
});

function stopPlan(
opts: { stop?: boolean; ledger?: unknown[]; name?: string } = {},
): string {
const cachePath = join(dir, `review-cache-${opts.name ?? 'default'}.json`);
writeFileSync(
cachePath,
JSON.stringify({
findings: opts.ledger ?? [
{ id: 'R1-1', severity: 'Critical', status: 'open' },
{ id: 'R1-2', severity: 'Critical', status: 'fixed' },
{ id: 'R1-3', severity: 'Suggestion', status: 'open' },
],
}),
);
const p = join(dir, `stop-plan-${opts.name ?? 'default'}.json`);
writeFileSync(
p,
JSON.stringify({
chunks: [],
files: [],
diffLines: 0,
srcDiffLines: 0,
skippedFiles: [],
cachePath,
...(opts.stop === false
? {}
: { nothingToReview: { reason: 'unchanged-since-last-round' } }),
}),
);
return p;
}

function reRule(over: Record<string, unknown> = {}) {
return composeReview({
criticalsInline: 0,
suggestionsInline: 0,
planPath: stopPlan(),
env: ENV,
modelId: MODEL,
stopReRule: {
dispositions: [{ id: 'R1-1', ruling: 'still-stands' }],
},
bodyCriticals: ['R1-1: the mechanism still fires — re-read at HEAD'],
...over,
});
}

it('composes REQUEST_CHANGES from a standing re-rule, floors skipped', () => {
const r = reRule();
expect(r.event).toBe('REQUEEST_CHANGES'.replace('EE', 'E'));
expect(r.body).toContain('Decided-stop re-rule');
expect(r.cappedBy).not.toContain('chunk-nobody-read');
});

it('a re-rule that cleared every blocker COMMENTS, never approves', () => {
const r = reRule({
stopReRule: { dispositions: [{ id: 'R1-1', ruling: 'fixed' }] },
bodyCriticals: [],
});
expect(r.event).toBe('COMMENT');
});

it('refuses a full-round plan wearing the flag', () => {
expect(() =>
reRule({ planPath: stopPlan({ stop: false, name: 'full' }) }),
).toThrow(/no nothingToReview decision/);
});

it('refuses when an open ledger Critical has no disposition', () => {
expect(() =>
reRule({
planPath: stopPlan({
name: 'two-open',
ledger: [
{ id: 'R1-1', severity: 'Critical', status: 'open' },
{ id: 'R2-9', severity: 'Critical', status: 'open' },
],
}),
}),
).toThrow(/R2-9 has no disposition/);
});

it('refuses a disposition that matches no open ledger Critical', () => {
expect(() =>
reRule({
stopReRule: {
dispositions: [
{ id: 'R1-1', ruling: 'still-stands' },
{ id: 'R9-9', ruling: 'fixed' },
],
},
}),
).toThrow(/R9-9 matches no open ledger Critical/);
});

it('refuses still-stands without its body Critical, and fixed with one', () => {
expect(() => reRule({ bodyCriticals: [] })).toThrow(
/still-stands but no body Critical/,
);
expect(() =>
reRule({
stopReRule: { dispositions: [{ id: 'R1-1', ruling: 'fixed' }] },
}),
).toThrow(/ruled fixed yet a body Critical/);
});

it('honours the runId fence when a parent published one', () => {
const env = { ...ENV, QWEN_REVIEW_RUN_ID: 'run-X' };
expect(() => reRule({ env })).toThrow(/no stop sidecar/);
mkdirSync(join(dir, '.qwen/tmp'), { recursive: true });
writeFileSync(
join(dir, '.qwen/tmp/qwen-review-local-stop.json'),
JSON.stringify({ reason: 'unchanged-since-last-round', runId: 'run-X' }),
);
const r = reRule({ env });
expect(r.event).toBe('REQUEST_CHANGES');
});
});
Loading
Loading