feat(tools): архив документов ревью выпущенных линий (#682)

Волна 5 эпика #674, инструментальная часть (класс B).
`scripts/reviews-archive.mjs --through=vX.Y.Z` печатает план переноса
документов ревью в `legacy/reviews/<тег>/`, `--apply` делает `git mv` и
пересобирает `docs/reviews/INDEX.md`. Членство — трейлеры `Issue: #NN` в
диапазоне линии, как у манифеста беты (#547) и ревью линии (#638). Правила —
в чистой `archivePlan`: задача уходит в последнюю свою линию; задача с
трейлером после тега остаётся целиком (её раунды ссылаются на прошлые);
закрытая без выпуска уходит с линией, где лёг её документ; документ задачи
без трейлера — с линией, где его добавили; RELEASE-REVIEW — в каталог
своего тега; чужие имена не трогаются. План по v1.77.0: 965 документов
332 задач, 154 остаются в открытой линии.

`legacy/` — класс C в process-gate. Сравнения деревьев с якорем вердикта
(`review-doc-guard.mjs` #499, `task-packet.mjs`) не видят переноса в
`legacy/reviews/`. `process-metrics.mjs` считает раунды по живому каталогу и
архиву. Порог «>900 документов» в тесте индекса снят: в каталоге остаётся
текущая линия. PROCESS.md §2.10 уточнён (правила членства, пустая очередь
S7, ревью линии до переноса), в DEVELOPMENT › Release — шаг чеклиста.
Юнит-тесты и два мутанта (`reviews-archive-moves-open-line-issue`,
`reviews-archive-first-line-wins`).

Issue: #682
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
This commit is contained in:
Claude
2026-09-27 22:10:46 +00:00
committed by claude[bot]
parent c64a1ab7d5
commit d4a672c715
12 changed files with 341 additions and 10 deletions
+16 -1
View File
@@ -3,7 +3,7 @@ import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import {
buildReport, issueMetrics, jobMinutes, pipelineMetrics, renderMarkdown, reviewRounds, runMetrics,
buildReport, issueMetrics, jobMinutes, pipelineMetrics, renderMarkdown, reviewDocNames, reviewRounds, runMetrics,
} from '../scripts/process-metrics.mjs';
const T = (h) => new Date(Date.UTC(2026, 8, 15, 0, Math.round(h * 60))).toISOString();
@@ -140,3 +140,18 @@ test('#637 workflow: еженедельный запуск читает толь
assert.match(wf, /GITHUB_STEP_SUMMARY/);
assert.ok(!/issues: write/.test(wf), 'метрики ничего не пишут в issue');
});
test('#682 reviewDocNames: живой каталог и архив legacy/reviews/<тег>/ считаются вместе', () => {
const listing = [
'docs/reviews/CODE-REVIEW-600-r2.md',
'docs/reviews/INDEX.md',
'legacy/reviews/v1.77.0/CODE-REVIEW-600-r1.md',
'legacy/reviews/v1.77.0/SPEC-REVIEW-601-r1.md',
'legacy/docs/ROADMAP.md',
'',
].join('\n');
const names = reviewDocNames(listing);
assert.deepEqual(names, ['CODE-REVIEW-600-r2.md', 'INDEX.md', 'CODE-REVIEW-600-r1.md', 'SPEC-REVIEW-601-r1.md']);
// Перенос r1 в архив не уменьшает число раундов задачи.
assert.equal(reviewRounds(names).get('CODE:600'), 2);
});