ci: merge-candidate compares patch-ids without the review documents

The candidate is the branch tip, which already carries the round's
CODE-REVIEW-N-rK.md; the material the reviewer read does not. With
docs/reviews in the diff the two patch-ids never matched once dev had
moved, so every green candidate went back to review whenever another
task published its own document in the meantime — #514 looped twice on
09.09 and #508 only merged when dev happened to stand still. The
patch-id now excludes docs/reviews, exactly like `reviewedFresh` next to
it; a real change of the patch under rebase still returns the task.

Mutant: merge-rereviews-own-review-doc.

Issue: #516
User-Visible: no
This commit is contained in:
Codex
2026-09-09 21:39:17 +00:00
committed by claude[bot]
parent 440460255b
commit 3ad5d0baea
3 changed files with 78 additions and 2 deletions
+4 -1
View File
@@ -110,8 +110,11 @@ export function realOps({ repo, token, workflow = 'validate.yml', sleep = (ms) =
revParse: (ref) => must(git('rev-parse', ref), `rev-parse ${ref}`),
mergeBase: (a, b) => must(git('merge-base', a, b), 'merge-base'),
diffNames: (from, to, pathspec = []) => must(git('diff', '--name-only', from, to, '--', ...pathspec), 'diff').split('\n').filter(Boolean),
// Документы ревью — не часть патча (#516): кандидат несёт свой
// CODE-REVIEW-N-rK.md, материал — нет, и без pathspec их patch-id
// расходились на каждом сдвиге dev; `reviewedFresh` судит так же.
patchId: (from, to) => {
const diff = must(git('diff', '--full-index', from, to), 'diff');
const diff = must(git('diff', '--full-index', from, to, '--', '.', ':!docs/reviews'), 'diff');
const r = spawnSync('git', ['patch-id', '--stable'], { input: diff, encoding: 'utf8' });
return (r.stdout || '').trim().split(' ')[0] || 'empty';
},
+11
View File
@@ -8203,6 +8203,17 @@ const MUTANT_DEFINITIONS = [
replace: " if (false) { // mutant: cancelled counts as red",
}],
},
{
id: 'merge-rereviews-own-review-doc',
guard: 'node --test test/merge-candidate.test.mjs',
because: 'the candidate carries its own review document and the material does not; a patch-id '
+ 'that counts docs/reviews sends every green candidate back to review whenever dev moved (#516)',
patches: [{
file: 'scripts/merge-candidate.mjs',
find: " const diff = must(git('diff', '--full-index', from, to, '--', '.', ':!docs/reviews'), 'diff');",
replace: " const diff = must(git('diff', '--full-index', from, to), 'diff'); // mutant: review docs count",
}],
},
{
id: 'merge-trusts-cancelled-dispatch',
guard: 'node --test test/merge-candidate.test.mjs',