fix(review-scope): void only a pass a later pass replaced, never a fix-check ledger (review pass 1)

A pN ledger never judged and named by no row is voided only when a later pM
pass (M > N) was judged or is named; a fix-check ledger and the last pass keep
counting, so a skipped judge can no longer hide a final pass's blockers or drop
a rowless fix-check. docs/review-policy.md names the REVIEW_SCOPE_VOIDED line.

Review-Finding: p1c/specialist-batched#1 reader=specialist-batched
Review-Finding: p1c/red-team#1 reader=red-team
Review-Finding: p1c/red-team#2 reader=red-team
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-11-03 22:55:19 +00:00
1 parent 91d2131c4c
commit eafdbd92ab
3 files changed
+20 -2

No files matched your search

+15
View File
@@ -68,6 +68,21 @@ describe('review loop counts bind by finding id (GST-1168)', () => {
expect(s.voided).toEqual(['pass p1: its ledger was never judged and no review-log row names it (an abandoned pass), so its 2 collected findings are left out']);
});
test('an unjudged fix-check ledger with no row still counts as a fix-check, never voided', () => {
const rows = [row('review', 20, [], { pass: 1 })];
const passes = [{ ...pass(0, ['p1/red-team#1']), name: 'p1', judged: true }, { ...pass(40, ['fc/fix-check#1'], true), name: 'fc', judged: false }];
const s = summarizeReviewLoop(rows, SINCE, [[], []], passes);
expect(s.voided).toBeUndefined();
expect(s.fix_checks).toBe(1);
});
test('the last pass is never voided: an unjudged pass no later pass replaced keeps its blockers', () => {
const ledgers = [[blocker('p1', 'red-team#1', 'src/a.ts:10')]];
const s = summarizeReviewLoop([], SINCE, ledgers, [{ ...pass(0, ['p1/red-team#1']), name: 'p1', judged: false }]);
expect(s.voided).toBeUndefined();
expect(s.blocking_found).toBe(1);
});
test('a judged pass with no row is still named unbound, never voided', () => {
const rows = [row('review', 30, [], { pass: 2 })];
const s = summarizeReviewLoop(rows, SINCE, [[blocker('p1', 'red-team#1', 'src/a.ts:10')], []], [{ ...pass(0, ['p1/red-team#1']), name: 'p1', judged: true }, { ...pass(20, []), name: 'p2', judged: true }]);