From 0991c45374adc3e9ba79a4d0f3cb08869f2310a9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 28 Sep 2026 00:32:22 +0300 Subject: [PATCH] =?UTF-8?q?fix(tools):=20=D0=B0=D1=80=D1=85=D0=B8=D0=B2=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=20=D0=BE=D1=82=D0=BD=D0=BE=D1=81=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=B5=D1=81=D1=91=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20(#682)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ревью #682 r1, Medium: перенос добавляет документу уровень вложенности (`docs/reviews/X.md` → `legacy/reviews/<тег>/X.md`, `docs/specs/` → `legacy/specs/`), а относительные ссылки внутри перенесённых документов и в соседях, ссылавшихся на них, никто не пересчитывал — на `97d19268` 53 битые ссылки в 46 файлах (заявление «все 26 резолвятся» в `7feb6177` было верно только до переноса документов ревью). Гейты архив не смотрят. `reviews-archive.mjs`: `repairLinks` пересчитывает ссылку, если она не резолвится от нового места, а цель находится от нового или старого места через карту переносов; битая и до переноса ссылка не трогается. `--apply` делает это само, `--repair-links=` — для всех переименований `..HEAD`, `--check-links` печатает битые. Этим коммитом `--repair-links=origin/dev` переписал ровно 53 ссылки в 46 файлах; остались две прежние «...»-заглушки в CODE-REVIEW-448-r2 (битые и на dev). Тесты: перенесённый документ, сосед со ссылкой в архив, ТЗ со ссылкой на позже перенесённое ревью, битая-до-переноса не трогается, в `legacy/` битых нет; мутант `reviews-archive-links-from-new-place-only`. PROCESS §2.10 и DEVELOPMENT › Release называют переписывание и `--check-links`. Issue: #682 User-Visible: no Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd --- PROCESS.md | 3 + docs/DEVELOPMENT.md | 5 +- docs/reviews/CODE-REVIEW-635-r1.md | 2 +- legacy/reviews/v1.63.0/CODE-REVIEW-89-r2.md | 2 +- legacy/reviews/v1.63.0/CODE-REVIEW-89-r3.md | 2 +- legacy/reviews/v1.63.0/SPEC-REVIEW-89-r1.md | 2 +- legacy/reviews/v1.64.0/CODE-REVIEW-107-r1.md | 2 +- legacy/reviews/v1.64.0/CODE-REVIEW-141-r1.md | 2 +- legacy/reviews/v1.64.0/CODE-REVIEW-146-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-150-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-198-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-198-r2.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-198-r3.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-200-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-201-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-203-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-204-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-205-r1.md | 2 +- legacy/reviews/v1.65.0/CODE-REVIEW-205-r2.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-174-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-178-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-178-r2.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-198-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-200-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-201-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-203-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-203-r2.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-204-r1.md | 2 +- legacy/reviews/v1.65.0/SPEC-REVIEW-205-r1.md | 2 +- legacy/reviews/v1.66.0/CODE-REVIEW-218-r1.md | 2 +- legacy/reviews/v1.68.0/CODE-REVIEW-226-r1.md | 2 +- legacy/reviews/v1.68.0/CODE-REVIEW-316-r1.md | 2 +- legacy/reviews/v1.68.0/SPEC-REVIEW-223-r1.md | 2 +- legacy/reviews/v1.68.0/SPEC-REVIEW-223-r2.md | 2 +- legacy/reviews/v1.68.0/SPEC-REVIEW-223-r3.md | 2 +- legacy/reviews/v1.68.0/SPEC-REVIEW-282-r1.md | 4 +- legacy/reviews/v1.68.0/SPEC-REVIEW-282-r2.md | 2 +- legacy/reviews/v1.69.0/CODE-REVIEW-359-r2.md | 4 +- legacy/reviews/v1.72.0/CODE-REVIEW-54-r1.md | 2 +- legacy/reviews/v1.72.0/CODE-REVIEW-54-r2.md | 2 +- legacy/reviews/v1.73.0/CODE-REVIEW-437-r1.md | 2 +- legacy/reviews/v1.73.0/SPEC-REVIEW-495-r1.md | 2 +- legacy/reviews/v1.77.0/SPEC-REVIEW-588-r2.md | 4 +- legacy/reviews/v1.77.0/SPEC-REVIEW-588-r3.md | 4 +- legacy/reviews/v1.77.0/SPEC-REVIEW-593-r1.md | 2 +- legacy/reviews/v1.77.0/SPEC-REVIEW-593-r2.md | 2 +- legacy/reviews/v1.77.0/SPEC-REVIEW-593-r3.md | 6 +- ...-readd-child-entity-after-device-delete.md | 2 +- scripts/mutation-registry.mjs | 11 ++ scripts/reviews-archive.mjs | 125 +++++++++++++++++- test/reviews-archive.test.mjs | 54 +++++++- 51 files changed, 242 insertions(+), 60 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index 21530b69..06de29ef 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -408,6 +408,9 @@ dev, ни при публикации документа код-ревью: ин в последнюю; закрытая без выпуска (как #522) уезжает с линией, где лёг её документ — коммит документа несёт трейлер; `RELEASE-REVIEW-vX.Y.Z.md` уходит в каталог своего тега, поэтому перенос делается после публикации ревью линии. +Относительные ссылки в перенесённых документах и в соседях, которые на них +ссылаются, инструмент переписывает сам; `--check-links` печатает оставшиеся +битые. Перенос идёт при пустой очереди `S7-code-review`: ребейз чужой ветки иначе упрётся в перемещённый каталог. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 4e156945..5c2e2f15 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -648,8 +648,9 @@ and what HACS downloads. (`RELEASE-REVIEW-vX.Y.Z.md`) is in `dev` and the `S7-code-review` queue is empty, archive the line's review documents (`PROCESS.md` §2.10): `node scripts/reviews-archive.mjs --through=vX.Y.Z` prints the plan, -`--apply` moves the files into `legacy/reviews/vX.Y.Z/` with `git mv` and -rebuilds `docs/reviews/INDEX.md`; commit the result as one class C commit +`--apply` moves the files into `legacy/reviews/vX.Y.Z/` with `git mv`, rewrites +the relative Markdown links in and to the moved documents and rebuilds +`docs/reviews/INDEX.md` (`--check-links` lists what is still broken); commit the result as one class C commit whose `Issue:` trailer names the issue doing the move or the repository-hygiene umbrella (`PROCESS.md` §11.3). diff --git a/docs/reviews/CODE-REVIEW-635-r1.md b/docs/reviews/CODE-REVIEW-635-r1.md index 96f204d6..e7489572 100644 --- a/docs/reviews/CODE-REVIEW-635-r1.md +++ b/docs/reviews/CODE-REVIEW-635-r1.md @@ -101,7 +101,7 @@ H=0, M=0, «Находки: —» — как будто находок не бы строку 14, а не 106. Индекс: ``` -| #594 | [CODE-REVIEW-594-r1.md](CODE-REVIEW-594-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — | +| #594 | [CODE-REVIEW-594-r1.md](../../legacy/reviews/v1.77.0/CODE-REVIEW-594-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — | ``` Реально в этом документе 3 Medium (M1 приёмка эталонов, M2 отпечаток diff --git a/legacy/reviews/v1.63.0/CODE-REVIEW-89-r2.md b/legacy/reviews/v1.63.0/CODE-REVIEW-89-r2.md index a150dcc4..4c3e4388 100644 --- a/legacy/reviews/v1.63.0/CODE-REVIEW-89-r2.md +++ b/legacy/reviews/v1.63.0/CODE-REVIEW-89-r2.md @@ -4,7 +4,7 @@ - Этап: `code` (PROCESS.md §2.7) - Диапазон: `origin/dev...HEAD`, `origin/dev` = `22e98c5`, `HEAD` = `6ea3ebf` (ветка `issue/89-isometric-stage1`, детач `HEAD`) -- ТЗ: [`docs/specs/089-isometric-view-stage1.md`](../specs/089-isometric-view-stage1.md), +- ТЗ: [`docs/specs/089-isometric-view-stage1.md`](../../../docs/specs/089-isometric-view-stage1.md), ревизия 3, ревью ТЗ зелёное — [`SPEC-REVIEW-89-r1.md`](SPEC-REVIEW-89-r1.md) - Цикл: **r2/4** - Вердикт: **красный** diff --git a/legacy/reviews/v1.63.0/CODE-REVIEW-89-r3.md b/legacy/reviews/v1.63.0/CODE-REVIEW-89-r3.md index a206dba4..2c5ebfcf 100644 --- a/legacy/reviews/v1.63.0/CODE-REVIEW-89-r3.md +++ b/legacy/reviews/v1.63.0/CODE-REVIEW-89-r3.md @@ -5,7 +5,7 @@ - Диапазон: `origin/dev...HEAD`, `origin/dev` = `869fe16`, `HEAD` = `7a2577d` (ветка `issue/89-isometric-stage1`, детач `HEAD`); мёрж-база с `origin/dev` — `9f02d88` -- ТЗ: [`docs/specs/089-isometric-view-stage1.md`](../specs/089-isometric-view-stage1.md), +- ТЗ: [`docs/specs/089-isometric-view-stage1.md`](../../../docs/specs/089-isometric-view-stage1.md), ревизия 3, ревью ТЗ зелёное — [`SPEC-REVIEW-89-r1.md`](SPEC-REVIEW-89-r1.md) - Предыдущий цикл код-ревью: [`CODE-REVIEW-89-r2.md`](CODE-REVIEW-89-r2.md) (красный, High H1 — обязательный смок красный на исполнении) diff --git a/legacy/reviews/v1.63.0/SPEC-REVIEW-89-r1.md b/legacy/reviews/v1.63.0/SPEC-REVIEW-89-r1.md index ba3bc823..c5ab3ed4 100644 --- a/legacy/reviews/v1.63.0/SPEC-REVIEW-89-r1.md +++ b/legacy/reviews/v1.63.0/SPEC-REVIEW-89-r1.md @@ -2,7 +2,7 @@ - Issue: [#89](https://github.com/Matysh/houseplan-card/issues/89) - Этап: `spec` (PROCESS.md §2.4) -- ТЗ под ревью: [`docs/specs/089-isometric-view-stage1.md`](../specs/089-isometric-view-stage1.md), ревизия 3 +- ТЗ под ревью: [`docs/specs/089-isometric-view-stage1.md`](../../../docs/specs/089-isometric-view-stage1.md), ревизия 3 - Диапазон: `origin/dev...74b08df` (ветка `issue/89-isometric-stage1`, детач `HEAD`) - Цикл: **r1/4** (первый независимый ревью-артефакт этой задачи в `docs/reviews/`; «историческое ревью ревизии 1», упомянутое в теле issue и в самом ТЗ, честно diff --git a/legacy/reviews/v1.64.0/CODE-REVIEW-107-r1.md b/legacy/reviews/v1.64.0/CODE-REVIEW-107-r1.md index a637eec8..1c96d138 100644 --- a/legacy/reviews/v1.64.0/CODE-REVIEW-107-r1.md +++ b/legacy/reviews/v1.64.0/CODE-REVIEW-107-r1.md @@ -1,7 +1,7 @@ # Код-ревью issue #107 — переключение виртуального источника света «Всегда» (r1) - **Issue:** https://github.com/Matysh/houseplan-card/issues/107 -- **ТЗ:** [`docs/specs/107-virtual-light-toggle.md`](../specs/107-virtual-light-toggle.md), ревью +- **ТЗ:** [`docs/specs/107-virtual-light-toggle.md`](../../specs/107-virtual-light-toggle.md), ревью [`SPEC-REVIEW-107-r1.md`](SPEC-REVIEW-107-r1.md) — зелёное, High 0 / Medium 0. - **Диапазон:** `origin/dev...HEAD`, коммит `1079cdfab25617df924b8c3592631aa40e078d87` ("feat: add persistent virtual light toggles"), ветка `issue/107-virtual-light-toggle`. diff --git a/legacy/reviews/v1.64.0/CODE-REVIEW-141-r1.md b/legacy/reviews/v1.64.0/CODE-REVIEW-141-r1.md index b31ccbc0..5aa987ea 100644 --- a/legacy/reviews/v1.64.0/CODE-REVIEW-141-r1.md +++ b/legacy/reviews/v1.64.0/CODE-REVIEW-141-r1.md @@ -4,7 +4,7 @@ Ветка: `issue/141-wall-joints` · implementation-коммит [`3e33f4a`](https://github.com/Matysh/houseplan-card/commit/3e33f4a5845a29694473697bea916bb3e2490ac2) -· ТЗ: [`docs/specs/141-wall-junctions.md`](../specs/141-wall-junctions.md) +· ТЗ: [`docs/specs/141-wall-junctions.md`](../../../docs/specs/141-wall-junctions.md) (reviewed `2858175`, зелёный SPEC-REVIEW-141-r1). ## Скоуп проверки diff --git a/legacy/reviews/v1.64.0/CODE-REVIEW-146-r1.md b/legacy/reviews/v1.64.0/CODE-REVIEW-146-r1.md index 5d115f35..34fabb0a 100644 --- a/legacy/reviews/v1.64.0/CODE-REVIEW-146-r1.md +++ b/legacy/reviews/v1.64.0/CODE-REVIEW-146-r1.md @@ -4,7 +4,7 @@ Ветка: `issue/146-four-phase-sun-background` · implementation-коммит [`debb13b`](https://github.com/Matysh/houseplan-card/commit/debb13baa280042c79a004c97152e3b1be5ab11b) -· ТЗ: [`docs/specs/146-four-phase-sun-background.md`](../specs/146-four-phase-sun-background.md) +· ТЗ: [`docs/specs/146-four-phase-sun-background.md`](../../../docs/specs/146-four-phase-sun-background.md) (зелёный [`SPEC-REVIEW-146-r1`](SPEC-REVIEW-146-r1.md), High:0, Medium:1 → #147, не блокирует). diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-150-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-150-r1.md index e34b8b52..447bcaeb 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-150-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-150-r1.md @@ -5,7 +5,7 @@ Ветка: `issue/150-wall-thickness-transition-fix` · implementation-коммит [`1975d1a`](https://github.com/Matysh/houseplan-card/commit/1975d1ae3784a0b98cf2f489910370f37417a1c6) на базе `origin/dev` (`a05aa5d`) · ТЗ: -[`docs/specs/150-wall-thickness-transition.md`](../specs/150-wall-thickness-transition.md) +[`docs/specs/150-wall-thickness-transition.md`](../../specs/150-wall-thickness-transition.md) (r2, зелёный `SPEC-REVIEW-150-r2`, High: 0 · Medium: 1 → #171, комментарий issue от 2026-08-18T08:40:34Z). diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-198-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-198-r1.md index ab899a49..6051d317 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-198-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-198-r1.md @@ -5,7 +5,7 @@ - Диапазон: `git log --oneline origin/dev..HEAD` = `0df8051` (реализация), `8c9241b` (ревью ТЗ r1), `9d6cd8b` (ТЗ) - Диапазон диффа: `git diff origin/dev...HEAD` -- ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../specs/198-optimize-micro-interval.md) +- ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../../specs/198-optimize-micro-interval.md) (ревью ТЗ зелёное, r1) ## Скоуп diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-198-r2.md b/legacy/reviews/v1.65.0/CODE-REVIEW-198-r2.md index 4e518565..7bdb58d3 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-198-r2.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-198-r2.md @@ -7,7 +7,7 @@ `1c9575a` (follow-up тесты на замечания r1), `0625b6f` (обновление provenance скриншотов после изменения `src/`) - Диапазон диффа: `git diff origin/dev...HEAD` -- ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../specs/198-optimize-micro-interval.md) +- ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../../specs/198-optimize-micro-interval.md) (ревью ТЗ зелёное, r1) - Предыдущий цикл: [`docs/reviews/CODE-REVIEW-198-r1.md`](CODE-REVIEW-198-r1.md) (жёлтый · Medium-1 AC5, Medium-2 AC8 — обе «доказательство обещанным diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-198-r3.md b/legacy/reviews/v1.65.0/CODE-REVIEW-198-r3.md index ad83358a..7651ced8 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-198-r3.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-198-r3.md @@ -9,7 +9,7 @@ r2), `5ce3cee` (исправление находки r2 — изоляция AC5-фикстуры), `2d5fec0` (обновление screenshot provenance после технического ребейза) - Диапазон диффа: `git diff origin/dev...HEAD` -- ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../specs/198-optimize-micro-interval.md) +- ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../../specs/198-optimize-micro-interval.md) (ревью ТЗ зелёное, r1) - Предыдущий цикл: [`docs/reviews/CODE-REVIEW-198-r2.md`](CODE-REVIEW-198-r2.md) (жёлтый · Medium-1 — новый AC5-тест не хермитичен к сценарию входной diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-200-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-200-r1.md index b1c90529..63ded74a 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-200-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-200-r1.md @@ -1,7 +1,7 @@ # Код-ревью issue #200 — r1 - Issue: [#200](https://github.com/Matysh/houseplan-card/issues/200) -- ТЗ: [docs/specs/200-room-label-parity.md](../specs/200-room-label-parity.md) +- ТЗ: [docs/specs/200-room-label-parity.md](../../specs/200-room-label-parity.md) - ТЗ-ревью: [SPEC-REVIEW-200-r1.md](SPEC-REVIEW-200-r1.md) — зелёный - Диапазон: `origin/dev..HEAD` (детач на `origin/issue/200-room-label-parity`), коммиты `4089c91`, `bf83246`, `cd029a0`, `88a2877` diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-201-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-201-r1.md index ea4cca34..51ee41bf 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-201-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-201-r1.md @@ -1,7 +1,7 @@ # Код-ревью #201 — r1 - Issue: [#201](https://github.com/Matysh/houseplan-card/issues/201) -- ТЗ: [docs/specs/201-atomic-thickness-lookup.md](../specs/201-atomic-thickness-lookup.md) +- ТЗ: [docs/specs/201-atomic-thickness-lookup.md](../../specs/201-atomic-thickness-lookup.md) (ревью ТЗ зелёное: [SPEC-REVIEW-201-r1.md](SPEC-REVIEW-201-r1.md)) - Диапазон: `git log --oneline origin/dev..HEAD` - `f7abf14` fix: inherit parent thickness for atomic walls (`Issue: #201`, `User-Visible: yes`) diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-203-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-203-r1.md index 166bbe0d..97badbe6 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-203-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-203-r1.md @@ -5,7 +5,7 @@ `1290927 fix: hide disabled room names` (`Issue: #203`, `User-Visible: yes`), плюс два уже смёрженных документа ревью ТЗ (`84e62dc`, `950403d`, `f7b811a`, `009fed9`) — без продуктового кода. -- ТЗ: [`docs/specs/203-hide-room-names.md`](../specs/203-hide-room-names.md), +- ТЗ: [`docs/specs/203-hide-room-names.md`](../../specs/203-hide-room-names.md), ревью ТЗ зелёное на r2: [`SPEC-REVIEW-203-r2.md`](SPEC-REVIEW-203-r2.md). - Issue: [#203](https://github.com/Matysh/houseplan-card/issues/203) - Ревьюер: Claude (роль «ревьюер кода»), свежая сессия без контекста реализации. diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-204-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-204-r1.md index 389dd53d..2050106d 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-204-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-204-r1.md @@ -1,7 +1,7 @@ # CODE-REVIEW-204-r1 - Issue: [#204](https://github.com/Matysh/houseplan-card/issues/204) -- ТЗ: [docs/specs/204-space-create-display-defaults.md](../specs/204-space-create-display-defaults.md) +- ТЗ: [docs/specs/204-space-create-display-defaults.md](../../specs/204-space-create-display-defaults.md) - Ветка: `issue/204-space-create-display-defaults`, коммит `12c4f77` - Диапазон: `origin/dev..HEAD` = `f703242` (spec) → `ec0ccaf` (spec review doc) → `12c4f77` (реализация) - Вердикт: **зелёный** diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-205-r1.md b/legacy/reviews/v1.65.0/CODE-REVIEW-205-r1.md index 52294abf..aa7cdc0a 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-205-r1.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-205-r1.md @@ -4,7 +4,7 @@ - Этап: `code` (PROCESS.md §2.7) - Диапазон: `origin/dev...HEAD`, `origin/dev` = `ad8e7a5`, `HEAD` = `11b0283` (ветка `issue/205-vacuum-trail-grace`, detached `HEAD`); merge-base — `f287bdd` -- ТЗ: [`docs/specs/205-vacuum-trail-resume-grace.md`](../specs/205-vacuum-trail-resume-grace.md), +- ТЗ: [`docs/specs/205-vacuum-trail-resume-grace.md`](../../specs/205-vacuum-trail-resume-grace.md), ревью ТЗ зелёное — [`SPEC-REVIEW-205-r1.md`](SPEC-REVIEW-205-r1.md) - Цикл: **r1/4** - Ревьюер: Claude, свежая сессия, без переписки с автором реализации diff --git a/legacy/reviews/v1.65.0/CODE-REVIEW-205-r2.md b/legacy/reviews/v1.65.0/CODE-REVIEW-205-r2.md index 9339eaf9..5b305602 100644 --- a/legacy/reviews/v1.65.0/CODE-REVIEW-205-r2.md +++ b/legacy/reviews/v1.65.0/CODE-REVIEW-205-r2.md @@ -5,7 +5,7 @@ - Диапазон: `origin/dev...HEAD`, `origin/dev` = `5dc9016` («docs: review document for #204»), `HEAD` = `e158f8f` (ветка `issue/205-vacuum-trail-grace`, detached `HEAD`); merge-base — `5dc9016` -- ТЗ: [`docs/specs/205-vacuum-trail-resume-grace.md`](../specs/205-vacuum-trail-resume-grace.md), +- ТЗ: [`docs/specs/205-vacuum-trail-resume-grace.md`](../../specs/205-vacuum-trail-resume-grace.md), ревью ТЗ зелёное — [`SPEC-REVIEW-205-r1.md`](SPEC-REVIEW-205-r1.md) - Предыдущий цикл: [`CODE-REVIEW-205-r1.md`](CODE-REVIEW-205-r1.md) — **зелёный**, High: 0, Medium: 0; вернулся не по замечаниям, а из-за конфликта diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-174-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-174-r1.md index 4d5ea9e1..e500dc81 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-174-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-174-r1.md @@ -1,7 +1,7 @@ # SPEC-REVIEW-174-r1 - **Issue:** https://github.com/Matysh/houseplan-card/issues/174 -- **ТЗ:** [`docs/specs/174-linked-virtual-light-controller.md`](../specs/174-linked-virtual-light-controller.md) +- **ТЗ:** [`docs/specs/174-linked-virtual-light-controller.md`](../../specs/174-linked-virtual-light-controller.md) (commit `4a8958291d28fbd86d0233e6ac9208b068b24f76`, ветка `issue/174-linked-virtual-light`) - **Ревьюер:** Claude (ревью ТЗ ≠ автор), этап `S4-spec-review` - **Цикл:** r1/4 (обычный трек — issue не `small`/`trivial`, что подтверждено diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r1.md index f0b37caa..24078e9f 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r1.md @@ -1,7 +1,7 @@ # SPEC-REVIEW-178-r1 - **Issue:** https://github.com/Matysh/houseplan-card/issues/178 -- **ТЗ:** [`docs/specs/178-toggle-entity.md`](../specs/178-toggle-entity.md) +- **ТЗ:** [`docs/specs/178-toggle-entity.md`](../../specs/178-toggle-entity.md) (commit `e46ef6f55c44ec1f05268cdff4ceeb4dcc5af116`, ветка `issue/178-toggle-entity`) - **Ревьюер:** Claude (ревью ТЗ ≠ автор), этап `S4-spec-review` - **Цикл:** r1/4 (обычный трек — issue не `small`/`trivial`, подтверждено diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r2.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r2.md index 11599229..b87d6e42 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r2.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-178-r2.md @@ -1,7 +1,7 @@ # SPEC-REVIEW-178-r2 - **Issue:** https://github.com/Matysh/houseplan-card/issues/178 -- **ТЗ:** [`docs/specs/178-toggle-entity.md`](../specs/178-toggle-entity.md) +- **ТЗ:** [`docs/specs/178-toggle-entity.md`](../../specs/178-toggle-entity.md) (commit `76f75f85aafabcf9f698c85de0185e2ee64a98b5`, ветка `issue/178-toggle-entity`) - **Ревьюер:** Claude (ревью ТЗ ≠ автор), этап `S4-spec-review`, сессия без контекста написания ТЗ и без контекста r1 diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-198-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-198-r1.md index 7fec6eed..6e26aa50 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-198-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-198-r1.md @@ -1,7 +1,7 @@ # Ревью ТЗ — issue #198, цикл r1 - Этап: `S4-spec-review` (PROCESS.md §2.4) -- Артефакт ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../specs/198-optimize-micro-interval.md), +- Артефакт ТЗ: [`docs/specs/198-optimize-micro-interval.md`](../../specs/198-optimize-micro-interval.md), коммит `9d6cd8b` на ветке `issue/198-optimize-micro-interval` - Issue: [#198](https://github.com/Matysh/houseplan-card/issues/198) - Ревьюер: Claude (роль «ревьюер ТЗ», отдельная сессия от аналитика/автора) diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-200-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-200-r1.md index db161966..a0e71e87 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-200-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-200-r1.md @@ -1,7 +1,7 @@ # Ревью ТЗ — issue #200, цикл r1 - Этап: `S4-spec-review` (PROCESS.md §2.4) -- Артефакт ТЗ: [`docs/specs/200-room-label-parity.md`](../specs/200-room-label-parity.md), +- Артефакт ТЗ: [`docs/specs/200-room-label-parity.md`](../../specs/200-room-label-parity.md), коммит `4089c91` на ветке `issue/200-room-label-parity` - Issue: [#200](https://github.com/Matysh/houseplan-card/issues/200) - Ревьюер: Claude (роль «ревьюер ТЗ», отдельная сессия от аналитика/автора) diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-201-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-201-r1.md index 6c15faba..721b967b 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-201-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-201-r1.md @@ -1,7 +1,7 @@ # Ревью ТЗ — issue #201, цикл r1 - Этап: `S4-spec-review` (PROCESS.md §2.4) -- Артефакт ТЗ: [`docs/specs/201-atomic-thickness-lookup.md`](../specs/201-atomic-thickness-lookup.md), +- Артефакт ТЗ: [`docs/specs/201-atomic-thickness-lookup.md`](../../specs/201-atomic-thickness-lookup.md), коммит `7b759f3` на ветке `issue/201-atomic-thickness-lookup` - Issue: [#201](https://github.com/Matysh/houseplan-card/issues/201) - Ревьюер: Claude (роль «ревьюер ТЗ», отдельная сессия от аналитика/автора) diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r1.md index d3ed8f6c..39b39396 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r1.md @@ -1,7 +1,7 @@ # Ревью ТЗ — issue #203, цикл r1 - Этап: `S4-spec-review` (PROCESS.md §2.4) -- Артефакт ТЗ: [`docs/specs/203-hide-room-names.md`](../specs/203-hide-room-names.md), +- Артефакт ТЗ: [`docs/specs/203-hide-room-names.md`](../../specs/203-hide-room-names.md), коммит `009fed9` на ветке `issue/203-hide-room-names` - Issue: [#203](https://github.com/Matysh/houseplan-card/issues/203) - Ревьюер: Claude (роль «ревьюер ТЗ», отдельная сессия от аналитика/автора) diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r2.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r2.md index 19a685b7..b6494809 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r2.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-203-r2.md @@ -1,7 +1,7 @@ # Ревью ТЗ — issue #203, цикл r2 - Этап: `S4-spec-review` (PROCESS.md §2.4) -- Артефакт ТЗ: [`docs/specs/203-hide-room-names.md`](../specs/203-hide-room-names.md), +- Артефакт ТЗ: [`docs/specs/203-hide-room-names.md`](../../specs/203-hide-room-names.md), правка коммитом `f7b811a` поверх `009fed9` на ветке `issue/203-hide-room-names` - Issue: [#203](https://github.com/Matysh/houseplan-card/issues/203) - Ревьюер: Claude (роль «ревьюер ТЗ») diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-204-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-204-r1.md index 21dc9ed3..7ce700ad 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-204-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-204-r1.md @@ -1,7 +1,7 @@ # SPEC-REVIEW-204-r1 - Issue: [#204](https://github.com/Matysh/houseplan-card/issues/204) -- ТЗ: [docs/specs/204-space-create-display-defaults.md](../specs/204-space-create-display-defaults.md) +- ТЗ: [docs/specs/204-space-create-display-defaults.md](../../specs/204-space-create-display-defaults.md) - Ветка: `issue/204-space-create-display-defaults`, коммит `f703242` - Трек: обычный (метка `small` не выставлена — файл ТЗ обязателен и присутствует) - Вердикт: **зелёный** diff --git a/legacy/reviews/v1.65.0/SPEC-REVIEW-205-r1.md b/legacy/reviews/v1.65.0/SPEC-REVIEW-205-r1.md index a48e246d..393fb4ea 100644 --- a/legacy/reviews/v1.65.0/SPEC-REVIEW-205-r1.md +++ b/legacy/reviews/v1.65.0/SPEC-REVIEW-205-r1.md @@ -1,7 +1,7 @@ # SPEC-REVIEW-205-r1 - Issue: [#205](https://github.com/Matysh/houseplan-card/issues/205) — след пылесоса обнуляется после мойки швабр -- ТЗ: [docs/specs/205-vacuum-trail-resume-grace.md](../specs/205-vacuum-trail-resume-grace.md) +- ТЗ: [docs/specs/205-vacuum-trail-resume-grace.md](../../specs/205-vacuum-trail-resume-grace.md) - Ветка: `issue/205-vacuum-trail-grace`, коммит спеки: `f3472de` ("docs: specify vacuum trail resume grace") - Этап: ТЗ на ревью (PROCESS.md §2.4) - Цикл: r1/4 (лёгкий трек не применяется — `small` не выставлен, сложность 4, риск 7) diff --git a/legacy/reviews/v1.66.0/CODE-REVIEW-218-r1.md b/legacy/reviews/v1.66.0/CODE-REVIEW-218-r1.md index d3726d78..850e8c4a 100644 --- a/legacy/reviews/v1.66.0/CODE-REVIEW-218-r1.md +++ b/legacy/reviews/v1.66.0/CODE-REVIEW-218-r1.md @@ -1,7 +1,7 @@ # CODE-REVIEW-218-r1 - **Issue:** [#218](https://github.com/Matysh/houseplan-card/issues/218) — floating-point шум одной комнаты гасит Glow всего пространства -- **ТЗ:** [docs/specs/218-glow-floor-geometry.md](../specs/218-glow-floor-geometry.md), принято на [SPEC-REVIEW-218-r2](SPEC-REVIEW-218-r2.md) (зелёный, r2/2) +- **ТЗ:** [docs/specs/218-glow-floor-geometry.md](../../specs/218-glow-floor-geometry.md), принято на [SPEC-REVIEW-218-r2](SPEC-REVIEW-218-r2.md) (зелёный, r2/2) - **Диапазон:** `origin/dev...HEAD`, продуктовый коммит `3d11758` (единственный коммит с изменением кода; `c6ff34c`…`4c512fa` — ТЗ и его ревью) - **Ветка:** `issue/218-glow-floor-geometry` - **Цикл:** r1/4 diff --git a/legacy/reviews/v1.68.0/CODE-REVIEW-226-r1.md b/legacy/reviews/v1.68.0/CODE-REVIEW-226-r1.md index 5b7c5ad1..b2eb7ccc 100644 --- a/legacy/reviews/v1.68.0/CODE-REVIEW-226-r1.md +++ b/legacy/reviews/v1.68.0/CODE-REVIEW-226-r1.md @@ -1,7 +1,7 @@ # Код-ревью #226 — r1 - Issue: [#226](https://github.com/Matysh/houseplan-card/issues/226) -- ТЗ: [`docs/specs/226-entity-parent-dedup.md`](../specs/226-entity-parent-dedup.md) +- ТЗ: [`docs/specs/226-entity-parent-dedup.md`](../../specs/226-entity-parent-dedup.md) (зелёное ревью r2: [`SPEC-REVIEW-226-r2.md`](SPEC-REVIEW-226-r2.md)) - Ветка: `issue/226-entity-parent-dedup`, коммит реализации `f151e70` - Материал: `git diff origin/dev...HEAD`, `git log --oneline origin/dev..HEAD` diff --git a/legacy/reviews/v1.68.0/CODE-REVIEW-316-r1.md b/legacy/reviews/v1.68.0/CODE-REVIEW-316-r1.md index c92cbba5..4849470d 100644 --- a/legacy/reviews/v1.68.0/CODE-REVIEW-316-r1.md +++ b/legacy/reviews/v1.68.0/CODE-REVIEW-316-r1.md @@ -6,7 +6,7 @@ `HEAD` = `ee672dcd` (ветка `issue/316-migration-auto-resolve`, ребейз на `dev` выполнен автором до этого ревью — коммент issue от 2026-08-26T19:12:24Z, конфликт был только в `CHANGELOG`) -- ТЗ: [`docs/specs/316-opening-host-auto-resolution.md`](../specs/316-opening-host-auto-resolution.md), +- ТЗ: [`docs/specs/316-opening-host-auto-resolution.md`](../../specs/316-opening-host-auto-resolution.md), ревизия 4, ревью ТЗ зелёное — [`SPEC-REVIEW-316-r4.md`](SPEC-REVIEW-316-r4.md) - Заход ревью: **r1**, блокирующих циклов код-ревью израсходовано **0/4** - Вердикт: **красный** diff --git a/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r1.md b/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r1.md index 80212a6c..ffbc9a4f 100644 --- a/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r1.md +++ b/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r1.md @@ -2,7 +2,7 @@ - Issue: [#223](https://github.com/Matysh/houseplan-card/issues/223) «Оптимизировать планы» должна канонизировать координаты, а не консервировать floating-point шум -- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../specs/223-optimize-coordinate-canonicalization.md) +- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../../specs/223-optimize-coordinate-canonicalization.md) на коммите `3a81dd6223095465f5563cf9cd76cd3ca5355bdb` - Трек: обычный (не `small`) — оценка владельца в аналитике: сложность/риск 4/10, одна общая функция координат + изменения в `AlignReport`/`OptimizeReport` + пользовательский текст + несколько diff --git a/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r2.md b/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r2.md index 8528487c..3587d80f 100644 --- a/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r2.md +++ b/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r2.md @@ -2,7 +2,7 @@ - Issue: [#223](https://github.com/Matysh/houseplan-card/issues/223) «Оптимизировать планы» должна канонизировать координаты, а не консервировать floating-point шум -- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../specs/223-optimize-coordinate-canonicalization.md) +- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../../specs/223-optimize-coordinate-canonicalization.md) на коммите `965711ee2005b8ec2587b9c70fb9b14735c7756e` (HEAD) - Раунд: r2/4 - Вердикт: **жёлтый** diff --git a/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r3.md b/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r3.md index ef8bc1a8..e3146cfb 100644 --- a/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r3.md +++ b/legacy/reviews/v1.68.0/SPEC-REVIEW-223-r3.md @@ -2,7 +2,7 @@ - Issue: [#223](https://github.com/Matysh/houseplan-card/issues/223) «Оптимизировать планы» должна канонизировать координаты, а не консервировать floating-point шум -- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../specs/223-optimize-coordinate-canonicalization.md) +- ТЗ: [`docs/specs/223-optimize-coordinate-canonicalization.md`](../../specs/223-optimize-coordinate-canonicalization.md) на коммите `8c9e5feae3503c086cc9f987d57f676e5435e537` (HEAD) - Раунд: r3/4 - Вердикт: **зелёный** diff --git a/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r1.md b/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r1.md index c6b6e733..0e7f8d17 100644 --- a/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r1.md +++ b/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r1.md @@ -3,9 +3,9 @@ - **Issue:** [#282 — Геометрия стен: сменить представление, а не чинить последствия](https://github.com/Matysh/houseplan-card/issues/282) - **Этап:** spec (PROCESS.md §2.4) - **Заход:** r1 (первый; дельта-режим §2.10 не применяется) -- **Артефакт ТЗ:** [`docs/specs/282-stable-wall-segment-identity.md`](../specs/282-stable-wall-segment-identity.md) +- **Артефакт ТЗ:** [`docs/specs/282-stable-wall-segment-identity.md`](../../specs/282-stable-wall-segment-identity.md) - **SHA ТЗ на момент ревью:** `8856fbda` (`docs: specify stable wall segment identity`, единственный коммит в ветке поверх `dev`) -- **Нормативный документ:** [`docs/adr/282-wall-geometry-representation.md`](../adr/282-wall-geometry-representation.md), статус: Stage 0 принят и реализован (#283), Stage 1 — предмет этого ТЗ +- **Нормативный документ:** [`docs/adr/282-wall-geometry-representation.md`](../../../docs/adr/282-wall-geometry-representation.md), статус: Stage 0 принят и реализован (#283), Stage 1 — предмет этого ТЗ - **Поставляемый этап:** ADR Stage 1 — stored identity сегментов contour walls ## Скоуп ревью diff --git a/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r2.md b/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r2.md index 3057e914..27403b89 100644 --- a/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r2.md +++ b/legacy/reviews/v1.68.0/SPEC-REVIEW-282-r2.md @@ -3,7 +3,7 @@ - **Issue:** [#282 — Геометрия стен: сменить представление, а не чинить последствия](https://github.com/Matysh/houseplan-card/issues/282) - **Этап:** spec (PROCESS.md §2.4) - **Заход:** r2 · блокирующих циклов израсходовано 1 из 4 (§2.10, §4: зелёный вердикт r1 не был — r1 был жёлтым и потратил цикл 1; если этот заход зелёный, он сам цикла не образует) -- **Артефакт ТЗ:** [`docs/specs/282-stable-wall-segment-identity.md`](../specs/282-stable-wall-segment-identity.md) +- **Артефакт ТЗ:** [`docs/specs/282-stable-wall-segment-identity.md`](../../specs/282-stable-wall-segment-identity.md) - **SHA ТЗ на момент этого ревью:** `2f30c481` (`docs: address wall identity spec review`) - **SHA предыдущего ревью (r1):** `8856fbda` (`docs: specify stable wall segment identity`) - **Документ r1:** [`docs/reviews/SPEC-REVIEW-282-r1.md`](./SPEC-REVIEW-282-r1.md), вердикт жёлтый, High: 0, Medium: 2 (обе в скоупе) diff --git a/legacy/reviews/v1.69.0/CODE-REVIEW-359-r2.md b/legacy/reviews/v1.69.0/CODE-REVIEW-359-r2.md index 5c0a4f45..fc099003 100644 --- a/legacy/reviews/v1.69.0/CODE-REVIEW-359-r2.md +++ b/legacy/reviews/v1.69.0/CODE-REVIEW-359-r2.md @@ -2,7 +2,7 @@ Issue: [#359](https://github.com/Matysh/houseplan-card/issues/359) — Предпросмотр мебели на плане перед размещением SHA: `fd762fa7` (`issue/359-furniture-placement-preview`) -Предыдущий раунд: [CODE-REVIEW-359-r1](../reviews/CODE-REVIEW-359-r1.md) (в дереве: `docs/reviews/CODE-REVIEW-359-r1.md`) — вердикт красный, SHA `8b66d67d` +Предыдущий раунд: [CODE-REVIEW-359-r1](CODE-REVIEW-359-r1.md) (в дереве: `docs/reviews/CODE-REVIEW-359-r1.md`) — вердикт красный, SHA `8b66d67d` Заход: r2 · блокирующих циклов израсходовано 1 из 4 (r1 — красный, потратил цикл) ## Скоуп проверки @@ -50,7 +50,7 @@ r1 (красный) содержал ровно одну находку — High Без повторной проверки — код не менялся с `8b66d67d`, на котором это было проверено чтением и тестами в -[CODE-REVIEW-359-r1.md](../reviews/CODE-REVIEW-359-r1.md): +[CODE-REVIEW-359-r1.md](CODE-REVIEW-359-r1.md): - **AC1–AC9** (появление preview, геометрический паритет preview/commit через единый `resolveFurniturePlacement`, живое обновление по полям размера, diff --git a/legacy/reviews/v1.72.0/CODE-REVIEW-54-r1.md b/legacy/reviews/v1.72.0/CODE-REVIEW-54-r1.md index 9668da5e..ddd35eed 100644 --- a/legacy/reviews/v1.72.0/CODE-REVIEW-54-r1.md +++ b/legacy/reviews/v1.72.0/CODE-REVIEW-54-r1.md @@ -4,7 +4,7 @@ - Этап: `code` (PROCESS.md §2.7) - Диапазон: `origin/dev...HEAD`, `origin/dev` = `ec9824f2`, `HEAD` = `a2867df9` (ветка `issue/54-zigbee-topology-hover`, детач `HEAD`) -- ТЗ: [`docs/specs/054-zigbee-topology-overlay.md`](../specs/054-zigbee-topology-overlay.md), +- ТЗ: [`docs/specs/054-zigbee-topology-overlay.md`](../../specs/054-zigbee-topology-overlay.md), ревью ТЗ зелёное на заходе r2 — [`SPEC-REVIEW-54-r2.md`](SPEC-REVIEW-54-r2.md) (r1 → M1/L1-L3 закрыты правкой `aed0b5b6`, подтверждено r2 зелёным) - Заход: **r1** код-ревью (первый заход этого этапа для #54; ревью ТЗ и код-ревью diff --git a/legacy/reviews/v1.72.0/CODE-REVIEW-54-r2.md b/legacy/reviews/v1.72.0/CODE-REVIEW-54-r2.md index 864b9759..fb66fc66 100644 --- a/legacy/reviews/v1.72.0/CODE-REVIEW-54-r2.md +++ b/legacy/reviews/v1.72.0/CODE-REVIEW-54-r2.md @@ -5,7 +5,7 @@ - Диапазон общий: `origin/dev...HEAD`, `origin/dev` = `ec9824f2`, `HEAD` = `f0ed526a` (ветка `issue/54-zigbee-topology-hover`, детач `HEAD`, merge-base с `origin/dev` не сдвинулся — `ec9824f2` тот же, что в r1, ребейза не было) -- ТЗ: [`docs/specs/054-zigbee-topology-overlay.md`](../specs/054-zigbee-topology-overlay.md), +- ТЗ: [`docs/specs/054-zigbee-topology-overlay.md`](../../specs/054-zigbee-topology-overlay.md), ревью ТЗ зелёное на заходе r2 — [`SPEC-REVIEW-54-r2.md`](SPEC-REVIEW-54-r2.md) - Заход: **r2** код-ревью - Блокирующих циклов израсходовано: **1/4** (зелёных вердиктов ревью ТЗ бюджет diff --git a/legacy/reviews/v1.73.0/CODE-REVIEW-437-r1.md b/legacy/reviews/v1.73.0/CODE-REVIEW-437-r1.md index b3844259..d7960b59 100644 --- a/legacy/reviews/v1.73.0/CODE-REVIEW-437-r1.md +++ b/legacy/reviews/v1.73.0/CODE-REVIEW-437-r1.md @@ -2,7 +2,7 @@ Issue: [#437](https://github.com/Matysh/houseplan-card/issues/437) — конфигурируемая read-only сводная панель поверх плана. Материал: `git log --oneline origin/dev..HEAD` / `git diff origin/dev...HEAD` на SHA `96e07b9a0255eef3a55cd6c3be08198a0adcc7ba`. -ТЗ: [docs/specs/437-summary-panel.md](../specs/437-summary-panel.md), принято ревью ТЗ r2 (зелёное, High 0/Medium 0). +ТЗ: [docs/specs/437-summary-panel.md](../../specs/437-summary-panel.md), принято ревью ТЗ r2 (зелёное, High 0/Medium 0). Этап: код-ревью, заход r1, лимит циклов 4/4 (полный трек). ## Скоуп диффа diff --git a/legacy/reviews/v1.73.0/SPEC-REVIEW-495-r1.md b/legacy/reviews/v1.73.0/SPEC-REVIEW-495-r1.md index 551c41be..a5484471 100644 --- a/legacy/reviews/v1.73.0/SPEC-REVIEW-495-r1.md +++ b/legacy/reviews/v1.73.0/SPEC-REVIEW-495-r1.md @@ -2,7 +2,7 @@ - Issue: [#495](https://github.com/Matysh/houseplan-card/issues/495) - Этап: `spec` (PROCESS.md §2.4) -- ТЗ под ревью: [`docs/specs/495-import-commit-and-route-runs-durability.md`](../specs/495-import-commit-and-route-runs-durability.md) +- ТЗ под ревью: [`docs/specs/495-import-commit-and-route-runs-durability.md`](../../specs/495-import-commit-and-route-runs-durability.md) - Материал: HEAD `70a394d2` (detached), содержит коммит ТЗ `70a394d2 docs: spec for #495 — import result follows the commit, dropped route runs reach the store` - Заход: **r1**, блокирующих циклов израсходовано 0/4 (первый раунд — раздел diff --git a/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r2.md b/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r2.md index dd800dd2..c1b6bb59 100644 --- a/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r2.md +++ b/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r2.md @@ -10,7 +10,7 @@ Issue: [#588](https://github.com/Matysh/houseplan-card/issues/588) ## Скоуп разбора (по дельте, §2.10) -Предыдущий вердикт: жёлтый, заход r1, [docs/reviews/SPEC-REVIEW-588-r1.md](../../docs/reviews/SPEC-REVIEW-588-r1.md), материал — тело issue на момент разбора (SHA-256 тела `ee15ac6db7376cfb878034a0fb3bdce2907fc84f45a69cf7c0e9cd0804b7e6ce`, дерево материала `14bf5e35f9bccc2d74e54a390ebf9c9d176f2e8f`, ветка `dev`@`a6185e295d2e`). +Предыдущий вердикт: жёлтый, заход r1, [docs/reviews/SPEC-REVIEW-588-r1.md](SPEC-REVIEW-588-r1.md), материал — тело issue на момент разбора (SHA-256 тела `ee15ac6db7376cfb878034a0fb3bdce2907fc84f45a69cf7c0e9cd0804b7e6ce`, дерево материала `14bf5e35f9bccc2d74e54a390ebf9c9d176f2e8f`, ветка `dev`@`a6185e295d2e`). Дельта между r1 и r2 объявлена самим автором в комментарии перехода (`Matysh`, 2026-09-18T08:33:23Z) и подтверждена сверкой с текстом r1-документа (цитаты кода и AC в нём) построчно против текущего тела issue: @@ -34,7 +34,7 @@ Issue: [#588](https://github.com/Matysh/houseplan-card/issues/588) ## Унаследовано из r1 -Без повторной проверки в этом раунде, по [SPEC-REVIEW-588-r1.md](../../docs/reviews/SPEC-REVIEW-588-r1.md) (материал: тело issue SHA-256 `ee15ac6d...b7e6ce`, дерево `14bf5e35f9bc...`, `dev`@`a6185e295d2e`): +Без повторной проверки в этом раунде, по [SPEC-REVIEW-588-r1.md](SPEC-REVIEW-588-r1.md) (материал: тело issue SHA-256 `ee15ac6d...b7e6ce`, дерево `14bf5e35f9bc...`, `dev`@`a6185e295d2e`): - Сценарий и «что человек увидит до/после» — форма и содержание по §7.1, персона и поверхность названы (r1 §«Что проверено и корректно», п.1). Текст не менялся в дельте. - Скоуп/не-скоуп (за вычетом убранной фразы M2) — соответствует файлам, реально содержащим логику `static_icon`/`value`; не-скоуп корректно исключает `import_export.py`. diff --git a/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r3.md b/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r3.md index 22c1a3b3..56496f92 100644 --- a/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r3.md +++ b/legacy/reviews/v1.77.0/SPEC-REVIEW-588-r3.md @@ -10,7 +10,7 @@ Issue: [#588](https://github.com/Matysh/houseplan-card/issues/588) ## Скоуп разбора (по дельте, §2.10) -Предыдущий вердикт: жёлтый, заход r2, [docs/reviews/SPEC-REVIEW-588-r2.md](../../docs/reviews/SPEC-REVIEW-588-r2.md), материал — тело issue на момент разбора (SHA-256 тела `40a3c8b12af7fe3803ad3fece1a00b54c8fa12bd8fdc36b6bccd6516bf41756f`, дерево материала `002d320431837447efa84ee6119a95334bac4080`, рабочая копия кода на `git rev-parse HEAD` = `5b7add94d15a3961adc7f288f00750820cbbba07`). +Предыдущий вердикт: жёлтый, заход r2, [docs/reviews/SPEC-REVIEW-588-r2.md](SPEC-REVIEW-588-r2.md), материал — тело issue на момент разбора (SHA-256 тела `40a3c8b12af7fe3803ad3fece1a00b54c8fa12bd8fdc36b6bccd6516bf41756f`, дерево материала `002d320431837447efa84ee6119a95334bac4080`, рабочая копия кода на `git rev-parse HEAD` = `5b7add94d15a3961adc7f288f00750820cbbba07`). Дельта между r2 и r3 объявлена автором в комментарии перехода (`Matysh`, 2026-09-18T08:48:00Z) и подтверждена построчной сверкой текущего тела issue с цитатами в документе r2: @@ -28,7 +28,7 @@ Issue: [#588](https://github.com/Matysh/houseplan-card/issues/588) ## Унаследовано из r2 -Без повторной проверки в этом раунде — код и текст этих разделов не менялись дельтой r2→r3; см. [SPEC-REVIEW-588-r2.md](../../docs/reviews/SPEC-REVIEW-588-r2.md) (материал: тело issue SHA-256 `40a3c8b1...b7e6ce`, дерево `002d3204...`, рабочая копия `5b7add94d15a`) и через него [SPEC-REVIEW-588-r1.md](../../docs/reviews/SPEC-REVIEW-588-r1.md) (материал: тело issue SHA-256 `ee15ac6d...b7e6ce`, дерево `14bf5e35f9bc...`, `dev`@`a6185e295d2e`): +Без повторной проверки в этом раунде — код и текст этих разделов не менялись дельтой r2→r3; см. [SPEC-REVIEW-588-r2.md](SPEC-REVIEW-588-r2.md) (материал: тело issue SHA-256 `40a3c8b1...b7e6ce`, дерево `002d3204...`, рабочая копия `5b7add94d15a`) и через него [SPEC-REVIEW-588-r1.md](SPEC-REVIEW-588-r1.md) (материал: тело issue SHA-256 `ee15ac6d...b7e6ce`, дерево `14bf5e35f9bc...`, `dev`@`a6185e295d2e`): - Сценарий и «что человек увидит до/после» — форма и содержание по §7.1 (r1 §«Что проверено и корректно», п.1). - Скоуп/не-скоуп — соответствует файлам, реально содержащим логику `static_icon`/`value`; не-скоуп корректно исключает `import_export.py`; фраза про «подсветку убираемой комнаты» убрана (M2, закрыт в r2), #589 существует, открыт, метки `bug, docs, vacuum, P3, S1-new` — проверено повторно в r2, не проверялось заново здесь. diff --git a/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r1.md b/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r1.md index a2f1b910..cef9f480 100644 --- a/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r1.md +++ b/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r1.md @@ -48,7 +48,7 @@ Issue: [#593](https://github.com/Matysh/houseplan-card/issues/593) Воспроизведение: `gh api repos/Matysh/houseplan-card/issues/593/timeline` показывает единственный комментарий issue (00:05:53) с текстом «Два продуктовых вопроса владельцу» и тут же — «Молчание считаю согласием с обоими вариантами по умолчанию: ТЗ пишу на них». Метка `S3-spec` появляется через 4 секунды после этого комментария (00:05:57), `S4-spec-review` — ещё через 7 минут (00:12:35). Метка `blocked` не применялась вовсе. Второго комментария, письма или иного независимого источника, где владелец лично подтверждает выбор, в issue нет. -`PROCESS.md` §7.1 резервирует «молчание — согласие» **только** за аналитическими оценками этапа S2 (§2.2: «Комментарий аналитики — уведомление, а не запрос»); для продуктовых вопросов этапа ТЗ предписан другой протокол — вопрос пачкой с дефолтом, `blocked` поверх `S3-spec`, и ожидание фактического ответа. Прецедент того, как это должно выглядеть, в этом же проекте: [SPEC-REVIEW-588-r1](../../docs/reviews/SPEC-REVIEW-588-r1.md) констатирует «владелец принял варианты по умолчанию по всем трём вопросам 18.09.2026 непосредственно в теле issue» — отдельным действием, с датой, отдельно от вопроса. +`PROCESS.md` §7.1 резервирует «молчание — согласие» **только** за аналитическими оценками этапа S2 (§2.2: «Комментарий аналитики — уведомление, а не запрос»); для продуктовых вопросов этапа ТЗ предписан другой протокол — вопрос пачкой с дефолтом, `blocked` поверх `S3-spec`, и ожидание фактического ответа. Прецедент того, как это должно выглядеть, в этом же проекте: [SPEC-REVIEW-588-r1](SPEC-REVIEW-588-r1.md) констатирует «владелец принял варианты по умолчанию по всем трём вопросам 18.09.2026 непосредственно в теле issue» — отдельным действием, с датой, отдельно от вопроса. Более того, прецедент по этой же самой подсистеме прямо предупреждает именно об этой ошибке: в [#159](https://github.com/Matysh/houseplan-card/issues/159) (внедрение библиотеки мебели 0.3.0) reviewer поставил **High-1** за то, что подтверждение авторства/MIT было дано «только в рабочей сессии» и не публично, хотя аналитика формулировала это как решённый факт — задача была заблокирована до тех пор, пока `Matysh` не опубликовал отдельный явный комментарий от первого лица. Автор текущего ТЗ этот урок применил к AC10 (лицензия) буквально, сославшись на #159 по номеру, но не применил его к собственным Р1/Р2 — те получили формулировку «Принято» без аналогичного независимого голоса. diff --git a/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r2.md b/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r2.md index 8a3c224a..66a167c4 100644 --- a/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r2.md +++ b/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r2.md @@ -15,7 +15,7 @@ Issue: [#593](https://github.com/Matysh/houseplan-card/issues/593) - Тело issue #593 на момент разбора: `gh issue view 593 --json body` (редакция 3 от 19.09.2026, раздел `## ТЗ`), сохранённое предложение автора выше него. - Все 5 комментариев issue: `gh issue view 593 --json comments`. - Полная временная шкала: `gh api repos/Matysh/houseplan-card/issues/593/timeline`. -- Предыдущий раунд: [`docs/reviews/SPEC-REVIEW-593-r1.md`](../../docs/reviews/SPEC-REVIEW-593-r1.md), вердикт красный, материал зафиксирован в его собственном машинном блоке якорей: ветка `dev`, коммит `073c45b04308cd613182c700f30c75ebfa8d2ca7`, дерево `393fc8925392ed600ae675587da91f34ba6b3372`, тело issue sha256 `8be001d5a0b2efa4aeb3f2bcd347a9253252dd47c38b091473e6686ca24f91d6`. Текущее тело issue (редакция 3) очевидно отличается от этого текста — задача прошла через редакции 2 и 3 в ответ на вердикт r1; байтового совпадения с r1 не проверял, поскольку различие заведомо есть (сам факт правки — предмет этого раунда). +- Предыдущий раунд: [`docs/reviews/SPEC-REVIEW-593-r1.md`](SPEC-REVIEW-593-r1.md), вердикт красный, материал зафиксирован в его собственном машинном блоке якорей: ветка `dev`, коммит `073c45b04308cd613182c700f30c75ebfa8d2ca7`, дерево `393fc8925392ed600ae675587da91f34ba6b3372`, тело issue sha256 `8be001d5a0b2efa4aeb3f2bcd347a9253252dd47c38b091473e6686ca24f91d6`. Текущее тело issue (редакция 3) очевидно отличается от этого текста — задача прошла через редакции 2 и 3 в ответ на вердикт r1; байтового совпадения с r1 не проверял, поскольку различие заведомо есть (сам факт правки — предмет этого раунда). - Прецедент [#159](https://github.com/Matysh/houseplan-card/issues/159) — та же подсистема, предыдущее внедрение библиотеки мебели (0.3.0): его r1-ревью, его находка High-1, его remediation-комментарии, финальный код (`test/furniture-assets.test.mjs`, `assets/furniture/houseplan-0.3.0/README.md`). Читал заново специально для этого раунда, поскольку именно на него ссылается текущий ТЗ (AC10) как на образец, и именно его конкретный текст стал мерилом находки H1(new) ниже. - Код: `test/furniture-assets.test.mjs` (тест `'release provenance is normalized to the repository MIT grant'`), `assets/furniture/houseplan-0.3.0/README.md`, `src/furniture-art-runtime.ts`, `src/houseplan-card.ts:2693`, `src/i18n/{ru,en,fr,de}.json` (ключ `toast.furniture_art_load_failed`) — прочитаны, чтобы проверить два конкретных утверждения редакции 3 (см. «Как проверялось»). - Ветка/код продукта: не создавались. `git log` подтверждает отсутствие любых коммитов или веток `issue/593-*`; рабочая копия на `HEAD = dcd6657581ba205edb63713e011a498b51983a20` (последний коммит — публикация документа r1), продуктовый код не менялся с r1. Гейты `typecheck`/`test`/`build`/`bundle:budget` не запускал — на этапе ревью ТЗ они не относятся к предмету раунда (см. «Чего не проверял», и это же практика самого r1). diff --git a/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r3.md b/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r3.md index cedb317d..e225a2ec 100644 --- a/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r3.md +++ b/legacy/reviews/v1.77.0/SPEC-REVIEW-593-r3.md @@ -21,7 +21,7 @@ Issue: [#593](https://github.com/Matysh/houseplan-card/issues/593) был учтён r2; новые — полноценный грант `#issuecomment-5739841899` (2026-09-19T06:09:00Z) и ответ на красный вердикт r2 `#issuecomment-5739855252` (06:12:00Z), которым поставлена `S4-spec-review`, заход r3). -- Предыдущий раунд: [`docs/reviews/SPEC-REVIEW-593-r2.md`](../../docs/reviews/SPEC-REVIEW-593-r2.md), +- Предыдущий раунд: [`docs/reviews/SPEC-REVIEW-593-r2.md`](SPEC-REVIEW-593-r2.md), вердикт красный, материал зафиксирован в его собственном машинном блоке якорей: ветка `dev`, коммит `dcd6657581ba205edb63713e011a498b51983a20`, дерево `0b48707268e99ee38221c8e74fb1c48ce6793e35`, тело issue sha256 @@ -73,10 +73,10 @@ Issue: [#593](https://github.com/Matysh/houseplan-card/issues/593) Дельта r2→r3 ограничена §3 Q3, §4 п.10–11, §8 (абзац «провенанс»), §10 AC10, §11 — всё остальное принято без повторной проверки в этом раунде, со ссылкой на -[`SPEC-REVIEW-593-r2.md`](../../docs/reviews/SPEC-REVIEW-593-r2.md) (материал: ветка +[`SPEC-REVIEW-593-r2.md`](SPEC-REVIEW-593-r2.md) (материал: ветка `dev`, коммит `dcd6657581ba205edb63713e011a498b51983a20`, дерево `0b48707268e99ee38221c8e74fb1c48ce6793e35`) и, где отмечено, на -[`SPEC-REVIEW-593-r1.md`](../../docs/reviews/SPEC-REVIEW-593-r1.md) (коммит +[`SPEC-REVIEW-593-r1.md`](SPEC-REVIEW-593-r1.md) (коммит `073c45b04308cd613182c700f30c75ebfa8d2ca7`): - Комплектность обязательных разделов §7.1 — проверена r1, дельта их не убирала. diff --git a/legacy/specs/262-readd-child-entity-after-device-delete.md b/legacy/specs/262-readd-child-entity-after-device-delete.md index 4b628ae8..612bda0e 100644 --- a/legacy/specs/262-readd-child-entity-after-device-delete.md +++ b/legacy/specs/262-readd-child-entity-after-device-delete.md @@ -3,7 +3,7 @@ - Issue: [#262](https://github.com/Matysh/houseplan-card/issues/262) - Ветка: `issue/262-readd-child-entity` - Статус: реализовано, ожидает код-ревью -- Ревью ТЗ: [`docs/reviews/SPEC-REVIEW-262-r1.md`](../../docs/reviews/SPEC-REVIEW-262-r1.md), +- Ревью ТЗ: [`docs/reviews/SPEC-REVIEW-262-r1.md`](../reviews/v1.68.0/SPEC-REVIEW-262-r1.md), зелёный вердикт - Приоритет: `P2` - Тип: `bug` diff --git a/scripts/mutation-registry.mjs b/scripts/mutation-registry.mjs index fcd5860c..5f059645 100644 --- a/scripts/mutation-registry.mjs +++ b/scripts/mutation-registry.mjs @@ -9969,6 +9969,17 @@ const MUTANT_DEFINITIONS = [ replace: ' for (const issue of line.issues) if (!lineOf.has(Number(issue))) lineOf.set(Number(issue), line.tag); // mutant: first line wins', }], }, + { + id: 'reviews-archive-links-from-new-place-only', + guard: 'node --test --test-name-pattern="#682 r1 ссылки: перенесённый документ" test/reviews-archive.test.mjs', + because: 'review #682 r1: a moved document keeps links written for its old folder; resolving ' + + 'them only from the new place leaves every ../specs/ and sibling link broken in the archive', + patches: [{ + file: 'scripts/reviews-archive.mjs', + find: ' for (const base of [path, oldPath]) {', + replace: ' for (const base of [path]) { // mutant: old location ignored', + }], + }, { id: 'reviews-index-release-counts-ignored', guard: 'node --test --test-name-pattern="#635 счётчики|#635 индекс покрывает" test/reviews-index.test.mjs', diff --git a/scripts/reviews-archive.mjs b/scripts/reviews-archive.mjs index 9a754067..c5317c98 100644 --- a/scripts/reviews-archive.mjs +++ b/scripts/reviews-archive.mjs @@ -28,9 +28,16 @@ * сам документ — первым стабильным тегом, содержащим его добавление; * - имя вне схемы и документ, не попавший ни в одну линию, остаются на месте * и печатаются — решает человек. + * + * Перенос добавляет документу уровень вложенности (`docs/reviews/X.md` → + * `legacy/reviews/<тег>/X.md`), поэтому `--apply` переписывает относительные + * Markdown-ссылки — и внутри перенесённых файлов, и в соседях, которые на них + * ссылаются (`repairLinks`, ревью #682 r1). `--repair-links=` делает то же + * для всех переименований `..HEAD`, `--check-links` печатает битые + * относительные ссылки архива и живых каталогов. */ -import { existsSync, mkdirSync } from 'node:fs'; -import { dirname, join, resolve } from 'node:path'; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join, posix, resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { isMainModule } from './spawn-portable.mjs'; @@ -150,6 +157,100 @@ export function addedLines({ names, through, head = 'HEAD', cwd = ROOT }) { return result; } +const LINK_RE = /(\]\()([^)\s]+)(\))/g; +const EXTERNAL = /^(?:[a-z][a-z0-9+.-]*:|#|\/)/i; + +/** + * Переписать относительные ссылки одного Markdown-файла после переносов. + * + * `path` — где файл лежит сейчас, `oldPath` — где лежал до переноса (для + * неперенесённого совпадает). Ссылка, которая и так резолвится от `path`, + * не трогается. Иначе цель ищется от `path` и от `oldPath`, проводится через + * `moved` (старый путь → новый), и если так найден существующий файл — ссылка + * пересчитывается от нового места. Ссылка, битая и до переноса, остаётся как + * была: чинить чужую историю — не дело архива. + * + * @returns {{ text: string, fixed: number }} + */ +export function repairLinks({ text, path, oldPath = path, moved, exists }) { + let fixed = 0; + const out = String(text).replace(LINK_RE, (whole, open, target, close) => { + if (EXTERNAL.test(target)) return whole; + const hash = target.indexOf('#'); + const file = hash >= 0 ? target.slice(0, hash) : target; + const anchor = hash >= 0 ? target.slice(hash) : ''; + if (!file) return whole; + let decoded; + try { decoded = decodeURI(file); } catch { decoded = file; } + const here = posix.normalize(posix.join(posix.dirname(path), decoded)); + if (exists(here)) return whole; + for (const base of [path, oldPath]) { + const candidate = posix.normalize(posix.join(posix.dirname(base), decoded)); + const now = moved.get(candidate) ?? candidate; + if (now !== here && exists(now)) { + fixed += 1; + let rel = posix.relative(posix.dirname(path), now); + if (!rel.startsWith('.')) rel = rel || posix.basename(now); + return `${open}${rel}${anchor}${close}`; + } + } + return whole; + }); + return { text: out, fixed }; +} + +/** Все отслеживаемые Markdown-файлы: ссылаться на перенесённый документ может любой. */ +function trackedMarkdown(cwd) { + return git(['ls-files', '-z', '--', '*.md'], cwd).split('\0').filter(Boolean); +} + +/** + * Прогнать `repairLinks` по всем Markdown-файлам дерева. + * @param moved Map<старый путь, новый путь> + */ +export function repairTreeLinks({ moved, cwd = ROOT }) { + const inverse = new Map([...moved].map(([from, to]) => [to, from])); + const exists = (rel) => existsSync(join(cwd, rel)); + let files = 0; let links = 0; + for (const path of trackedMarkdown(cwd)) { + const full = join(cwd, path); + if (!existsSync(full)) continue; + const text = readFileSync(full, 'utf8'); + const result = repairLinks({ text, path, oldPath: inverse.get(path) ?? path, moved, exists }); + if (result.fixed) { + writeFileSync(full, result.text); + files += 1; links += result.fixed; + } + } + return { files, links }; +} + +/** Переименования `rev..HEAD` (`git diff -M`): карта старый путь → новый. */ +export function renamesSince(rev, cwd = ROOT) { + const out = git(['diff', '-M', '--name-status', '--diff-filter=R', '-z', rev, 'HEAD'], cwd).split('\0').filter(Boolean); + const moved = new Map(); + for (let i = 0; i < out.length; i += 3) moved.set(out[i + 1], out[i + 2]); + return moved; +} + +/** Битые относительные ссылки в архиве и живых каталогах документов ревью и ТЗ. */ +export function brokenLinks({ cwd = ROOT, roots = [LIVE_DIR, ARCHIVE_DIR, 'docs/specs', 'legacy/specs'] } = {}) { + const broken = []; + for (const path of trackedMarkdown(cwd).filter((p) => roots.some((root) => p.startsWith(`${root}/`)))) { + const text = readFileSync(join(cwd, path), 'utf8'); + for (const [, , target] of text.matchAll(LINK_RE)) { + if (EXTERNAL.test(target)) continue; + const file = target.split('#')[0]; + if (!file) continue; + let decoded; + try { decoded = decodeURI(file); } catch { decoded = file; } + const resolved = posix.normalize(posix.join(posix.dirname(path), decoded)); + if (!existsSync(join(cwd, resolved))) broken.push({ path, target }); + } + } + return broken; +} + export function applyPlan({ moves, cwd = ROOT }) { const dirty = git(['status', '--porcelain', '--', LIVE_DIR, ARCHIVE_DIR], cwd).trim(); if (dirty) throw new Error(`рабочее дерево ${LIVE_DIR}/${ARCHIVE_DIR} не чистое:\n${dirty}`); @@ -158,16 +259,30 @@ export function applyPlan({ moves, cwd = ROOT }) { mkdirSync(join(cwd, dirname(move.to)), { recursive: true }); git(['mv', move.from, move.to], cwd); } + const repaired = repairTreeLinks({ moved: new Map(moves.map((move) => [move.from, move.to])), cwd }); + if (repaired.files) git(['add', '-u', '--', '.'], cwd); const index = spawnSync(process.execPath, [join(ROOT, 'scripts/reviews-index.mjs'), `--dir=${LIVE_DIR}`], { cwd, encoding: 'utf8' }); if (index.status !== 0) throw new Error(`reviews-index: ${index.stderr || index.stdout}`); git(['add', '--', join(LIVE_DIR, INDEX_FILE)], cwd); + return repaired; } if (isMainModule(import.meta.url)) { const arg = (name) => process.argv.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3); + if (arg('repair-links')) { + const result = repairTreeLinks({ moved: renamesSince(arg('repair-links')) }); + console.log(`ссылок переписано ${result.links} в ${result.files} файл(ах)`); + process.exit(0); + } + if (process.argv.includes('--check-links')) { + const broken = brokenLinks(); + for (const item of broken) console.log(`${item.path}: ${item.target}`); + console.log(`битых относительных ссылок: ${broken.length}`); + process.exit(broken.length ? 1 : 0); + } const through = arg('through'); if (!through || !STABLE_TAG_RE.test(through)) { - console.error('usage: node scripts/reviews-archive.mjs --through=vX.Y.Z [--head=HEAD] [--apply]'); + console.error('usage: node scripts/reviews-archive.mjs --through=vX.Y.Z [--head=HEAD] [--apply] | --repair-links= | --check-links'); process.exit(2); } const head = arg('head') || 'HEAD'; @@ -179,8 +294,8 @@ if (isMainModule(import.meta.url)) { : first; console.log(renderPlan({ ...plan, through })); if (process.argv.includes('--apply')) { - applyPlan({ moves: plan.moves }); - console.log(`перенесено ${plan.moves.length}; ${LIVE_DIR}/${INDEX_FILE} пересобран. Коммит — класс C, с трейлером задачи.`); + const repaired = applyPlan({ moves: plan.moves }); + console.log(`перенесено ${plan.moves.length}; ссылок переписано ${repaired.links} в ${repaired.files} файл(ах); ${LIVE_DIR}/${INDEX_FILE} пересобран. Коммит — класс C, с трейлером задачи.`); } else { console.log('план (--apply выполнит git mv и пересоберёт индекс)'); } diff --git a/test/reviews-archive.test.mjs b/test/reviews-archive.test.mjs index dbf8c83f..61069f80 100644 --- a/test/reviews-archive.test.mjs +++ b/test/reviews-archive.test.mjs @@ -1,7 +1,7 @@ // #682: архив документов ревью выпущенных линий — кому куда, решают трейлеры. import assert from 'node:assert/strict'; import test from 'node:test'; -import { ARCHIVE_DIR, LIVE_DIR, archivePlan, renderPlan, stableTagsThrough } from '../scripts/reviews-archive.mjs'; +import { ARCHIVE_DIR, LIVE_DIR, archivePlan, brokenLinks, renderPlan, repairLinks, stableTagsThrough } from '../scripts/reviews-archive.mjs'; const lines = [ { tag: 'v1.76.0', issues: [500, 510, 520] }, @@ -66,3 +66,55 @@ test('#682 архив: линии — только стабильные теги assert.throws(() => stableTagsThrough([], 'v1.78.0-beta.1'), /not a stable release tag/); assert.throws(() => archivePlan({ names: [], lines: [{ tag: 'v1.78.0', issues: [] }], open: [], through: 'v1.77.0' }), /newer than/); }); + +// Ревью #682 r1 (Medium): перенос добавляет уровень вложенности, и относительные +// ссылки внутри перенесённых документов и в соседях, которые на них ссылаются, +// ломались молча — ни один гейт не смотрит в архив. +const tree = new Set([ + 'docs/specs/089-stage1.md', + 'docs/reviews/CODE-REVIEW-635-r1.md', + 'legacy/reviews/v1.77.0/CODE-REVIEW-594-r1.md', + 'legacy/reviews/v1.77.0/CODE-REVIEW-594-r2.md', + 'legacy/reviews/v1.68.0/SPEC-REVIEW-262-r1.md', + 'legacy/specs/262-readd.md', +]); +const exists = (path) => tree.has(path); +const moved = new Map([ + ['docs/reviews/CODE-REVIEW-594-r1.md', 'legacy/reviews/v1.77.0/CODE-REVIEW-594-r1.md'], + ['docs/reviews/CODE-REVIEW-594-r2.md', 'legacy/reviews/v1.77.0/CODE-REVIEW-594-r2.md'], + ['docs/reviews/SPEC-REVIEW-262-r1.md', 'legacy/reviews/v1.68.0/SPEC-REVIEW-262-r1.md'], + ['docs/specs/262-readd.md', 'legacy/specs/262-readd.md'], +]); + +test('#682 r1 ссылки: перенесённый документ пересчитывает свои ссылки от нового места', () => { + const result = repairLinks({ + text: 'ТЗ: [s](../specs/089-stage1.md#ac2); прошлый раунд: [r1](CODE-REVIEW-594-r1.md); сайт: [x](https://example.org/a.md)', + path: 'legacy/reviews/v1.77.0/CODE-REVIEW-594-r2.md', + oldPath: 'docs/reviews/CODE-REVIEW-594-r2.md', + moved, exists, + }); + assert.equal(result.text, 'ТЗ: [s](../../../docs/specs/089-stage1.md#ac2); прошлый раунд: [r1](CODE-REVIEW-594-r1.md); сайт: [x](https://example.org/a.md)'); + assert.equal(result.fixed, 1); +}); + +test('#682 r1 ссылки: сосед, ссылавшийся на перенесённый документ, ведёт в архив', () => { + const live = repairLinks({ text: '[r1](CODE-REVIEW-594-r1.md)', path: 'docs/reviews/CODE-REVIEW-635-r1.md', moved, exists }); + assert.equal(live.text, '[r1](../../legacy/reviews/v1.77.0/CODE-REVIEW-594-r1.md)'); + // Ссылка, уже переписанная прошлым переносом (ТЗ ушло в legacy/specs раньше документа ревью). + const spec = repairLinks({ + text: '[r](../../docs/reviews/SPEC-REVIEW-262-r1.md)', path: 'legacy/specs/262-readd.md', oldPath: 'docs/specs/262-readd.md', moved, exists, + }); + assert.equal(spec.text, '[r](../reviews/v1.68.0/SPEC-REVIEW-262-r1.md)'); +}); + +test('#682 r1 ссылки: битая и до переноса ссылка не «чинится» наугад', () => { + const result = repairLinks({ text: '[x](...), [y](nowhere.md)', path: 'legacy/reviews/v1.72.0/CODE-REVIEW-448-r2.md', oldPath: 'docs/reviews/CODE-REVIEW-448-r2.md', moved, exists }); + assert.equal(result.fixed, 0); + assert.equal(result.text, '[x](...), [y](nowhere.md)'); +}); + +test('#682 r1 архив legacy/: относительные ссылки резолвятся (кроме известных «...»-заглушек)', () => { + const broken = brokenLinks({ roots: ['legacy/reviews', 'legacy/specs'] }).filter((item) => item.target !== '...'); + assert.deepEqual(broken, []); +}); +