From 49bae62e9a3c17bba349fc77c69e36efac7f51e6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 23 Sep 2026 16:48:27 +0300 Subject: [PATCH] =?UTF-8?q?reviews-index:=20=D1=81=D0=B2=D0=B5=D0=B6=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D0=B8=D0=BD=D0=B4=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80=D0=B5=D0=B1=D0=B5?= =?UTF-8?q?=D0=B9=D0=B7=D0=BE=D0=B2=20=D0=BA=D0=BE=D0=BD=D0=B2=D0=B5=D0=B9?= =?UTF-8?q?=D0=B5=D1=80=D0=B0,=20=D0=BF=D0=B5=D1=80=D0=B2=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=B0=D0=B1=D0=B7=D0=B0=D1=86=20=D0=BD=D0=B0=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=BA=D0=B8=20=D1=86=D0=B5=D0=BB=D0=B8=D0=BA=D0=BE=D0=BC=20(#6?= =?UTF-8?q?35=20r3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit r2 H1: INDEX.md — снимок каталога, и ребейз ветки на dev, получивший чужие документы ревью, устаревал его молча. Теперь `--commit-if-stale` пересобирает и коммитит индекс коммитом конвейера после приведения к dev (process.yml) и после ребейза кандидата (merge-candidate.mjs); тест «индекс свеж» сравнивает закоммиченный файл с пересборкой и красит Validate при расхождении. r2 M1: находка без заголовка — первый абзац секции, склеенный из перенесённых строк, без маркера буллета и кода `**M1.**`; «не найдено», служебные скобки «(унаследовано…)» — не находка. Нумерованные пункты тоже забирают перенесённые строки. Мутант reviews-index-paragraph-tail. PROCESS.md §2.10 дополнен. Issue: #635 User-Visible: no --- .github/workflows/process.yml | 6 ++ PROCESS.md | 8 +- docs/reviews/INDEX.md | 177 +++++++++++++++++----------------- scripts/merge-candidate.mjs | 13 ++- scripts/mutation-registry.mjs | 11 +++ scripts/reviews-index.mjs | 83 ++++++++++++++-- test/merge-candidate.test.mjs | 8 +- test/reviews-index.test.mjs | 82 +++++++++++++++- 8 files changed, 288 insertions(+), 100 deletions(-) diff --git a/.github/workflows/process.yml b/.github/workflows/process.yml index 9cce9bc5..9d9be65e 100644 --- a/.github/workflows/process.yml +++ b/.github/workflows/process.yml @@ -396,6 +396,7 @@ jobs: # #539: тем же токеном спрашивается REST — через него идёт и диспатч. GH_TOKEN: ${{ secrets.HP_PROCESS_TOKEN }} BRANCH: ${{ steps.branch.outputs.name }} + NUM: ${{ github.event.issue.number }} # rebase, в отличие от commit, не принимает -c user.*: он запускает # свои процессы и требует личность в окружении, иначе падает с # «unable to auto-detect email address». @@ -427,6 +428,11 @@ jobs: printf 'конфликтуют:\n%s\n' "${files:-(git не назвал файлы)}" exit 0 fi + # #635 r2: ребейз мог принести в docs/reviews документы других задач, + # а закоммиченный INDEX.md — снимок каталога — их не знает. Свежесть + # держит тест «индекс свеж» в Validate, поэтому индекс пересобирается + # здесь же, коммитом конвейера (класс C), до фиксации материала. + node scripts/reviews-index.mjs --dir=docs/reviews --commit-if-stale --issue="$NUM" # --force-with-lease с явным ожидаемым значением обязателен: между # fetch и push автор мог запушить коммит, и слепой --force потерял бы # его молча. Расхождение lease — падение прогона, а не предупреждение: diff --git a/PROCESS.md b/PROCESS.md index 634ad47d..de6e5ed5 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -330,9 +330,13 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready → сокращение превращается в молчаливое доверие. **Индекс документов ревью** — `docs/reviews/INDEX.md` (#635): одна строка на -документ — issue, этап, раунд, вердикт, число High/Medium, заголовки находок. +документ — issue, этап, раунд, вердикт, число High/Medium, заголовки находок, +файлы из находок (искать по имени файла: `grep form-kit docs/reviews/INDEX.md`). Файл генерируется `node scripts/reviews-index.mjs` и пересобирается конвейером -тем же коммитом, что публикует документ; руками не правится. Прежде чем брать +тем же коммитом, что публикует документ, а также после каждого его ребейза +(приведение к dev перед ревью, слияние кандидата — `--commit-if-stale`, коммит +класса C); руками не правится. Тест «индекс свеж» в Validate красит дерево, +где `INDEX.md` расходится с каталогом. Прежде чем брать задачу по подсистеме, стоит прочитать её строки в индексе: что находили и чем закрывали — там, а не в тысяче файлов. Уроки, пережившие свою задачу, собираются в `docs/LESSONS.md` с датой и ссылкой на источник. diff --git a/docs/reviews/INDEX.md b/docs/reviews/INDEX.md index bc4a96b7..7becf2b6 100644 --- a/docs/reviews/INDEX.md +++ b/docs/reviews/INDEX.md @@ -1,15 +1,20 @@ # Индекс ревью -Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 992, issue: 345. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. +Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 997, issue: 346. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. | Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы | |---|---|---|---|---:|---:|---|---| -| #639 | [CODE-REVIEW-639-r1.md](CODE-REVIEW-639-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Новая запись smoke-links.mjs для smoke_space_settings_form.mjs | `smoke-links.mjs` `smoke_space_settings_form.mjs` `scripts/smoke-links.mjs` `demo/smoke_space_settings_form.mjs` `src/editors/space-form.ts` `form-kit.ts` | +| #639 | [CODE-REVIEW-639-r1.md](CODE-REVIEW-639-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Новая запись smoke-links.mjs для smoke_space_settings_form.mjs описывает проверку, кото… | `smoke-links.mjs` `smoke_space_settings_form.mjs` `scripts/smoke-links.mjs` `demo/smoke_space_settings_form.mjs` `src/editors/space-form.ts` `form-kit.ts` | | #639 | [CODE-REVIEW-639-r2.md](CODE-REVIEW-639-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #637 | [CODE-REVIEW-637-r1.md](CODE-REVIEW-637-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | ложный «—» вместо настоящего «0 ч» в медианах | `scripts/process-metrics.mjs` | | #637 | [CODE-REVIEW-637-r2.md](CODE-REVIEW-637-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #636 | [CODE-REVIEW-636-r1.md](CODE-REVIEW-636-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #635 | [CODE-REVIEW-635-r1.md](CODE-REVIEW-635-r1.md) | code · r1 | 🟡 жёлтый | 1 | 0 | индекс молчаливо теряет находки и врёт числами по текущему | `docs/reviews/CODE-REVIEW-639-r1.md` `CODE-REVIEW-637-r1.md` `docs/reviews/CODE-REVIEW-594-r1.md` `docs/LESSONS.md` | +| #635 | [CODE-REVIEW-635-r2.md](CODE-REVIEW-635-r2.md) | code · r2 | 🟡 жёлтый | 1 | 1 | docs/reviews/INDEX.md, зафиксированный в материале ревью, устарел на собственном SHA — …; parseFindings/parseFiles: фолбэк «первая строка тела блока» вырезает начало буллета и п… | `docs/reviews/INDEX.md` `SPEC-REVIEW-625-r1.md` `SPEC-REVIEW-625-r2.md` `CODE-REVIEW-625-r1.md` `CODE-REVIEW-625-r2.md` `process.yml` `test/reviews-index.test.mjs` `INDEX.md` | +| #625 | [SPEC-REVIEW-625-r1.md](SPEC-REVIEW-625-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | новый инвариант markers[].id не описывает исход для уже испорченной хранимой конфигурации; продуктовые формулировки §7.1 неполны; не проговорены явные «нет» по i18n/touch | `validation.py` `__init__.py` | +| #625 | [SPEC-REVIEW-625-r2.md](SPEC-REVIEW-625-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | +| #625 | [CODE-REVIEW-625-r1.md](CODE-REVIEW-625-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | Три из четырёх точек вызова validate_active_marker_ids не имеют ни одного теста, exerci…; AC5 текстуально обещает «отдельные тесты сохраняют поведение при отсутствующем length» …; store.py:async_save_config_state — controller.async_flush() и последующий controller.re… | `custom_components/houseplan/websocket_api.py` `test_validation.py` | +| #625 | [CODE-REVIEW-625-r2.md](CODE-REVIEW-625-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #621 | [CODE-REVIEW-621-r1.md](CODE-REVIEW-621-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #619 | [CODE-REVIEW-619-r1.md](CODE-REVIEW-619-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #613 | [SPEC-REVIEW-613-r1.md](SPEC-REVIEW-613-r1.md) | spec · r1 | 🟡 жёлтый | 1 | 1 | High. Принятое предположение о scroll-инвалидации не работает в основном заявленном сце…; Medium (в скоупе), сопутствует H1. AC1/AC2 не требуют, чтобы smoke-контейнер пересекал … | `demo/serve.mjs` | @@ -31,7 +36,7 @@ | #607 | [SPEC-REVIEW-607-r1.md](SPEC-REVIEW-607-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | предварительный блок ## AC в начале тела issue называет несуществующую кнопку | — | | #607 | [CODE-REVIEW-607-r1.md](CODE-REVIEW-607-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | новые guard'ы AC4 проверяются только смоком, но не зарегистрированы в scripts/mutation-… | `scripts/mutation-registry.mjs` `demo/smoke_dialog_modal_recovery.mjs` `scripts/mutation-gate.mjs` | | #607 | [CODE-REVIEW-607-r2.md](CODE-REVIEW-607-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #606 | [SPEC-REVIEW-606-r1.md](SPEC-REVIEW-606-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. Предположение 1 («резолвер покрывает арт и lazy-gate») по буквальному | `src/decor-image-editor.ts` `demo/smoke_furniture.mjs` `test/furniture-assets.test.mjs` | +| #606 | [SPEC-REVIEW-606-r1.md](SPEC-REVIEW-606-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. Предположение 1 («резолвер покрывает арт и lazy-gate») по буквальному прочтению не н… | `src/decor-image-editor.ts` `demo/smoke_furniture.mjs` `test/furniture-assets.test.mjs` | | #606 | [CODE-REVIEW-606-r1.md](CODE-REVIEW-606-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #605 | [SPEC-REVIEW-605-r1.md](SPEC-REVIEW-605-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #605 | [CODE-REVIEW-605-r1.md](CODE-REVIEW-605-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | @@ -50,19 +55,19 @@ | #598 | [SPEC-REVIEW-598-r2.md](SPEC-REVIEW-598-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #598 | [CODE-REVIEW-598-r1.md](CODE-REVIEW-598-r1.md) | code · r1 | 🔴 красный | 1 | 3 | AC8 (эталоны) не выполнен: golden:verify красный на этом SHA; AC2/AC3 нарушены: изменён один из «неприкосновенных» .srcrow-смоков; Сегментированный переключатель обещан в семи местах ТЗ, реализован в одном; AC5 доказан мутантом только наполовину; AC1 не имеет обещанного автотеста для диалога «Пространство» (закрыто чтением) | `src/editors/general-settings-dialog.ts` `src/editors/space-settings-dialog.ts` `src/editors/marker-dialog.ts` `demo/smoke_tap_run.mjs` `smoke_general_settings.mjs` `smoke_tap_run.mjs` `demo/smoke_marker_dialog_cards.mjs` `space-settings-dialog.ts` | | #598 | [CODE-REVIEW-598-r2.md](CODE-REVIEW-598-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #597 | [SPEC-REVIEW-597-r1.md](SPEC-REVIEW-597-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | AC2 заявляет проверку «ни одно из пяти правил не лежит в листе панели литералом», но; К3/AC3 заявляют байт-в-байт неизменность выхода formKitCss(CARD_DIALOG_FORM_KIT), но | `src/summary-panel-editor-style.ts` `test/form-kit.test.mjs` `test/styles-split.test.mjs` `styles-split.test.mjs` | +| #597 | [SPEC-REVIEW-597-r1.md](SPEC-REVIEW-597-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | AC2 заявляет проверку «ни одно из пяти правил не лежит в листе панели литералом», но на…; К3/AC3 заявляют байт-в-байт неизменность выхода formKitCss(CARD_DIALOG_FORM_KIT), но на… | `src/summary-panel-editor-style.ts` `test/form-kit.test.mjs` `test/styles-split.test.mjs` `styles-split.test.mjs` | | #597 | [SPEC-REVIEW-597-r2.md](SPEC-REVIEW-597-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #597 | [CODE-REVIEW-597-r1.md](CODE-REVIEW-597-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | устаревший обязательный гейт check-docs не закрыт | `src/styles/form-kit.styles.ts` `src/summary-panel-editor-style.ts` `USER-GUIDE.ru.md` `docs/images/screenshots.json` | | #597 | [CODE-REVIEW-597-r2.md](CODE-REVIEW-597-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #596 | [CODE-REVIEW-596-r1.md](CODE-REVIEW-596-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #595 | [CODE-REVIEW-595-r1.md](CODE-REVIEW-595-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #594 | [SPEC-REVIEW-594-r2.md](SPEC-REVIEW-594-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Раздел «i18n» ТЗ не называет ключи для текста заголовков четырёх новых карточек-групп | — | +| #594 | [SPEC-REVIEW-594-r2.md](SPEC-REVIEW-594-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Раздел «i18n» ТЗ не называет ключи для текста заголовков четырёх новых карточек-групп (… | — | | #594 | [SPEC-REVIEW-594-r3.md](SPEC-REVIEW-594-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — | | #594 | [CODE-REVIEW-594-r1.md](CODE-REVIEW-594-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | AC7 не закрыт до конца — эталоны не приняты; отпечаток скриншотов документации не обновлён; AC1 доказан у́же, чем заявлено | `docs/images/screenshots.json` `test/form-kit.test.mjs` `demo/smoke_room_settings.mjs` `smoke_color_picker_consumers.mjs` `smoke_room_temperature_thresholds.mjs` | | #594 | [CODE-REVIEW-594-r2.md](CODE-REVIEW-594-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #594 | [CODE-REVIEW-594-r3.md](CODE-REVIEW-594-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | | #593 | [SPEC-REVIEW-593-r1.md](SPEC-REVIEW-593-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | Оба продуктовых решения (Р1 «кактус → plant», Р2 «при отказе чанка не рисуется ничего»)…; М1. AC9 и §7 заявляют защиту трёх бюджетов через npm run bundle:budget, но код гейта фа… | `PROCESS.md` `docs/FURNITURE.md` `scripts/bundle-manifest.mjs` `furniture-plan-art.generated.ts` `furniture-menu-art.generated.ts` `scripts/bundle-budget.mjs` | -| #593 | [SPEC-REVIEW-593-r2.md](SPEC-REVIEW-593-r2.md) | spec · r2 | 🔴 красный | 1 | 0 | (new). Раздел §3 Q3 и AC10 заявляют, что владелец «публично подтвердил... авторство и M… | `test/furniture-assets.test.mjs` `assets/furniture/houseplan-0.3.0/README.md` `pack.json` `LICENSE.md` `README.md` `assets/furniture/houseplan-0.3.0/pack.json` `PROCESS.md` | +| #593 | [SPEC-REVIEW-593-r2.md](SPEC-REVIEW-593-r2.md) | spec · r2 | 🔴 красный | 1 | 0 | Воспроизведение | `test/furniture-assets.test.mjs` `assets/furniture/houseplan-0.3.0/README.md` `pack.json` `LICENSE.md` `README.md` `assets/furniture/houseplan-0.3.0/pack.json` `PROCESS.md` | | #593 | [SPEC-REVIEW-593-r3.md](SPEC-REVIEW-593-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — | | #593 | [CODE-REVIEW-593-r1.md](CODE-REVIEW-593-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | docs/ARCHITECTURE.md не обновлён, хотя ТЗ явно называет это условием; сцена tray-narrow-palette-en меняется, но не объявлена в списке golden-приёмки | `docs/ARCHITECTURE.md` `docs/FURNITURE.md` `docs/images/screenshots.json` `demo/golden/matrix.mjs` `scripts/golden-acceptance.mjs` `artifacts/golden/golden-report.json` | | #593 | [CODE-REVIEW-593-r2.md](CODE-REVIEW-593-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -70,7 +75,7 @@ | #592 | [SPEC-REVIEW-592-r2.md](SPEC-REVIEW-592-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #592 | [CODE-REVIEW-592-r1.md](CODE-REVIEW-592-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | «перенесённая» строка в гейте no-new-any матчится по всему диффу, а не по паре файлов р…; Нет — все второстепенные наблюдения либо покрыты объяснением автора (device-icon-state-… | `scripts/no-new-any.mjs` `brand-new-feature.ts` `room-settings-dialog.ts` `space-settings-dialog.ts` `test/no-new-any.test.mjs` `test/houseplan-source.mjs` | | #592 | [CODE-REVIEW-592-r2.md](CODE-REVIEW-592-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #588 | [SPEC-REVIEW-588-r1.md](SPEC-REVIEW-588-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | М1. Три ветки пылесоса, явно включённые в скоуп, не имеют ни одного AC/теста/мутанта; М2. docs/USER-GUIDE.ru.md и docs/FILTERING.md описывают «подсветку убираемой комнаты» п…; Не найдено значимых Low-находок сверх М1/М2. Формулировка «чем краснеет» AC6 («правка л… | `src/houseplan-card.ts` `houseplan-card.ts` `test/device-presentation-policy.test.mjs` `smoke_static_icon.mjs` `device-value-badge.ts` `device-pulse.ts` `demo/smoke_static_icon.mjs` `docs/USER-GUIDE.ru.md` | +| #588 | [SPEC-REVIEW-588-r1.md](SPEC-REVIEW-588-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | М1. Три ветки пылесоса, явно включённые в скоуп, не имеют ни одного AC/теста/мутанта; М2. docs/USER-GUIDE.ru.md и docs/FILTERING.md описывают «подсветку убираемой комнаты» п… | `src/houseplan-card.ts` `houseplan-card.ts` `test/device-presentation-policy.test.mjs` `smoke_static_icon.mjs` `device-value-badge.ts` `device-pulse.ts` `demo/smoke_static_icon.mjs` `docs/USER-GUIDE.ru.md` | | #588 | [SPEC-REVIEW-588-r2.md](SPEC-REVIEW-588-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | Третий факт AC6 (отсутствие .vacwarn) не доказывается способом, который сам же AC6 назы…; Новых Low-находок в дельте не найдено. Low из r1 (нечёткость «чем краснеет» AC7/бывший … | `demo/smoke_static_icon.mjs` `src/vacuum-routes.ts` `demo/smoke_vacuum_multifloor.mjs` `smoke_vacuum_multifloor.mjs` | | #588 | [SPEC-REVIEW-588-r3.md](SPEC-REVIEW-588-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — | | #588 | [CODE-REVIEW-588-r1.md](CODE-REVIEW-588-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | docs/TESTING.md называет непроверяемую поверхность «PDF» | `docs/TESTING.md` `src/pdf/pdf-export.ts` `pdf-scene.ts` `src/pdf/pdf-scene.ts` `pdf-export.ts` `src/device-presentation.ts` | @@ -79,12 +84,12 @@ | #585 | [SPEC-REVIEW-585-r1.md](SPEC-REVIEW-585-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #585 | [CODE-REVIEW-585-r1.md](CODE-REVIEW-585-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | устаревшая строка docs/STATUS.md и отсутствующий хендофф evidence | `docs/STATUS.md` | | #585 | [CODE-REVIEW-585-r2.md](CODE-REVIEW-585-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #584 | [SPEC-REVIEW-584-r1.md](SPEC-REVIEW-584-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | влияние на touch не названо; 1. Раздел «UX» и «скоуп/не-скоуп» не оформлены отдельными заголовками | `docs/TOUCH-SUPPORT.md` | +| #584 | [SPEC-REVIEW-584-r1.md](SPEC-REVIEW-584-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | влияние на touch не названо; 1. Раздел «UX» и «скоуп/не-скоуп» не оформлены отдельными заголовками. Содержание по фа… | `docs/TOUCH-SUPPORT.md` | | #584 | [SPEC-REVIEW-584-r2.md](SPEC-REVIEW-584-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #584 | [CODE-REVIEW-584-r1.md](CODE-REVIEW-584-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | рост ленивого чанка furniture-plan-art.generated не назван числом, как того требует соб… | `scripts/bundle-budget.mjs` | | #584 | [CODE-REVIEW-584-r2.md](CODE-REVIEW-584-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #583 | [SPEC-REVIEW-583-r1.md](SPEC-REVIEW-583-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1, снята решением ревьюера с записью | — | -| #583 | [CODE-REVIEW-583-r1.md](CODE-REVIEW-583-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Золотой (golden) семантический контракт для iso-дверей не обновлён под новое | `demo/golden/run.mjs` `demo/golden/matrix.mjs` `src/iso-openings.ts` `test/iso-openings.test.mjs` `test/isometric-contract.test.mjs` `demo/smoke_isometric_contract.mjs` `matrix.mjs` | +| #583 | [CODE-REVIEW-583-r1.md](CODE-REVIEW-583-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Золотой (golden) семантический контракт для iso-дверей не обновлён под новое поведение … | `demo/golden/run.mjs` `demo/golden/matrix.mjs` `src/iso-openings.ts` `test/iso-openings.test.mjs` `test/isometric-contract.test.mjs` `demo/smoke_isometric_contract.mjs` `matrix.mjs` | | #583 | [CODE-REVIEW-583-r2.md](CODE-REVIEW-583-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | — | — | | #582 | [SPEC-REVIEW-582-r1.md](SPEC-REVIEW-582-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | AC5 не несёт собственного независимого доказательства (снято ревьюером) | `houseplan-card.ts` | | #582 | [CODE-REVIEW-582-r1.md](CODE-REVIEW-582-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — | — | @@ -92,21 +97,21 @@ | #582 | [CODE-REVIEW-582-r3.md](CODE-REVIEW-582-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | | #581 | [SPEC-REVIEW-581-r1.md](SPEC-REVIEW-581-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #581 | [CODE-REVIEW-581-r1.md](CODE-REVIEW-581-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #580 | [SPEC-REVIEW-580-r1.md](SPEC-REVIEW-580-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ не отвечает на несколько обязательных пунктов §7.1 / чек-листа DoR; Контракт п.4 использует немодальную формулировку («может оставаться | `docs/SCOPE.md` `PROCESS.md` `docs/TOUCH-SUPPORT.md` `docs/SUN.md` | +| #580 | [SPEC-REVIEW-580-r1.md](SPEC-REVIEW-580-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ не отвечает на несколько обязательных пунктов §7.1 / чек-листа DoR §2.5, оставляя их…; Контракт п.4 использует немодальную формулировку («может оставаться видимым»), которую … | `docs/SCOPE.md` `PROCESS.md` `docs/TOUCH-SUPPORT.md` `docs/SUN.md` | | #580 | [SPEC-REVIEW-580-r2.md](SPEC-REVIEW-580-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #580 | [CODE-REVIEW-580-r1.md](CODE-REVIEW-580-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #580 | [CODE-REVIEW-580-r2.md](CODE-REVIEW-580-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #579 | [SPEC-REVIEW-579-r1.md](SPEC-REVIEW-579-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #579 | [CODE-REVIEW-579-r1.md](CODE-REVIEW-579-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC4 (матрица day cycle/Glow/room fills/hatching/фон) не имеет тестового доказательства; AC2 не имеет именованного мутанта. У AC2 («бюджет сохранён») нет специального | `test/live-viewport.test.mjs` `demo/smoke_live_pan_coverage.mjs` `demo/screencast_visual_continuity.mjs` `demo/srv/demo.html` `src/houseplan-card.ts` | +| #579 | [CODE-REVIEW-579-r1.md](CODE-REVIEW-579-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC4 (матрица day cycle/Glow/room fills/hatching/фон) не имеет тестового доказательства; AC2 не имеет именованного мутанта. У AC2 («бюджет сохранён») нет специального MUTANT_DE… | `test/live-viewport.test.mjs` `demo/smoke_live_pan_coverage.mjs` `demo/screencast_visual_continuity.mjs` `demo/srv/demo.html` `src/houseplan-card.ts` | | #579 | [CODE-REVIEW-579-r2.md](CODE-REVIEW-579-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #578 | [SPEC-REVIEW-578-r1.md](SPEC-REVIEW-578-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | i18n закрыт только косвенно; сценарий «новый mouse pointerdown сразу после pinch» не назван явно ни в одном AC | `test/touch-gesture-click-guard.test.mjs` | | #578 | [CODE-REVIEW-578-r1.md](CODE-REVIEW-578-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #577 | [SPEC-REVIEW-577-r1.md](SPEC-REVIEW-577-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | раздел «Release-артефакты» не называет два документа, которые эта же задача обязана обн… | `docs/CHANGELOG.md` `.ru.md` `docs/SUN.md` `docs/USER-GUIDE.ru.md` `docs/TESTING.md` `docs/WALL-THICKNESS.md` `docs/CONFIG-COMPATIBILITY.md` `WALL-THICKNESS.md` | | #577 | [SPEC-REVIEW-577-r2.md](SPEC-REVIEW-577-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #577 | [CODE-REVIEW-577-r1.md](CODE-REVIEW-577-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC4 и AC7 объявляют доказательство golden, но ни один golden-сценарий и | `demo/golden/matrix.mjs` `demo/smoke_sun.mjs` `test/sun.test.mjs` | +| #577 | [CODE-REVIEW-577-r1.md](CODE-REVIEW-577-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC4 и AC7 объявляют доказательство golden, но ни один golden-сценарий и эталон для режи… | `demo/golden/matrix.mjs` `demo/smoke_sun.mjs` `test/sun.test.mjs` | | #577 | [CODE-REVIEW-577-r2.md](CODE-REVIEW-577-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #576 | [CODE-REVIEW-576-r1.md](CODE-REVIEW-576-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #573 | [CODE-REVIEW-573-r1.md](CODE-REVIEW-573-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | evaluateCiProof меняет поведение merge/review-потребителей без теста и | `scripts/ci-proof.mjs` `scripts/merge-candidate.mjs` `scripts/validate-gate.mjs` `validate.yml` `merge-candidate.mjs` `validate-gate.mjs` `test/ci-proof.test.mjs` `test/merge-candidate.test.mjs` | +| #573 | [CODE-REVIEW-573-r1.md](CODE-REVIEW-573-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | evaluateCiProof меняет поведение merge/review-потребителей без теста и вопреки утвержде… | `scripts/ci-proof.mjs` `scripts/merge-candidate.mjs` `scripts/validate-gate.mjs` `validate.yml` `merge-candidate.mjs` `validate-gate.mjs` `test/ci-proof.test.mjs` `test/merge-candidate.test.mjs` | | #573 | [CODE-REVIEW-573-r2.md](CODE-REVIEW-573-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #571 | [CODE-REVIEW-571-r1.md](CODE-REVIEW-571-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #570 | [SPEC-REVIEW-570-r1.md](SPEC-REVIEW-570-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | @@ -128,7 +133,7 @@ | #562 | [CODE-REVIEW-562-r1.md](CODE-REVIEW-562-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | task-packet.mjs определяет инфра-трек и право трогать класс A по тематической метке inf… | `task-packet.mjs` `PROCESS.md` `AGENTS.md` `scripts/process-gate.mjs` `process-gate.mjs` `test/task-packet.test.mjs` | | #562 | [CODE-REVIEW-562-r2.md](CODE-REVIEW-562-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | после фикса статусless infra-issue без опубликованной ветки получает заведомо неверную … | `scripts/task-packet.mjs` `AGENTS.md` `task-packet.mjs` `process-gate.mjs` `PROCESS.md` | | #562 | [CODE-REVIEW-562-r3.md](CODE-REVIEW-562-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | -| #561 | [SPEC-REVIEW-561-r1.md](SPEC-REVIEW-561-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ не называет явно влияние на touch/View/kiosk — обязательный, блокирующий; Разделы «сценарий» и «что человек увидит до/после» не оформлены отдельными | `docs/TOUCH-SUPPORT.md` | +| #561 | [SPEC-REVIEW-561-r1.md](SPEC-REVIEW-561-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ не называет явно влияние на touch/View/kiosk — обязательный, блокирующий пункт DoR (…; Разделы «сценарий» и «что человек увидит до/после» не оформлены отдельными подзаголовка… | `docs/TOUCH-SUPPORT.md` | | #561 | [SPEC-REVIEW-561-r2.md](SPEC-REVIEW-561-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — | — | | #561 | [CODE-REVIEW-561-r1.md](CODE-REVIEW-561-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #560 | [CODE-REVIEW-560-r1.md](CODE-REVIEW-560-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | process-gate даёт 1 предупреждение, а хендофф заявляет «предупреждений 0» | `scripts/process-gate.mjs` | @@ -140,7 +145,7 @@ | #555 | [CODE-REVIEW-555-r2.md](CODE-REVIEW-555-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #554 | [SPEC-REVIEW-554-r1.md](SPEC-REVIEW-554-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #554 | [CODE-REVIEW-554-r1.md](CODE-REVIEW-554-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #553 | [CODE-REVIEW-553-r2.md](CODE-REVIEW-553-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | Регрессионный тест #553 не защищает от отката формулировки, ради которого; Стале-цитата правила в §11.4 после правки формулировки §5 | `test/review-doc-guard.test.mjs` `PROCESS.md` `AGENTS.md` | +| #553 | [CODE-REVIEW-553-r2.md](CODE-REVIEW-553-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | Регрессионный тест #553 не защищает от отката формулировки, ради которого заведён; Стале-цитата правила в §11.4 после правки формулировки §5 | `test/review-doc-guard.test.mjs` `PROCESS.md` `AGENTS.md` | | #553 | [CODE-REVIEW-553-r3.md](CODE-REVIEW-553-r3.md) | code · r3 | 🟡 жёлтый | 0 | 0 | — | — | | #551 | [CODE-REVIEW-551-r1.md](CODE-REVIEW-551-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #551 | [CODE-REVIEW-551-r4.md](CODE-REVIEW-551-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — | — | @@ -159,9 +164,9 @@ | #543 | [CODE-REVIEW-543-r1.md](CODE-REVIEW-543-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #542 | [CODE-REVIEW-542-r1.md](CODE-REVIEW-542-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #541 | [CODE-REVIEW-541-r1.md](CODE-REVIEW-541-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #536 | [SPEC-REVIEW-536-r1.md](SPEC-REVIEW-536-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. «До/После» использует термин реализации. Формулировка «уходит тогда | — | +| #536 | [SPEC-REVIEW-536-r1.md](SPEC-REVIEW-536-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. «До/После» использует термин реализации. Формулировка «уходит тогда, когда контролле… | — | | #536 | [CODE-REVIEW-536-r1.md](CODE-REVIEW-536-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #535 | [SPEC-REVIEW-535-r1.md](SPEC-REVIEW-535-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. Не-скоуп не продублирован внутри ## ТЗ. Перечень «чего в этой задаче | — | +| #535 | [SPEC-REVIEW-535-r1.md](SPEC-REVIEW-535-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. Не-скоуп не продублирован внутри ## ТЗ. Перечень «чего в этой задаче нет» (формулиро… | — | | #535 | [CODE-REVIEW-535-r1.md](CODE-REVIEW-535-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | текст console.error панели изменён вопреки букве К2 ТЗ | `scripts/bundle-manifest.mjs` | | #534 | [SPEC-REVIEW-534-r1.md](SPEC-REVIEW-534-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ключевое техническое допущение К2/«Принято предположительно» №2 неверно, и это открывае…; «их единицы» (К3) неточно описывает число проёмов | `src/styles/devices.styles.ts` `demo/smoke_space_switch_transitions.mjs` `test/device-marker-polish-contract.test.mjs` `test/space-order.test.mjs` `test/device-face.test.mjs` | | #534 | [SPEC-REVIEW-534-r2.md](SPEC-REVIEW-534-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | К2 распространяет keyed+repeat на список проёмов «для единообразия», но обоснование (К3… | `src/styles/plan.styles.ts` `src/houseplan-card.ts` | @@ -213,7 +218,7 @@ | #514 | [SPEC-REVIEW-514-r1.md](SPEC-REVIEW-514-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #514 | [CODE-REVIEW-514-r1.md](CODE-REVIEW-514-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #514 | [CODE-REVIEW-514-r2.md](CODE-REVIEW-514-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #514 | [CODE-REVIEW-514-r3.md](CODE-REVIEW-514-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | фолбэк-токен E2E_DISPATCH_TOKEN, если он scoped только на houseplan-e2e, молча ломает p…; High не найдено. Medium вне скоупа не найдено — единственный Medium (M1) целиком внутри… | `release.yml` `scripts/e2e-gate.mjs` `e2e-gate.mjs` `.github/workflows/release.yml` `houseplan-e2e/e2e.yml` `e2e.yml` `validate-gate.mjs` `PROCESS.md` | +| #514 | [CODE-REVIEW-514-r3.md](CODE-REVIEW-514-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | фолбэк-токен E2E_DISPATCH_TOKEN, если он scoped только на houseplan-e2e, молча ломает p… | `release.yml` `scripts/e2e-gate.mjs` `e2e-gate.mjs` `.github/workflows/release.yml` `houseplan-e2e/e2e.yml` `e2e.yml` `validate-gate.mjs` `PROCESS.md` | | #514 | [CODE-REVIEW-514-r4.md](CODE-REVIEW-514-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | docs/specs/514-e2e-stable-release-gate.md:38 дословно цитирует старый текст TOKEN_HINT,… | `docs/specs/514-e2e-stable-release-gate.md` `scripts/e2e-gate.mjs` | | #513 | [CODE-REVIEW-513-r1.md](CODE-REVIEW-513-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | scripts/pre-push-gate.mjs продолжает называть полный мутационный реестр предрелизным ге… | `scripts/pre-push-gate.mjs` `mutation-gate.yml` `docs/TESTING.md` `pre-push-gate.mjs` `scripts/mutation-gate.mjs` `mutation-gate.mjs` | | #513 | [CODE-REVIEW-513-r2.md](CODE-REVIEW-513-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -227,13 +232,13 @@ | #510 | [SPEC-REVIEW-510-r2.md](SPEC-REVIEW-510-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | 1: проводка gate → красный-возврат / продолжение ревью использует в трёх соседних предл… | `docs/specs/510-mutants-on-candidate-and-review-waits-validate.md` | | #510 | [SPEC-REVIEW-510-r3.md](SPEC-REVIEW-510-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | 1: унификация «всё через proceed» ломает reuse-fast-path (#499) — деплой-зависимости, C… | `docs/specs/510-mutants-on-candidate-and-review-waits-validate.md` `process.yml` `test/review-doc-guard.test.mjs` | | #510 | [SPEC-REVIEW-510-r4.md](SPEC-REVIEW-510-r4.md) | spec · r4 | 🟢 зелёный | 0 | 0 | — | — | -| #510 | [CODE-REVIEW-510-r1.md](CODE-REVIEW-510-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Отменённый (cancelled) dispatch-прогон читается как красный, а не игнорируется — то же …; Не найдено требующих записи — единственная спорная деталь (M1) достаточно | `scripts/validate-gate.mjs` `scripts/merge-candidate.mjs` `validate.yml` `validate-gate.mjs` `test/validate-gate.test.mjs` `test/merge-candidate.test.mjs` `scripts/release-gate.mjs` | -| #510 | [CODE-REVIEW-510-r2.md](CODE-REVIEW-510-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | (новая, r2). Закрытие M1(r1) асимметрично: половина фикса в; Не найдено требующих записи | `scripts/merge-candidate.mjs` `test/merge-candidate.test.mjs` `merge-candidate.mjs` `scripts/validate-gate.mjs` | +| #510 | [CODE-REVIEW-510-r1.md](CODE-REVIEW-510-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Отменённый (cancelled) dispatch-прогон читается как красный, а не игнорируется — то же … | `scripts/validate-gate.mjs` `scripts/merge-candidate.mjs` `validate.yml` `validate-gate.mjs` `test/validate-gate.test.mjs` `test/merge-candidate.test.mjs` `scripts/release-gate.mjs` | +| #510 | [CODE-REVIEW-510-r2.md](CODE-REVIEW-510-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | Файл: scripts/merge-candidate.mjs:145 — waitValidate внутри realOps: js const runs = al… | `scripts/merge-candidate.mjs` `test/merge-candidate.test.mjs` `merge-candidate.mjs` `scripts/validate-gate.mjs` | | #510 | [CODE-REVIEW-510-r3.md](CODE-REVIEW-510-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | | #509 | [SPEC-REVIEW-509-r1.md](SPEC-REVIEW-509-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | отсутствует раздел «Принятые технические предположения» (PROCESS.md §7.1); контракт п.4 (прежнее значение при инвалидации мемо, без скелета) не доказан ни одним AC; критерий отказа от лёгкого трека не назван явно | `SPEC-REVIEW-505-r1.md` `docs/specs/493-...md` | | #509 | [SPEC-REVIEW-509-r2.md](SPEC-REVIEW-509-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | способ инъекции счётчика вызовов для AC3 остался неназванным | `wall-thickness.ts` | | #509 | [CODE-REVIEW-509-r1.md](CODE-REVIEW-509-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #508 | [SPEC-REVIEW-508-r1.md](SPEC-REVIEW-508-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | AC3 называет несуществующее доказательство: golden-сценариев summary- в; В ТЗ лёгкого трека нет раздела «откат»; Целевой файл документации для фразы про футер не определён; Влияние на производительность не названо явно | `demo/capture_summary_panel_505.mjs` `docs/UX-MODES.md` `docs/ARCHITECTURE.md` | +| #508 | [SPEC-REVIEW-508-r1.md](SPEC-REVIEW-508-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | AC3 называет несуществующее доказательство: golden-сценариев summary- в репозитории нет; В ТЗ лёгкого трека нет раздела «откат»; Целевой файл документации для фразы про футер не определён. Пункт 3 «Изменений» называе…; Влияние на производительность не названо явно. DoR (§2.5) требует явного «нет», если вл… | `demo/capture_summary_panel_505.mjs` `docs/UX-MODES.md` `docs/ARCHITECTURE.md` | | #508 | [SPEC-REVIEW-508-r2.md](SPEC-REVIEW-508-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #508 | [CODE-REVIEW-508-r1.md](CODE-REVIEW-508-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #508 | [CODE-REVIEW-508-r2.md](CODE-REVIEW-508-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -280,14 +285,14 @@ | #485 | [SPEC-REVIEW-485-r2.md](SPEC-REVIEW-485-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #485 | [SPEC-REVIEW-485-r3.md](SPEC-REVIEW-485-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | новый гейт видимости, по тексту, исключает ранее принятый адаптер «любой числовой сенсо… | `docs/specs/485-radar-presence-stage1.md` `stage1.md` `485-radar-presence.md` | | #485 | [SPEC-REVIEW-485-r4.md](SPEC-REVIEW-485-r4.md) | spec · r4 | 🟢 зелёный | 0 | 0 | — | — | -| #485 | [CODE-REVIEW-485-r1.md](CODE-REVIEW-485-r1.md) | code · r1 | 🔴 красный | 6 | 6 | «partial» не существует как состояние здоровья; смешанные и полностью; гонка teardown/await воскрешает HA-подписки после выгрузки интеграции; нет проверки «то же устройство» для верифицированного адаптера LD2450; «Настроить на плане» отказывает для комнаты без контура вместо; известные занятые зоны (zones_v1) никогда не рисуются на плане; смена HA-привязки маркера может молча удалить уже сохранённую | `custom_components/houseplan/radar.py` `__init__.py` `custom_components/houseplan/radar_validation.py` `radar.py` `src/editors/radar-section.ts` `radar-model.ts` `radar-editor.ts` `editors/radar-section.ts` | -| #485 | [CODE-REVIEW-485-r2.md](CODE-REVIEW-485-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | M-1 (продолжение M6 из r1, закрыто частично). Три из четырёх числовых гардов; чтению (src/editors/radar-section.ts:185-197, ключ radar.no_contour | `radar_geometry.py` `src/radar-geometry.ts` `test/radar-geometry.test.mjs` `radar_websocket.py` `test_ha_radar_websocket.py` `custom_components/houseplan/websocket_api.py` `docs/specs/485-radar-presence-stage1.md` `custom_components/houseplan/__init__.py` | -| #485 | [CODE-REVIEW-485-r3.md](CODE-REVIEW-485-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | M-1 (новая). Четвёртый числовой гвард двухточечного решателя | `custom_components/houseplan/radar_geometry.py` `src/radar-geometry.ts` | -| #485 | [CODE-REVIEW-485-r4.md](CODE-REVIEW-485-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | пусто). Не эскалирую третий раунд подряд по той же логике r2/r3: защитные | `radar.py` | +| #485 | [CODE-REVIEW-485-r1.md](CODE-REVIEW-485-r1.md) | code · r1 | 🔴 красный | 6 | 6 | «partial» не существует как состояние здоровья; смешанные и полностью устаревшие данные…; гонка teardown/await воскрешает HA-подписки после выгрузки интеграции. custom_component…; нет проверки «то же устройство» для верифицированного адаптера LD2450. custom_component…; «Настроить на плане» отказывает для комнаты без контура вместо предупреждения и незанят…; известные занятые зоны (zones_v1) никогда не рисуются на плане. grep -n "zone" src/rada…; смена HA-привязки маркера может молча удалить уже сохранённую, откалиброванную конфигур… | `custom_components/houseplan/radar.py` `__init__.py` `custom_components/houseplan/radar_validation.py` `radar.py` `src/editors/radar-section.ts` `radar-model.ts` `radar-editor.ts` `editors/radar-section.ts` | +| #485 | [CODE-REVIEW-485-r2.md](CODE-REVIEW-485-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | M-1 (продолжение M6 из r1, закрыто частично). Три из четырёх числовых гардов калибровоч…; Фикс H4 (комната без контура открывает мастер с предупреждением) корректен по чтению (s… | `radar_geometry.py` `src/radar-geometry.ts` `test/radar-geometry.test.mjs` `radar_websocket.py` `test_ha_radar_websocket.py` `custom_components/houseplan/websocket_api.py` `docs/specs/485-radar-presence-stage1.md` `custom_components/houseplan/__init__.py` | +| #485 | [CODE-REVIEW-485-r3.md](CODE-REVIEW-485-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | M-1 (новая). Четвёртый числовой гвард двухточечного решателя — согласованность радиальн… | `custom_components/houseplan/radar_geometry.py` `src/radar-geometry.ts` | +| #485 | [CODE-REVIEW-485-r4.md](CODE-REVIEW-485-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | Нет golden-сцены для радара (find demo/golden -iname "radar" — по-прежнему пусто). Не э… | `radar.py` | | #484 | [SPEC-REVIEW-484-r1.md](SPEC-REVIEW-484-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #484 | [CODE-REVIEW-484-r1.md](CODE-REVIEW-484-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #483 | [CODE-REVIEW-483-r1.md](CODE-REVIEW-483-r1.md) | code · r1 | ⚪ — | 0 | 0 | — | — | -| #482 | [SPEC-REVIEW-482-r1.md](SPEC-REVIEW-482-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | источник и лицензия векторного компаса заявлены как факт без | `docs/specs/482-pdf-export-polish.md` `docs/FURNITURE.md` `docs/PDF-EXPORT.md` `SPEC-REVIEW-159-r1.md` | +| #482 | [SPEC-REVIEW-482-r1.md](SPEC-REVIEW-482-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | источник и лицензия векторного компаса заявлены как факт без проверяемой цитаты, аналог… | `docs/specs/482-pdf-export-polish.md` `docs/FURNITURE.md` `docs/PDF-EXPORT.md` `SPEC-REVIEW-159-r1.md` | | #482 | [SPEC-REVIEW-482-r2.md](SPEC-REVIEW-482-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #482 | [CODE-REVIEW-482-r1.md](CODE-REVIEW-482-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #481 | [SPEC-REVIEW-481-r1.md](SPEC-REVIEW-481-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | в скоупе задачи, чинится в этом же issue; снимаю с записью, не блокирует | `validate.yml` `test/mutation-gate.test.mjs` `test/validate-workflow.test.mjs` | @@ -301,7 +306,7 @@ | #477 | [CODE-REVIEW-477-r1.md](CODE-REVIEW-477-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #476 | [SPEC-REVIEW-476-r1.md](SPEC-REVIEW-476-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | §18 противоречит §7.3/AC4; §7.2 нумерованный список читается как безусловный | `docs/specs/476-color-picker-ok.md` `hp-color-opacity.ts` | | #476 | [SPEC-REVIEW-476-r2.md](SPEC-REVIEW-476-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #476 | [CODE-REVIEW-476-r1.md](CODE-REVIEW-476-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | AC4: защита от обхода невалидного HEX повторным «ОК» не имеет постоянного; AC3/§7.2.4: заявленная защита «клик не проваливается в план/toolbar под; (git diff слепил две записи объекта). Чисто косметика, синтаксис и typecheck | `scripts/mutation-gate.mjs` `SPEC-REVIEW-476-r1.md` `demo/smoke_color_picker.mjs` `scripts/smoke-links.mjs` `src/houseplan-card.ts` | +| #476 | [CODE-REVIEW-476-r1.md](CODE-REVIEW-476-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | AC4: защита от обхода невалидного HEX повторным «ОК» не имеет постоянного свидетеля в s…; AC3/§7.2.4: заявленная защита «клик не проваливается в план/toolbar под поверхностью» н…; src/houseplan-card.ts:5932 — invalidHex: …, confirm: … на одной строке (git diff слепил… | `scripts/mutation-gate.mjs` `SPEC-REVIEW-476-r1.md` `demo/smoke_color_picker.mjs` `scripts/smoke-links.mjs` `src/houseplan-card.ts` | | #476 | [CODE-REVIEW-476-r2.md](CODE-REVIEW-476-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #476 | [CODE-REVIEW-476-r3.md](CODE-REVIEW-476-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | | #475 | [SPEC-REVIEW-475-r1.md](SPEC-REVIEW-475-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | job и guardFiles() не покрывают гарды бэкенда, хотя они уже есть в реестре | `.test.mjs` `scripts/mutation-gate.mjs` `custom_components/houseplan/frontend_registration.py` `tests_backend/test_ha_frontend_registration.py` `mutation-gate.mjs` `.github/workflows/validate.yml` `src/wall-merge.ts` | @@ -330,8 +335,8 @@ | #462 | [SPEC-REVIEW-462-r2.md](SPEC-REVIEW-462-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | новый контракт lovelace.resource_mode: yaml не подтверждён и; числовой touch-target 44×44; SHA не назван в вердикт-комментарии r1 | `SPEC-REVIEW-462-r1.md` | | #462 | [SPEC-REVIEW-462-r3.md](SPEC-REVIEW-462-r3.md) | spec · r3 | 🔴 красный | 1 | 0 | — | — | | #462 | [CODE-REVIEW-462-r1.md](CODE-REVIEW-462-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | 1 Backend (AC2, AC3, AC4, AC5, AC11); 2 Frontend (AC6–AC10, AC12); 3 Документация (AC1) и артефакты сборки (AC13) | — | -| #461 | [SPEC-REVIEW-461-r1.md](SPEC-REVIEW-461-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. §9.3, formula несогласованность между двумя scaling-проверками не | — | -| #461 | [CODE-REVIEW-461-r1.md](CODE-REVIEW-461-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC4 заявляет метод доказательства «unit + mutation witness» для; §6.4 против фактической обработки !safe в commitDraftSegmentGeometry | `scripts/mutation-gate.mjs` `test/draft-live-preflight.test.mjs` `test/wall-union-isolation.test.mjs` `demo/smoke_wall_draw_click.mjs` `smoke_junction_limits.mjs` `smoke_wall_junctions.mjs` `smoke_multiwall_junction.mjs` `smoke_near_orthogonal_junction.mjs` | +| #461 | [SPEC-REVIEW-461-r1.md](SPEC-REVIEW-461-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. §9.3, formula несогласованность между двумя scaling-проверками не объяснена одной фр… | — | +| #461 | [CODE-REVIEW-461-r1.md](CODE-REVIEW-461-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC4 заявляет метод доказательства «unit + mutation witness» для «verdict fast/full совп…; §6.4 против фактической обработки !safe в commitDraftSegmentGeometry | `scripts/mutation-gate.mjs` `test/draft-live-preflight.test.mjs` `test/wall-union-isolation.test.mjs` `demo/smoke_wall_draw_click.mjs` `smoke_junction_limits.mjs` `smoke_wall_junctions.mjs` `smoke_multiwall_junction.mjs` `smoke_near_orthogonal_junction.mjs` | | #461 | [CODE-REVIEW-461-r2.md](CODE-REVIEW-461-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #460 | [SPEC-REVIEW-460-r1.md](SPEC-REVIEW-460-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #460 | [CODE-REVIEW-460-r1.md](CODE-REVIEW-460-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | @@ -343,7 +348,7 @@ | #457 | [CODE-REVIEW-457-r1.md](CODE-REVIEW-457-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | нормализация relationship отступает от принятого ТЗ §6.3; доказательство AC9 неполно: нет browser-smoke на аспектах/zoom | `src/zigbee-topology.ts` `test/zigbee-topology.test.mjs` `demo/smoke_zigbee_topology_hover.mjs` `src/live-viewport.ts` `zigbee-topology-overlay-bridge.ts` | | #457 | [CODE-REVIEW-457-r2.md](CODE-REVIEW-457-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #456 | [SPEC-REVIEW-456-r1.md](SPEC-REVIEW-456-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #456 | [CODE-REVIEW-456-r1.md](CODE-REVIEW-456-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | 1 Дешёвые гейты (гоняю сам — зелёного Validate на этом SHA нет); 2 Живой браузерный прогон новой фичи (нет закоммиченного смока — см. M3); check-docs.mjs красный: отпечаток скриншотов устарел; golden:verify красный: footer диалога пространства изменился, эталон не обновлён; заявленный в ТЗ browser smoke для Copy отсутствует; Фокус поля имени при возврате из отменённого Optimize-warning (§6.2, §11 | `check-docs.mjs` `docs/images/screenshots.json` `space-copy.ts` `space-copy-runtime.ts` `plan-optimize-write.ts` `space-dialog.ts` `houseplan-editor-runtime.ts` `houseplan-card.ts` | +| #456 | [CODE-REVIEW-456-r1.md](CODE-REVIEW-456-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | 1 Дешёвые гейты (гоняю сам — зелёного Validate на этом SHA нет); 2 Живой браузерный прогон новой фичи (нет закоммиченного смока — см. M3); check-docs.mjs красный: отпечаток скриншотов устарел; golden:verify красный: footer диалога пространства изменился, эталон не обновлён; заявленный в ТЗ browser smoke для Copy отсутствует; Фокус поля имени при возврате из отменённого Optimize-warning (§6.2, §11: «при возврате… | `check-docs.mjs` `docs/images/screenshots.json` `space-copy.ts` `space-copy-runtime.ts` `plan-optimize-write.ts` `space-dialog.ts` `houseplan-editor-runtime.ts` `houseplan-card.ts` | | #456 | [CODE-REVIEW-456-r2.md](CODE-REVIEW-456-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | 1 Дешёвые гейты — прогнаны заново (код изменился, стоят минуты); 2 Гейты, закрывающие находки r1 — прогнаны целиком (не только для проверки на слово авт…; 3 Не прогонялось повторно — обосновано в §5 «Унаследовано» | — | | #454 | [SPEC-REVIEW-454-r1.md](SPEC-REVIEW-454-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | AC2 не доказуем тем способом, который сам называет; нет явных разделов «UX» и «i18n»; cohesion review-doc-guard.mjs | `SPEC-REVIEW-449-r1.md` `-r2.md` `-r1.md` `PROCESS.md` `review-doc-guard.mjs` `scripts/review-doc-guard.mjs` `scripts/review-round-counter.mjs` | | #454 | [SPEC-REVIEW-454-r2.md](SPEC-REVIEW-454-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -356,13 +361,13 @@ | #451 | [CODE-REVIEW-451-r3.md](CODE-REVIEW-451-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | не заявленный в ТЗ постоянный отказ от live-preflight на больших планах, противоречит с… | `src/resize-controller.ts` `src/houseplan-editor-runtime.ts` `demo/fixtures/large-house.mjs` `docs/CHANGELOG.md` `.ru.md` | | #451 | [CODE-REVIEW-451-r4.md](CODE-REVIEW-451-r4.md) | code · r4 | 🟡 жёлтый | 0 | 1 | локальный кандидат для physical-geometry исключает соседнюю комнату, от которой зависит… | `src/resize-live-preflight.ts` `src/houseplan-editor-runtime.ts` `test/fixtures/278-wall-union-isolation.json` `test/resize-controller.test.mjs` `demo/benchmark_large_house.mjs` `smoke_room_resize.mjs` | | #450 | [CODE-REVIEW-450-r1.md](CODE-REVIEW-450-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #449 | [SPEC-REVIEW-449-r1.md](SPEC-REVIEW-449-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | Строка Touch editor: not exposed, закрывающая M1, называет; / Low | `docs/specs/449-double-fit-all.md` `docs/USER-GUIDE.ru.md` `docs/UX-MODES.md` `scripts/check-docs.mjs` | +| #449 | [SPEC-REVIEW-449-r1.md](SPEC-REVIEW-449-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | Строка Touch editor: not exposed, закрывающая M1, называет несуществующий четвёртый ред…; / Low | `docs/specs/449-double-fit-all.md` `docs/USER-GUIDE.ru.md` `docs/UX-MODES.md` `scripts/check-docs.mjs` | | #449 | [SPEC-REVIEW-449-r2.md](SPEC-REVIEW-449-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #449 | [CODE-REVIEW-449-r1.md](CODE-REVIEW-449-r1.md) | code · r1 | 🔴 красный | 3 | 3 | custom_components/houseplan/frontend/ не синхронизирован с dist/: пользователь не получ…; docs-гейт красный: скрипты не пересняты после правки src/; заявленное доказательство AC3 красное: demo/smoke_kiosk_pan_lock.mjs; bundle budget: запас ушёл ниже шумовой полосы; мутант room-fit-enters-kiosk-double-tap-sequence больше ничего не ловит; ТЗ (AC5) обещает «targeted production-bundle smoke для device, opening и room | `dist/houseplan-assets/houseplan-card-CbNfZuwV.js` `custom_components/houseplan/frontend/houseplan-assets/houseplan-card-BgNWi9NC.js` `test/bundle-tree-committed.test.mjs` `test/release-contract.test.mjs` `dist/houseplan-card.js` `src/houseplan-card.ts` `src/room-fit.ts` `demo/smoke_kiosk_pan_lock.mjs` | +| #449 | [CODE-REVIEW-449-r1.md](CODE-REVIEW-449-r1.md) | code · r1 | 🔴 красный | 3 | 3 | custom_components/houseplan/frontend/ не синхронизирован с dist/: пользователь не получ…; docs-гейт красный: скрипты не пересняты после правки src/; заявленное доказательство AC3 красное: demo/smoke_kiosk_pan_lock.mjs; $ npm test → not ok: "#438 полоса шире наблюдаемого шума метрики" error: 'сверху меньше…; bundle budget: запас ушёл ниже шумовой полосы; мутант room-fit-enters-kiosk-double-tap-sequence больше ничего не ловит | `dist/houseplan-assets/houseplan-card-CbNfZuwV.js` `custom_components/houseplan/frontend/houseplan-assets/houseplan-card-BgNWi9NC.js` `test/bundle-tree-committed.test.mjs` `test/release-contract.test.mjs` `dist/houseplan-card.js` `src/houseplan-card.ts` `src/room-fit.ts` `demo/smoke_kiosk_pan_lock.mjs` | | #449 | [CODE-REVIEW-449-r2.md](CODE-REVIEW-449-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #448 | [SPEC-REVIEW-448-r1.md](SPEC-REVIEW-448-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ не закрывает обязательный пункт DoR «влияние на touch» (docs/TOUCH-SUPPORT.md) | `docs/TOUCH-SUPPORT.md` `docs/specs/448-alpha-switch.md` `src/houseplan-card.ts` | | #448 | [SPEC-REVIEW-448-r2.md](SPEC-REVIEW-448-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #448 | [CODE-REVIEW-448-r1.md](CODE-REVIEW-448-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | docs/RELEASE-NOTES.md потерял пункт #447 в обеих секциях; AGENTS.md §«Labs flags» не обновлён и описывает контракт, которого больше нет; Не найдено сверх M1/M2 | `docs/RELEASE-NOTES.md` `docs/DEVELOPMENT.md` `AGENTS.md` `src/labs.ts` `docs/ISOMETRIC.md` `docs/STATUS.md` | +| #448 | [CODE-REVIEW-448-r1.md](CODE-REVIEW-448-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | docs/RELEASE-NOTES.md потерял пункт #447 в обеих секциях; AGENTS.md §«Labs flags» не обновлён и описывает контракт, которого больше нет | `docs/RELEASE-NOTES.md` `docs/DEVELOPMENT.md` `AGENTS.md` `src/labs.ts` `docs/ISOMETRIC.md` `docs/STATUS.md` | | #448 | [CODE-REVIEW-448-r2.md](CODE-REVIEW-448-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #447 | [SPEC-REVIEW-447-r1.md](SPEC-REVIEW-447-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | AC4 и §3 путают единицы «шага сетки»: render-space gridPitch vs normalised GRID_STEP_N,… | `docs/specs/447-exterior-furniture-snap-keyboard-nudge.md` `src/space-geometry.ts` `space-render.ts` `houseplan-card.ts` `src/houseplan-editor-runtime.ts` | | #447 | [SPEC-REVIEW-447-r2.md](SPEC-REVIEW-447-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -379,7 +384,7 @@ | #440 | [SPEC-REVIEW-440-r1.md](SPEC-REVIEW-440-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #440 | [CODE-REVIEW-440-r1.md](CODE-REVIEW-440-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | предсуществующий (не #440) неточный мутант, вне блокировки | `scripts/mutation-gate.mjs` | | #439 | [CODE-REVIEW-439-r1.md](CODE-REVIEW-439-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #437 | [SPEC-REVIEW-437-r1.md](SPEC-REVIEW-437-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Раздел 10 «i18n и визуальное соответствие» пропускает французскую; Термин viewAllowed в формуле §5.3 не введён явно; Систематически пропущены пробелы перед числами в ряде мест текста | `docs/specs/437-summary-panel.md` `src/i18n/fr.json` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `docs/USER-GUIDE.ru.md` `CONTRIBUTING.md` | +| #437 | [SPEC-REVIEW-437-r1.md](SPEC-REVIEW-437-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Раздел 10 «i18n и визуальное соответствие» пропускает французскую локаль, которая являе…; Термин viewAllowed в формуле §5.3 не введён явно; Систематически пропущены пробелы перед числами в ряде мест текста | `docs/specs/437-summary-panel.md` `src/i18n/fr.json` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `docs/USER-GUIDE.ru.md` `CONTRIBUTING.md` | | #437 | [SPEC-REVIEW-437-r2.md](SPEC-REVIEW-437-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #437 | [CODE-REVIEW-437-r1.md](CODE-REVIEW-437-r1.md) | code · r1 | 🟡 жёлтый | 0 | 4 | существующий смок demo/smoke_kiosk.mjs падает необработанным исключением на этом SHA; исключение «удалённого устройства» в подсчёте Q2 не имеет свидетеля; tap-target реордер/удаления в форме настроек меньше заявленных 44×44 CSS px; идентичность карточки (AC21) не имеет ни выделенного резолвера, ни свидетеля теста | `demo/smoke_kiosk.mjs` `src/houseplan-card.ts` `scripts/smoke-select.mjs` `src/summary-panel-metrics.ts` `test/summary-panel.test.mjs` `src/summary-panel-style.ts` `summary-panel-editor.ts` `docs/TOUCH-SUPPORT.md` | | #437 | [CODE-REVIEW-437-r2.md](CODE-REVIEW-437-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | регресс восстановления камеры View при возврате из редактора, унаследован из r1-материа…; prepareCameraCommand, bootSoftCancel, stagePointerDown (houseplan-card.ts) объединяют п…; та же строка import { measuredCardHeaderHeight, settleSoftStageLayout } from './boot-so…; src/summary-panel-identity.ts: structuralPath() по-прежнему строит идентичность через c… | `demo/smoke_zoom_out.mjs` `docs/houseplan-card.ts` `smoke_zoom_out.mjs` `houseplan-editor-runtime.ts` `src/boot-soft-layout.ts` `houseplan-card.ts` `src/summary-panel-identity.ts` | @@ -411,7 +416,7 @@ | #421 | [SPEC-REVIEW-421-r2.md](SPEC-REVIEW-421-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #421 | [CODE-REVIEW-421-r1.md](CODE-REVIEW-421-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #420 | [CODE-REVIEW-420-r1.md](CODE-REVIEW-420-r1.md) | code · r1 | ⚪ — | 0 | 0 | — | — | -| #419 | [SPEC-REVIEW-419-r1.md](SPEC-REVIEW-419-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | Формулировка «Full import/export и space-only import сохраняют; Контракт «второе подтверждение» (§3 п.4, AC6) и «ровно один | `CONFIG-COMPATIBILITY.md` | +| #419 | [SPEC-REVIEW-419-r1.md](SPEC-REVIEW-419-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | Формулировка «Full import/export и space-only import сохраняют контракты #126 без измен…; Контракт «второе подтверждение» (§3 п.4, AC6) и «ровно один confirmation refresh» (AC9)… | `CONFIG-COMPATIBILITY.md` | | #419 | [CODE-REVIEW-419-r1.md](CODE-REVIEW-419-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #418 | [SPEC-REVIEW-418-r1.md](SPEC-REVIEW-418-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | нет отдельных разделов «Сценарий» и «Что человек увидит до/после» (waived) | `PROCESS.md` `docs/SCOPE.md` | | #418 | [CODE-REVIEW-418-r1.md](CODE-REVIEW-418-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | @@ -435,8 +440,8 @@ | #402 | [SPEC-REVIEW-402-r2.md](SPEC-REVIEW-402-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | Число в цитате TOUCH-SUPPORT.md неверно; Явного упоминания touch-статуса пяти вызовов из houseplan-editor-runtime.ts по-прежнему… | `docs/specs/402-confirm-outside-main-branch.md` `docs/TOUCH-SUPPORT.md` `houseplan-editor-runtime.ts` | | #402 | [CODE-REVIEW-402-r1.md](CODE-REVIEW-402-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | AC2 не покрыт смоком буквально (ветки fixed_floor pending/invalid, !space); AC3 не проверен буквальным сценарием issue (клик по корзине → deleteServerPlan); AC8: тап по scrim не проверен явно; confirmDanger не проверяет языковой гейт warm явно | `smoke_danger_confirm_branches.mjs` `src/houseplan-card.ts` `houseplan-onboarding-runtime.ts` `houseplan-card.ts` `smoke_danger_confirmation.mjs` `src/i18n/language-runtime.ts` | | #400 | [SPEC-REVIEW-400-r1.md](SPEC-REVIEW-400-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #400 | [CODE-REVIEW-400-r1.md](CODE-REVIEW-400-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Мутант furniture-edge-handles-steal-the-corner не воспроизводит регрессию, которую обяз…; AC4 доказан не тем видом теста, что назван в ТЗ; Число «2 654 Б gzip» для 38 help-строк в docs/ARCHITECTURE.md не | `scripts/mutation-gate.mjs` `src/houseplan-card.ts` `.github/workflows/mutation-gate.yml` `test/align-candidates.test.mjs` `demo/smoke_align_guides.mjs` `docs/ARCHITECTURE.md` | -| #400 | [CODE-REVIEW-400-r2.md](CODE-REVIEW-400-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | (перенесена из r1, не закрыта). Мутационный гейт | `src/houseplan-card.ts` `smoke_furniture.mjs` | +| #400 | [CODE-REVIEW-400-r1.md](CODE-REVIEW-400-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Мутант furniture-edge-handles-steal-the-corner не воспроизводит регрессию, которую обяз…; AC4 доказан не тем видом теста, что назван в ТЗ; Число «2 654 Б gzip» для 38 help-строк в docs/ARCHITECTURE.md не перепроверено независимо | `scripts/mutation-gate.mjs` `src/houseplan-card.ts` `.github/workflows/mutation-gate.yml` `test/align-candidates.test.mjs` `demo/smoke_align_guides.mjs` `docs/ARCHITECTURE.md` | +| #400 | [CODE-REVIEW-400-r2.md](CODE-REVIEW-400-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | Дополнительно к находке r1: комментарий автора от 2026-08-31T05:14:07Z заявляет закрыти… | `src/houseplan-card.ts` `smoke_furniture.mjs` | | #400 | [CODE-REVIEW-400-r3.md](CODE-REVIEW-400-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | | #399 | [SPEC-REVIEW-399-r1.md](SPEC-REVIEW-399-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | «План автотестов» (п.4) не обновлён вслед за AC5 и описывает как раз ту слабую версию, … | `docs/specs/399-backend-gate-honesty.md` `validate.yml` `mutation-gate.yml` | | #399 | [SPEC-REVIEW-399-r2.md](SPEC-REVIEW-399-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -460,8 +465,8 @@ | #391 | [CODE-REVIEW-391-r2.md](CODE-REVIEW-391-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #390 | [CODE-REVIEW-390-r1.md](CODE-REVIEW-390-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | Утверждение в сообщении коммита неверно | — | | #389 | [CODE-REVIEW-389-r1.md](CODE-REVIEW-389-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #385 | [SPEC-REVIEW-385-r1.md](SPEC-REVIEW-385-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Контракт (в) описывает предикат isRelease неполно, что рискует; «План автотестов» ссылается на несуществующий тестовый паттерн; DoR-примечание не называет явно влияние на производительность; Формулировка «(б)–(г) — «мелкие уточнения»» в Release-артефактах | `docs/specs/385-audit-lows.md` `scripts/process-gate.mjs` `AGENTS.md` `src/houseplan-editor-runtime.ts` `src/houseplan-card.ts` | -| #385 | [SPEC-REVIEW-385-r2.md](SPEC-REVIEW-385-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | Абзац-обоснование перед «Контрактом» (в) сохраняет старую неточную | `docs/specs/385-audit-lows.md` | +| #385 | [SPEC-REVIEW-385-r1.md](SPEC-REVIEW-385-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Контракт (в) описывает предикат isRelease неполно, что рискует разойтись с AC4; «План автотестов» ссылается на несуществующий тестовый паттерн. Текст: «паттерн существ…; DoR-примечание не называет явно влияние на производительность. PROCESS.md §2.5 требует …; Формулировка «(б)–(г) — «мелкие уточнения»» в Release-артефактах двусмысленна. Раздел U… | `docs/specs/385-audit-lows.md` `scripts/process-gate.mjs` `AGENTS.md` `src/houseplan-editor-runtime.ts` `src/houseplan-card.ts` | +| #385 | [SPEC-REVIEW-385-r2.md](SPEC-REVIEW-385-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | Абзац-обоснование перед «Контрактом» (в) сохраняет старую неточную формулировку предика… | `docs/specs/385-audit-lows.md` | | #385 | [CODE-REVIEW-385-r1.md](CODE-REVIEW-385-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #385 | [CODE-REVIEW-385-r2.md](CODE-REVIEW-385-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — | — | | #385 | [CODE-REVIEW-385-r3.md](CODE-REVIEW-385-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | @@ -512,9 +517,9 @@ | #362 | [CODE-REVIEW-362-r1.md](CODE-REVIEW-362-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | верифицировано чтением, фикс не требуется | `src/houseplan-card.ts` `smoke_decor.mjs` `dialogs.styles.ts` `plan.styles.ts` | | #361 | [SPEC-REVIEW-361-r1.md](SPEC-REVIEW-361-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | план автотестов противоречит порядку гейтов из AGENTS.md | `AGENTS.md` `docs/specs/361-furniture-stroke-zoom.md` `demo/smoke_furniture.mjs` | | #361 | [SPEC-REVIEW-361-r2.md](SPEC-REVIEW-361-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #361 | [CODE-REVIEW-361-r1.md](CODE-REVIEW-361-r1.md) | code · r1 | ⚪ — | 0 | 1 | Golden-бейзлайны с реальной мебелью не обновлены под новый физический stroke; npm run | `.github/workflows/validate.yml` `demo/golden/matrix.mjs` | +| #361 | [CODE-REVIEW-361-r1.md](CODE-REVIEW-361-r1.md) | code · r1 | ⚪ — | 0 | 1 | Golden-бейзлайны с реальной мебелью не обновлены под новый физический stroke; npm run g… | `.github/workflows/validate.yml` `demo/golden/matrix.mjs` | | #361 | [CODE-REVIEW-361-r2.md](CODE-REVIEW-361-r2.md) | code · r2 | ⚪ — | 0 | 0 | — | — | -| #360 | [SPEC-REVIEW-360-r1.md](SPEC-REVIEW-360-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | не назван обязательный touch-статус фичи; не описано, что сохранение свойств уже существующего объекта; Не найдено содержательных Low-находок сверх названных Medium; текст ТЗ | `docs/TOUCH-SUPPORT.md` `houseplan-editor-runtime.ts` | +| #360 | [SPEC-REVIEW-360-r1.md](SPEC-REVIEW-360-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | не назван обязательный touch-статус фичи. docs/TOUCH-SUPPORT.md (раздел «Documentation …; не описано, что сохранение свойств уже существующего объекта перезаписывает тот же deco… | `docs/TOUCH-SUPPORT.md` `houseplan-editor-runtime.ts` | | #360 | [SPEC-REVIEW-360-r2.md](SPEC-REVIEW-360-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #360 | [CODE-REVIEW-360-r1.md](CODE-REVIEW-360-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #360 | [CODE-REVIEW-360-r2.md](CODE-REVIEW-360-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -534,16 +539,16 @@ | #353 | [SPEC-REVIEW-353-r2.md](SPEC-REVIEW-353-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | , снято с запиской] AC5 не проговаривает, что структурная проверка обязана отличать «па… | `test/houseplan-source.mjs` | | #353 | [CODE-REVIEW-353-r1.md](CODE-REVIEW-353-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #348 | [SPEC-REVIEW-348-r1.md](SPEC-REVIEW-348-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | de-CH унаследует «ß», хотя стандартная швейцарская орфография его не использует; явного блока «принято предположительно, поменять свободно» в конце документа нет | `docs/specs/348-german-localization.md` | -| #348 | [CODE-REVIEW-348-r1.md](CODE-REVIEW-348-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC8 не имеет обещанного в ТЗ smoke-доказательства «нет overflow»; src/i18n/language-runtime.ts определяет полноценный переиспользуемый класс; Initial View budget после follow-up-коммита — 255 986 / 256 000 B gzip, запас; scripts/bundle-manifest.mjs: классификация editorRoots/onboardingRoots/; Удалённые из en.json/ru.json ключи (title.add_device, title.show_all | `docs/specs/348-german-localization.md` `demo/smoke_dialog_footer_width.mjs` `demo/smoke_german_locale.mjs` `smoke_dialog_footer_width.mjs` `smoke_german_locale.mjs` `src/i18n/language-runtime.ts` `test/i18n-runtime.test.mjs` `src/i18n/registry.ts` | +| #348 | [CODE-REVIEW-348-r1.md](CODE-REVIEW-348-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | AC8 не имеет обещанного в ТЗ smoke-доказательства «нет overflow». docs/specs/348-german…; src/i18n/language-runtime.ts определяет полноценный переиспользуемый класс LanguageRunt…; Initial View budget после follow-up-коммита — 255 986 / 256 000 B gzip, запас 14 байт и…; scripts/bundle-manifest.mjs: классификация editorRoots/onboardingRoots/ localeRoots сме…; Удалённые из en.json/ru.json ключи (title.add_device, title.show_all, title.markup_open… | `docs/specs/348-german-localization.md` `demo/smoke_dialog_footer_width.mjs` `demo/smoke_german_locale.mjs` `smoke_dialog_footer_width.mjs` `smoke_german_locale.mjs` `src/i18n/language-runtime.ts` `test/i18n-runtime.test.mjs` `src/i18n/registry.ts` | | #348 | [CODE-REVIEW-348-r2.md](CODE-REVIEW-348-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #341 | [CODE-REVIEW-341-r1.md](CODE-REVIEW-341-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #340 | [SPEC-REVIEW-340-r1.md](SPEC-REVIEW-340-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | заведён отдельный issue; не блокирует, отмечено с решением «оставить как есть» | `custom_components/houseplan/websocket_api.py` `tests_backend/test_ha_websocket.py` `docs/TESTING.md` `docs/ARCHITECTURE.md` `docs/specs/340-config-set-revision.md` | | #340 | [CODE-REVIEW-340-r1.md](CODE-REVIEW-340-r1.md) | code · r1 | ⚪ — | 0 | 0 | — | — | | #339 | [CODE-REVIEW-339-r1.md](CODE-REVIEW-339-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #337 | [SPEC-REVIEW-337-r1.md](SPEC-REVIEW-337-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #337 | [CODE-REVIEW-337-r1.md](CODE-REVIEW-337-r1.md) | code · r1 | 🔴 красный | 5 | 3 | Warm-remount коммитит editor mode в обход loader-гейта — падения на; Kiosk-контролы, явно названные в принятом ТЗ eager (§6.3: «kiosk; Безопасность resize «fail-closed» сломана: принудительный отказ; Стрелочная навигация по вкладкам инвентаря устройств падает с; Визуальная порча вторичного тулбара Device editor + 3 неподтверждённых; Два существующих smoke ожидают, что houseplan-card-editor уже | `src/houseplan-card.ts` `docs/WARM-REMOUNT.md` `demo/smoke_preloader_lifecycle.mjs` `demo/smoke_warm_dialogs.mjs` `demo/smoke_warm_owners.mjs` `docs/SCOPE.md` `demo/smoke_kiosk.mjs` `demo/smoke_room_resize.mjs` | -| #337 | [CODE-REVIEW-337-r2.md](CODE-REVIEW-337-r2.md) | code · r2 | 🔴 красный | 2 | 1 | Warm-remount editor-камера теряет бит-точность — визуальный «прыжок»; фикс устранил исключение, но обнажил под ним ещё один, ранее не наблюдаемый; (→ [#346](https://github.com/Matysh/houseplan-card/issues/346)). Golden-эталоны | `demo/smoke_warm_dialogs.mjs` `docs/WARM-REMOUNT.md` `src/houseplan-card.ts` | -| #337 | [CODE-REVIEW-337-r3.md](CODE-REVIEW-337-r3.md) | code · r3 | 🔴 красный | 1 | 0 | check-docs красный на ревьюемом SHA — стало устаревшим ровно из-за; Нет находок этого уровня в дельте r2→r3 | `scripts/source-fingerprint.mjs` `src/houseplan-card.ts` `docs/images/screenshots.json` `docs/specs/337-lazy-editor-chunk.md` `PROCESS.md` | +| #337 | [CODE-REVIEW-337-r1.md](CODE-REVIEW-337-r1.md) | code · r1 | 🔴 красный | 5 | 3 | Warm-remount коммитит editor mode в обход loader-гейта — падения на уже существующих sm…; Kiosk-контролы, явно названные в принятом ТЗ eager (§6.3: «kiosk controls остаются eage…; Безопасность resize «fail-closed» сломана: принудительный отказ preflight-проверки всё …; Стрелочная навигация по вкладкам инвентаря устройств падает с необработанным исключение…; Визуальная порча вторичного тулбара Device editor + 3 неподтверждённых golden-дельты по…; Два существующих smoke ожидают, что houseplan-card-editor уже зарегистрирован на страни… | `src/houseplan-card.ts` `docs/WARM-REMOUNT.md` `demo/smoke_preloader_lifecycle.mjs` `demo/smoke_warm_dialogs.mjs` `demo/smoke_warm_owners.mjs` `docs/SCOPE.md` `demo/smoke_kiosk.mjs` `demo/smoke_room_resize.mjs` | +| #337 | [CODE-REVIEW-337-r2.md](CODE-REVIEW-337-r2.md) | code · r2 | 🔴 красный | 2 | 1 | Warm-remount editor-камера теряет бит-точность — визуальный «прыжок» кадра, воспроизвод…; фикс устранил исключение, но обнажил под ним ещё один, ранее не наблюдаемый дефект в то… | `demo/smoke_warm_dialogs.mjs` `docs/WARM-REMOUNT.md` `src/houseplan-card.ts` | +| #337 | [CODE-REVIEW-337-r3.md](CODE-REVIEW-337-r3.md) | code · r3 | 🔴 красный | 1 | 0 | check-docs красный на ревьюемом SHA — стало устаревшим ровно из-за этого коммита, AC13 … | `scripts/source-fingerprint.mjs` `src/houseplan-card.ts` `docs/images/screenshots.json` `docs/specs/337-lazy-editor-chunk.md` `PROCESS.md` | | #337 | [CODE-REVIEW-337-r4.md](CODE-REVIEW-337-r4.md) | code · r4 | 🟢 зелёный | 1 | 0 | — | — | | #335 | [SPEC-REVIEW-335-r1.md](SPEC-REVIEW-335-r1.md) | spec · r1 | 🟡 жёлтый | 1 | 1 | определение «маркер существует» игнорирует tombstone removed: true, из-за чего AC1 не з…; release-артефакты / User-Visible не названы | `src/devices.ts` `custom_components/houseplan/validation.py` `trails.py` `tests_backend/test_trail_recorder.py` `import_export.py` `src/houseplan-editor-runtime.ts` `docs/VACUUM.md` `houseplan-editor-runtime.ts` | | #335 | [SPEC-REVIEW-335-r2.md](SPEC-REVIEW-335-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -552,8 +557,8 @@ | #333 | [SPEC-REVIEW-333-r2.md](SPEC-REVIEW-333-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — | — | | #333 | [CODE-REVIEW-333-r1.md](CODE-REVIEW-333-r1.md) | code · r1 | 🟡 жёлтый | 1 | 1 | Optimize новым гейтом ломает существующий бэкенд-тест — подтверждённая регрессия | `junction_limits.py` `tests_backend/test_ha_websocket.py` `test/fixtures/optimize-storage-roundtrip.json` `optimize-storage-roundtrip.json` | | #333 | [CODE-REVIEW-333-r2.md](CODE-REVIEW-333-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #331 | [SPEC-REVIEW-331-r1.md](SPEC-REVIEW-331-r1.md) | spec · r1 | 🔴 красный | 1 | 4 | Ключ узла квантуется через round(), а не через уже принятый в этом; Собственный пример AC1 не проходит собственный порог инцидентности; Не решено, распространяется ли fail-closed §2.6 на сторону; Максимальная ветвь ищется DFS-перебором вариантов; наихудшая; Release-артефакты не называют docs/USER-GUIDE.ru.md; §1 не отвечает на два обязательных продуктовых вопроса ТЗ в открытой | `docs/specs/331-junction-limit-precision.md` `src/coordinate-canonicalization.ts` `custom_components/houseplan/coordinate_canonicalization.py` `coordinate_canonicalization.py` `custom_components/houseplan/junction_limits.py` `docs/USER-GUIDE.ru.md` `check-docs.mjs` `docs/SCOPE.md` | -| #331 | [SPEC-REVIEW-331-r2.md](SPEC-REVIEW-331-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | M-r2-1 (наследник M2, закрыт частично). AC6 не различает сторону; §6 «Риски» (2) описывает механизм, которого §2.3 больше не содержит | `docs/specs/331-junction-limit-precision.md` | +| #331 | [SPEC-REVIEW-331-r1.md](SPEC-REVIEW-331-r1.md) | spec · r1 | 🔴 красный | 1 | 4 | Ключ узла квантуется через round(), а не через уже принятый в этом репозитории cross-la…; Собственный пример AC1 не проходит собственный порог инцидентности; Не решено, распространяется ли fail-closed §2.6 на сторону previous, и не создаёт ли эт…; Максимальная ветвь ищется DFS-перебором вариантов; наихудшая сложность не оценена и не …; Release-артефакты не называют docs/USER-GUIDE.ru.md; §1 не отвечает на два обязательных продуктовых вопроса ТЗ в открытой форме — какая перс… | `docs/specs/331-junction-limit-precision.md` `src/coordinate-canonicalization.ts` `custom_components/houseplan/coordinate_canonicalization.py` `coordinate_canonicalization.py` `custom_components/houseplan/junction_limits.py` `docs/USER-GUIDE.ru.md` `check-docs.mjs` `docs/SCOPE.md` | +| #331 | [SPEC-REVIEW-331-r2.md](SPEC-REVIEW-331-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | M-r2-1 (наследник M2, закрыт частично). AC6 не различает сторону (previous/candidate) —…; §6 «Риски» (2) описывает механизм, которого §2.3 больше не содержит («максимальная ветв… | `docs/specs/331-junction-limit-precision.md` | | #331 | [SPEC-REVIEW-331-r3.md](SPEC-REVIEW-331-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — | | #331 | [CODE-REVIEW-331-r1.md](CODE-REVIEW-331-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #330 | [SPEC-REVIEW-330-r1.md](SPEC-REVIEW-330-r1.md) | spec · r1 | ⚪ — | 2 | 1 | Перф-бюджеты §5 недостижимы решением из §4: AC2 и AC6 непроверяемы как написаны; AC4 ссылается на бенч, который не вызывает изменяемый код; Отсутствуют обязательные разделы ТЗ по §7.1: i18n, touch, риски, release-артефакты | `docs/specs/330-junction-limits-performance.md` `junction_limits.py` `src/houseplan-card.ts` `benchmark_junction_limits.mjs` `demo/benchmark_safe_resize.mjs` `test-build/resize.js` `test-build/plan-geometry-preflight.js` `benchmark_safe_resize.mjs` | @@ -573,8 +578,8 @@ | #319 | [CODE-REVIEW-319-r1.md](CODE-REVIEW-319-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #318 | [SPEC-REVIEW-318-r1.md](SPEC-REVIEW-318-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #318 | [CODE-REVIEW-318-r1.md](CODE-REVIEW-318-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #317 | [SPEC-REVIEW-317-r1.md](SPEC-REVIEW-317-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. Терминология HA Area/HA-зона в плане документации. ТЗ систематически | `docs/USER-GUIDE.ru.md` `USER-GUIDE.ru.md` | -| #317 | [CODE-REVIEW-317-r1.md](CODE-REVIEW-317-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | 1. Нет юнит-теста на дублирующиеся live-маркеры одного binding в | `src/devices.ts` | +| #317 | [SPEC-REVIEW-317-r1.md](SPEC-REVIEW-317-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | 1. Терминология HA Area/HA-зона в плане документации. ТЗ систематически использует «HA … | `docs/USER-GUIDE.ru.md` `USER-GUIDE.ru.md` | +| #317 | [CODE-REVIEW-317-r1.md](CODE-REVIEW-317-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | 1. Нет юнит-теста на дублирующиеся live-маркеры одного binding в roomClimateMap. Коммен… | `src/devices.ts` | | #316 | [SPEC-REVIEW-316-r1.md](SPEC-REVIEW-316-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | ТЗ не закрывает несколько обязательных разделов §7.1 / чек-листа DoR §2.5; AC3 описывает фикстуру, не достижимую в названном ею механизме; коллизия термина «инертный» | `ru.json` `en.json` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `docs/specs/README.md` `wall-segment-model.ts` `scripts/config-field-registry.mjs` `docs/CONFIG-COMPATIBILITY.md` | | #316 | [SPEC-REVIEW-316-r2.md](SPEC-REVIEW-316-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | §5.1 указывает не тот абзац docs/CONFIG-COMPATIBILITY.md; §5.3 неточно утверждает отсутствие span+проём в существующих golden-сценах | `docs/CONFIG-COMPATIBILITY.md` `demo/golden/harness.mjs` `demo/golden/matrix.mjs` `baselines-index.json` | | #316 | [SPEC-REVIEW-316-r3.md](SPEC-REVIEW-316-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | §5.3 обосновывает «без изменений» неточным утверждением о контурных/независимых атомах | `demo/golden/harness.mjs` `276-coincident-partition.json` `src/wall-segment-model.ts` `matrix.mjs` `src/houseplan-card.ts` | @@ -590,19 +595,19 @@ | #310 | [SPEC-REVIEW-310-r2.md](SPEC-REVIEW-310-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #310 | [CODE-REVIEW-310-r1.md](CODE-REVIEW-310-r1.md) | code · r1 | ⚪ — | 1 | 1 | недостоверный Baseline-Reviewed в коммите 0e6fbfb0; обещанный тест на пересечение #271+#310 отсутствует | `.github/workflows/validate.yml` `demo/golden/README.md` `PROCESS.md` `AGENTS.md` `validate-commit-provenance.mjs` `test/wall-thickness.test.mjs` | | #310 | [CODE-REVIEW-310-r2.md](CODE-REVIEW-310-r2.md) | code · r2 | 🟢 зелёный | 1 | 1 | 1 Честность нового Baseline-Reviewed; 2 Новый юнит-тест — умеет падать | — | -| #309 | [SPEC-REVIEW-309-r1.md](SPEC-REVIEW-309-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Отсутствуют несколько обязательных разделов §7.1, включая оба продуктовых; docs/WALL-THICKNESS.md («Junction tooling»: «sixteen close-up golden scenes | `docs/specs/309-junction-visual-limit.md` `docs/WALL-THICKNESS.md` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `docs/specs/README.md` `demo/golden/matrix.mjs` `AGENTS.md` | -| #309 | [SPEC-REVIEW-309-r2.md](SPEC-REVIEW-309-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Раздел «Скоуп и не-скоуп» (§3.6) не закрывает находку r1 полностью, и одна из | `src/wall-thickness.ts` `docs/WALL-THICKNESS.md` `PROCESS.md` `docs/TOUCH-SUPPORT.md` | -| #309 | [SPEC-REVIEW-309-r3.md](SPEC-REVIEW-309-r3.md) | spec · r3 | 🟢 зелёный | 0 | 1 | Нумерация AC в §5 разъезжается: новая строка помечена «7a», но названа в | `PROCESS.md` | +| #309 | [SPEC-REVIEW-309-r1.md](SPEC-REVIEW-309-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Отсутствуют несколько обязательных разделов §7.1, включая оба продуктовых; §3.5 и §4 повторяют формулировку «Все 16 junction-сцен» из docs/WALL-THICKNESS.md («Jun… | `docs/specs/309-junction-visual-limit.md` `docs/WALL-THICKNESS.md` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `docs/specs/README.md` `demo/golden/matrix.mjs` `AGENTS.md` | +| #309 | [SPEC-REVIEW-309-r2.md](SPEC-REVIEW-309-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Раздел «Скоуп и не-скоуп» (§3.6) не закрывает находку r1 полностью, и одна из двух его … | `src/wall-thickness.ts` `docs/WALL-THICKNESS.md` `PROCESS.md` `docs/TOUCH-SUPPORT.md` | +| #309 | [SPEC-REVIEW-309-r3.md](SPEC-REVIEW-309-r3.md) | spec · r3 | 🟢 зелёный | 0 | 1 | Нумерация AC в §5 разъезжается: новая строка помечена «7a», но названа в прозе «AC8», а… | `PROCESS.md` | | #309 | [CODE-REVIEW-309-r1.md](CODE-REVIEW-309-r1.md) | code · r1 | 🔴 красный | 0 | 1 | npm test красный на проверяемом SHA; AC5 доказана не буквально как записано в ТЗ | `test/golden-matrix.test.mjs` `demo/golden/matrix.mjs` `demo/golden/README.md` `docs/specs/309-junction-visual-limit.md` `test/fixtures/309-junction-teeth.json` `smoke_junction_holes.mjs` `302-junction-artifacts.json` `scripts/wall-strip-containment.mjs` | | #309 | [CODE-REVIEW-309-r2.md](CODE-REVIEW-309-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #307 | [SPEC-REVIEW-307-r1.md](SPEC-REVIEW-307-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #307 | [CODE-REVIEW-307-r1.md](CODE-REVIEW-307-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #306 | [SPEC-REVIEW-306-r1.md](SPEC-REVIEW-306-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | лимит wall_segments[] в ТЗ устарел и противоречит уже слитому #282 | `docs/specs/306-zero-thickness-walls.md` `custom_components/houseplan/validation.py` `docs/specs/282-stable-wall-segment-identity.md` `docs/specs/282-...md` | | #306 | [SPEC-REVIEW-306-r2.md](SPEC-REVIEW-306-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #306 | [CODE-REVIEW-306-r1.md](CODE-REVIEW-306-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | 1 Гейты — что прогнано; 2 Что НЕ прогонялось и почему; Отчёт «Оптимизировать планы» показывает退ый термин «виртуальный»/«virtual»; docs/CHANGELOG.md/docs/CHANGELOG.ru.md не содержат обязательного; Четыре i18n-ключа из таблицы §15 ТЗ реализованы не под тем именем/точным | `src/i18n/en.json` `ru.json` `src/houseplan-card.ts` `src/plan-optimizer.ts` `plan-optimizer.ts` `houseplan-card.ts` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` | +| #306 | [CODE-REVIEW-306-r1.md](CODE-REVIEW-306-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | 1 Гейты — что прогнано; 2 Что НЕ прогонялось и почему; Отчёт «Оптимизировать планы» показывает退ый термин «виртуальный»/«virtual», который это …; docs/CHANGELOG.md/docs/CHANGELOG.ru.md не содержат обязательного предупреждения о backu…; Четыре i18n-ключа из таблицы §15 ТЗ реализованы не под тем именем/точным текстом | `src/i18n/en.json` `ru.json` `src/houseplan-card.ts` `src/plan-optimizer.ts` `plan-optimizer.ts` `houseplan-card.ts` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` | | #306 | [CODE-REVIEW-306-r2.md](CODE-REVIEW-306-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | 1 Гейты — что прогнано лично; 2 Что НЕ прогонялось и почему; 3 Разбор смок-выборки по дельте | — | | #304 | [SPEC-REVIEW-304-r1.md](SPEC-REVIEW-304-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #304 | [CODE-REVIEW-304-r1.md](CODE-REVIEW-304-r1.md) | code · r1 | 🟡 жёлтый | 1 | 0 | два golden-сценария неродственных фич стали «different» на канонической Linux CI и не п…; буквально такой же топологией (golden использует смежный, но не идентичный golden-coinc… | `demo/golden/harness.mjs` `demo/golden/matrix.mjs` | +| #304 | [CODE-REVIEW-304-r1.md](CODE-REVIEW-304-r1.md) | code · r1 | 🟡 жёлтый | 1 | 0 | два golden-сценария неродственных фич стали «different» на канонической Linux CI и не п…; AC1 фиксирует «шесть узлов» через частный unit/smoke fixture, а не через golden-сцену с… | `demo/golden/harness.mjs` `demo/golden/matrix.mjs` | | #304 | [CODE-REVIEW-304-r2.md](CODE-REVIEW-304-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #303 | [SPEC-REVIEW-303-r1.md](SPEC-REVIEW-303-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #303 | [CODE-REVIEW-303-r1.md](CODE-REVIEW-303-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | счёт unit-тестов в отчёте разработчика на единицу отличается от факта | — | @@ -628,7 +633,7 @@ | #295 | [CODE-REVIEW-295-r2.md](CODE-REVIEW-295-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #294 | [SPEC-REVIEW-294-r1.md](SPEC-REVIEW-294-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | AC7 уже формулировкой не покрывает весь текст, который спецификация обязана исправить | `docs/specs/294-wall-esc-detach.md` `docs/USER-GUIDE.md` `docs/USER-GUIDE.ru.md` | | #294 | [SPEC-REVIEW-294-r2.md](SPEC-REVIEW-294-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #294 | [CODE-REVIEW-294-r1.md](CODE-REVIEW-294-r1.md) | code · r1 | 🔴 красный | 0 | 2 | Обязательный гейт node scripts/check-docs.mjs красный на ревьюемом SHA; Новый таргетированный смок demo/smoke_unified_wall_tool.mjs падает на | `src/houseplan-card.ts` `docs/images/screenshots.json` `demo/smoke_unified_wall_tool.mjs` | +| #294 | [CODE-REVIEW-294-r1.md](CODE-REVIEW-294-r1.md) | code · r1 | 🔴 красный | 0 | 2 | Обязательный гейт node scripts/check-docs.mjs красный на ревьюемом SHA; Новый таргетированный смок demo/smoke_unified_wall_tool.mjs падает на двух ассертах, ко… | `src/houseplan-card.ts` `docs/images/screenshots.json` `demo/smoke_unified_wall_tool.mjs` | | #294 | [CODE-REVIEW-294-r2.md](CODE-REVIEW-294-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #293 | [SPEC-REVIEW-293-r1.md](SPEC-REVIEW-293-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Отсутствуют два обязательных раздела §7.1 — «риски» и «откат»; docs/specs/293-resize-pointer-noop.md не добавлен в индекс docs/specs/README.md | `docs/specs/293-resize-pointer-noop.md` `docs/specs/README.md` | | #293 | [SPEC-REVIEW-293-r2.md](SPEC-REVIEW-293-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -636,16 +641,16 @@ | #292 | [SPEC-REVIEW-292-r1.md](SPEC-REVIEW-292-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | обещание в §5 не имеет технической опоры и не проверяется ни одним AC; отсутствуют разделы, обязательные по PROCESS.md §7.1 и принятые в соседних ТЗ той же по…; AC1–AC8 не помечают явно способ доказательства | `docs/specs/292-resize-availability-audit.md` `src/resize.ts` `src/i18n/en.json` `src/i18n/ru.json` `PROCESS.md` `292-resize-availability-audit.md` `277-safe-resize.md` `276-coincident-partition-reconciliation.md` | | #292 | [SPEC-REVIEW-292-r2.md](SPEC-REVIEW-292-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #292 | [CODE-REVIEW-292-r1.md](CODE-REVIEW-292-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #291 | [SPEC-REVIEW-291-r1.md](SPEC-REVIEW-291-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | Отсутствуют обе обязательные продуктовые секции §7.1, и новый видимый UI; Нет разделов «Риски» и «Откат», обязательных по DoR (§2.5) и присутствующих; AC3 иллюстрирует вывод CLI текстом, который не совпадает с реальным; Issue #291 называет себя «Стадия 1 из ADR #282», хотя реальная Stage 1 | `docs/specs/291-lattice-coordinate-write-barrier.md` `docs/SCOPE.md` `src/i18n/ru.json` `docs/specs/252-optimize-orphan-layout-report.md` `docs/specs/279-near-orthogonal-junction.md` `docs/specs/226-entity-parent-dedup.md` `scripts/model-invariants.mjs` `docs/adr/282-wall-geometry-representation.md` | -| #291 | [SPEC-REVIEW-291-r2.md](SPEC-REVIEW-291-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Раздел «i18n», обязательный по цепочке §7.1, отсутствует; новые строки; (из r1) — пример CLI-вывода в AC3 остаётся текстово рассинхронизирован | `docs/specs/291-lattice-coordinate-write-barrier.md` `PROCESS.md` `src/i18n/en.json` `src/i18n/ru.json` `docs/specs/252-optimize-orphan-layout-report.md` `docs/specs/094-universal-state-toggle.md` | -| #291 | [SPEC-REVIEW-291-r3.md](SPEC-REVIEW-291-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | Точность (число знаков/округление) нового placeholder {cm} в; (из r1) — тело issue #291 всё ещё называет задачу «Стадия 1 из ADR | `docs/specs/291-lattice-coordinate-write-barrier.md` `src/houseplan-card.ts` `model-invariants.mjs` | +| #291 | [SPEC-REVIEW-291-r1.md](SPEC-REVIEW-291-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | Отсутствуют обе обязательные продуктовые секции §7.1, и новый видимый UI предъявлен как…; Нет разделов «Риски» и «Откат», обязательных по DoR (§2.5) и присутствующих в каждом со…; AC3 иллюстрирует вывод CLI текстом, который не совпадает с реальным форматом инструмента; Issue #291 называет себя «Стадия 1 из ADR #282», хотя реальная Stage 1 ADR #282 — это «… | `docs/specs/291-lattice-coordinate-write-barrier.md` `docs/SCOPE.md` `src/i18n/ru.json` `docs/specs/252-optimize-orphan-layout-report.md` `docs/specs/279-near-orthogonal-junction.md` `docs/specs/226-entity-parent-dedup.md` `scripts/model-invariants.mjs` `docs/adr/282-wall-geometry-representation.md` | +| #291 | [SPEC-REVIEW-291-r2.md](SPEC-REVIEW-291-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Раздел «i18n», обязательный по цепочке §7.1, отсутствует; новые строки отчёта Optimize …; остаётся. Не относится к файлу ТЗ, не блокирует | `docs/specs/291-lattice-coordinate-write-barrier.md` `PROCESS.md` `src/i18n/en.json` `src/i18n/ru.json` `docs/specs/252-optimize-orphan-layout-report.md` `docs/specs/094-universal-state-toggle.md` | +| #291 | [SPEC-REVIEW-291-r3.md](SPEC-REVIEW-291-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | Точность (число знаков/округление) нового placeholder {cm} в gs.optimize_lattice_summar…; остаётся. Не относится к файлу ТЗ, не блокирует | `docs/specs/291-lattice-coordinate-write-barrier.md` `src/houseplan-card.ts` `model-invariants.mjs` | | #291 | [CODE-REVIEW-291-r1.md](CODE-REVIEW-291-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | AC4 не доказан ни автотестом, ни явной записью; docs/USER-GUIDE.ru.md не обновлён; не блокируют, зафиксированы без правки | `smoke_lattice_write_barrier.mjs` `smoke_optimize_coordinate_canonicalization.mjs` `docs/USER-GUIDE.ru.md` `docs/USER-GUIDE.md` `src/i18n/ru.json` | | #291 | [CODE-REVIEW-291-r2.md](CODE-REVIEW-291-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #290 | [SPEC-REVIEW-290-r1.md](SPEC-REVIEW-290-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | Отсутствуют обязательные разделы §7.1 «риски» и «откат»; AC исходного issue про npm run invariants на реальных данных и; AC4 неточно называет источник fixture | `docs/specs/290-near-axis-authoring-and-repair.md` `docs/specs/277-safe-resize.md` `docs/specs/279-near-orthogonal-junction.md` `scripts/model-invariants.mjs` `44.json` `test/fixtures/279-near-orthogonal-junction.json` | +| #290 | [SPEC-REVIEW-290-r1.md](SPEC-REVIEW-290-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | Отсутствуют обязательные разделы §7.1 «риски» и «откат»; AC исходного issue про npm run invariants на реальных данных и видимое снижение числа п…; AC4 неточно называет источник fixture | `docs/specs/290-near-axis-authoring-and-repair.md` `docs/specs/277-safe-resize.md` `docs/specs/279-near-orthogonal-junction.md` `scripts/model-invariants.mjs` `44.json` `test/fixtures/279-near-orthogonal-junction.json` | | #290 | [SPEC-REVIEW-290-r2.md](SPEC-REVIEW-290-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #290 | [CODE-REVIEW-290-r1.md](CODE-REVIEW-290-r1.md) | code · r1 | 🔴 красный | 1 | 2 | 1 Смок-выборка; 2 Инварианты и AC10 — реальные планы; Resize отключается на всей комнате из-за чужой, нетронутой near-axis стены (AC3 нарушен…; AC9: 3 из 6 обязательных мутантов отсутствуют; AC10: нет автотеста на двух реальных фикстурах; AC1 «source guard» не механизирован | `src/resize.ts` `test/fixtures/real-plan-second-floor.json` `scripts/mutation-gate.mjs` `test/near-axis.test.mjs` `mutation-gate.mjs` `smoke_near_axis_optimize.mjs` `test/model-invariants.test.mjs` `test/plan-optimizer.test.mjs` | | #290 | [CODE-REVIEW-290-r2.md](CODE-REVIEW-290-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | 1 Смок-выборка; 1 Проверка закрытия High H1 (не декларативно — воспроизведением на обоих состояниях кода); 2 Проверка закрытия Medium M1 (mutation-gate); 3 Проверка закрытия Medium M2 (AC10 автотест) | — | -| #290 | [CODE-REVIEW-290-r3.md](CODE-REVIEW-290-r3.md) | code · r3 | ⚪ — | 0 | 0 | ТЗ AC1 (docs/specs/290-near-axis-authoring-and-repair.md:173-174) прямо | `docs/specs/290-near-axis-authoring-and-repair.md` `src/wall-thickness.ts` `test/near-axis.test.mjs` `test/single-source-numbers.test.mjs` `src/near-axis.ts` `wall-thickness.ts` | +| #290 | [CODE-REVIEW-290-r3.md](CODE-REVIEW-290-r3.md) | code · r3 | ⚪ — | 0 | 0 | ТЗ AC1 (docs/specs/290-near-axis-authoring-and-repair.md:173-174) прямо обещает: «Autho… | `docs/specs/290-near-axis-authoring-and-repair.md` `src/wall-thickness.ts` `test/near-axis.test.mjs` `test/single-source-numbers.test.mjs` `src/near-axis.ts` `wall-thickness.ts` | | #290 | [CODE-REVIEW-290-r4.md](CODE-REVIEW-290-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — | — | | #289 | [SPEC-REVIEW-289-r1.md](SPEC-REVIEW-289-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | раздел «Риски» отсутствует полностью; раздел «Откат» отсутствует полностью; 6 из 9 AC не указывают способ доказательства; терминология «рукоятка» вместо канонической «ручка»; i18n-ключ не назван по имени | `docs/RESIZE.md` `demo/smoke_room_resize.mjs` `test/resize.test.mjs` `docs/USER-GUIDE.ru.md` `src/resize.ts` `src/i18n/en.json` `ru.json` | | #289 | [SPEC-REVIEW-289-r2.md](SPEC-REVIEW-289-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -662,14 +667,14 @@ | #282 | [CODE-REVIEW-282-r2.md](CODE-REVIEW-282-r2.md) | code · r2 | 🔴 красный | 2 | 0 | npm test красный: диагностика больше не соответствует контракту, который сама же проверяет; AC7 нарушен: opening на обычной стене исчезает со Static-карточки после миграции в v8 | `test/open-passage-contract.test.mjs` `demo/smoke_open_passage.mjs` `src/space-render.ts` `space-card.ts` `ARCHITECTURE.md` `src/wall-segment-model.ts` `space-render.ts` `src/houseplan-card.ts` | | #282 | [CODE-REVIEW-282-r3.md](CODE-REVIEW-282-r3.md) | code · r3 | 🔴 красный | 1 | 0 | AC7 всё ещё нарушен: Static-карточка рисует сплошную стену прямо по месту прохода после… | `src/space-render.ts` `src/wall-segment-model.ts` `space-render.ts` `houseplan-card.ts` `demo/smoke_open_passage.mjs` `src/logic.ts` `docs/SCOPE.md` `smoke_open_passage.mjs` | | #282 | [CODE-REVIEW-282-r4.md](CODE-REVIEW-282-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — | — | -| #278 | [SPEC-REVIEW-278-r1.md](SPEC-REVIEW-278-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | отсутствует обязательный раздел «Риски» | `docs/specs/278-wall-union-isolation.md` `docs/specs/253-resize-wall-thickness.md` `docs/specs/275-multiwall-strip-containment.md` | +| #278 | [SPEC-REVIEW-278-r1.md](SPEC-REVIEW-278-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | отсутствует обязательный раздел «Риски». PROCESS.md §7.1 перечисляет обязательные разде… | `docs/specs/278-wall-union-isolation.md` `docs/specs/253-resize-wall-thickness.md` `docs/specs/275-multiwall-strip-containment.md` | | #278 | [SPEC-REVIEW-278-r2.md](SPEC-REVIEW-278-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #278 | [CODE-REVIEW-278-r1.md](CODE-REVIEW-278-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | docs/TESTING.md называет несуществующие id мутантов | `docs/TESTING.md` `scripts/mutation-gate.mjs` `TESTING.md` `mutation-gate.mjs` | | #278 | [CODE-REVIEW-278-r2.md](CODE-REVIEW-278-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #277 | [SPEC-REVIEW-277-r1.md](SPEC-REVIEW-277-r1.md) | spec · r1 | ⚪ — | 0 | 3 | нет обязательного раздела «риски» (§7.1); нет обязательного «что человек увидит до и после» одной фразой без терминов реализации …; из плана тестов выпала обязательная анонимизированная fixture реального плана | `docs/specs/277-safe-resize.md` | | #277 | [SPEC-REVIEW-277-r2.md](SPEC-REVIEW-277-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #277 | [CODE-REVIEW-277-r1.md](CODE-REVIEW-277-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Кэш допустимости (eligibility) на самом деле не memo­изирует дорогую; Мёртвый код и устаревший комментарий: rszSel теперь ничего не | `src/houseplan-card.ts` `docs/ARCHITECTURE.md` `demo/fixtures/large-house.mjs` `benchmark_safe_resize.mjs` | -| #277 | [CODE-REVIEW-277-r2.md](CODE-REVIEW-277-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | (процессная, повтор паттерна из SPEC-REVIEW-277-r2/L2). Вердикт-комментарий | `docs/reviews/CODE-REVIEW-277-r1.md` `src/houseplan-card.ts` | +| #277 | [CODE-REVIEW-277-r1.md](CODE-REVIEW-277-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Кэш допустимости (eligibility) на самом деле не memo­изирует дорогую часть — рендер руч…; Мёртвый код и устаревший комментарий: rszSel теперь ничего не рендерит, хотя всё ещё вы… | `src/houseplan-card.ts` `docs/ARCHITECTURE.md` `demo/fixtures/large-house.mjs` `benchmark_safe_resize.mjs` | +| #277 | [CODE-REVIEW-277-r2.md](CODE-REVIEW-277-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | Находка предыдущего раунда (M1) закрыта полностью — см. раздел ниже. Новых находок в пр… | `docs/reviews/CODE-REVIEW-277-r1.md` `src/houseplan-card.ts` | | #276 | [SPEC-REVIEW-276-r1.md](SPEC-REVIEW-276-r1.md) | spec · r1 | 🔴 красный | 1 | 3 | Заявленный Redo для серверной отмены Optimize не существует и не заявлен как новая работа; Раздел «Риски» отсутствует — обязательный пункт DoR; Не перечислены затронутые файлы и модули — обязательный пункт DoR; Ссылка на несуществующий канонический документ docs/PLAN-OPTIMIZE.md | `src/houseplan-card.ts` `docs/USER-GUIDE.ru.md` `docs/ARCHITECTURE.md` `docs/specs/275-multiwall-strip-containment.md` `src/plan-optimizer.ts` `src/wall-merge.ts` `src/physical-geometry.ts` `docs/PLAN-OPTIMIZE.md` | | #276 | [SPEC-REVIEW-276-r2.md](SPEC-REVIEW-276-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #276 | [SPEC-REVIEW-276-r3.md](SPEC-REVIEW-276-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | Разное именование одной переменной в двух соседних формулах; AC1 сохраняет квалификатор «same-thickness», хотя условие эксплицитно расширено дельтой; Второй подряд неверный SHA в хендофф-комментарии автора — повтор находки r2 | `docs/reviews/SPEC-REVIEW-276-r2.md` | @@ -712,12 +717,12 @@ | #261 | [SPEC-REVIEW-261-r1.md](SPEC-REVIEW-261-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | «Что человек увидит до и после» смешивает продуктовое и техническое | `docs/specs/261-white-wedges-root-cause.md` | | #261 | [CODE-REVIEW-261-r1.md](CODE-REVIEW-261-r1.md) | code · r1 | ⚪ — | 0 | 0 | — | — | | #258 | [SPEC-REVIEW-258-r1.md](SPEC-REVIEW-258-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | «Что человек увидит» смешивает продуктовую и техническую лексику | `docs/specs/258-wall-key-storage-roundtrip.md` | -| #258 | [CODE-REVIEW-258-r1.md](CODE-REVIEW-258-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Release-артефакты заявляют больше, чем доказано, и противоречат собственному; 'Записи толщины, которые не найдутся по ключу' теперь мёртв — wall_key | `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `CHANGELOG.md` `.ru.md` `scripts/model-invariants.mjs` | +| #258 | [CODE-REVIEW-258-r1.md](CODE-REVIEW-258-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Release-артефакты заявляют больше, чем доказано, и противоречат собственному расследова…; scripts/model-invariants.mjs, titles внутри report(): ключ wall_key: 'Записи толщины, к… | `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `CHANGELOG.md` `.ru.md` `scripts/model-invariants.mjs` | | #258 | [CODE-REVIEW-258-r2.md](CODE-REVIEW-258-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #256 | [CODE-REVIEW-256-r1.md](CODE-REVIEW-256-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #253 | [SPEC-REVIEW-253-r1.md](SPEC-REVIEW-253-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | риск MAX_WALLS=500 от роста числа записей не упомянут в разделе рисков | `custom_components/houseplan/validation.py` | +| #253 | [SPEC-REVIEW-253-r1.md](SPEC-REVIEW-253-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | риск MAX_WALLS=500 от роста числа записей не упомянут в разделе рисков. Новый контракт … | `custom_components/houseplan/validation.py` | | #253 | [CODE-REVIEW-253-r1.md](CODE-REVIEW-253-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #252 | [SPEC-REVIEW-252-r1.md](SPEC-REVIEW-252-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ меняет задокументированный и опубликованный инвариант Optimize, не | `docs/CANVAS.md` `docs/CHANGELOG.md` `docs/specs/252-optimize-orphan-layout-report.md` | +| #252 | [SPEC-REVIEW-252-r1.md](SPEC-REVIEW-252-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | ТЗ меняет задокументированный и опубликованный инвариант Optimize, не называя его | `docs/CANVAS.md` `docs/CHANGELOG.md` `docs/specs/252-optimize-orphan-layout-report.md` | | #252 | [SPEC-REVIEW-252-r2.md](SPEC-REVIEW-252-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #252 | [CODE-REVIEW-252-r1.md](CODE-REVIEW-252-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #252 | [CODE-REVIEW-252-r2.md](CODE-REVIEW-252-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -734,7 +739,7 @@ | #249 | [CODE-REVIEW-249-r2.md](CODE-REVIEW-249-r2.md) | code · r2 | ⚪ — | 0 | 0 | Два из восьми вызовов innerContourForRoom не получили sharedRoomWallGeometry | `src/houseplan-card.ts` | | #248 | [SPEC-REVIEW-248-r1.md](SPEC-REVIEW-248-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | не блокирует, оставлено на усмотрение автора | `docs/USER-GUIDE.ru.md` `USER-GUIDE.ru.md` | | #248 | [CODE-REVIEW-248-r1.md](CODE-REVIEW-248-r1.md) | code · r1 | 🟢 зелёный | 1 | 0 | — | — | -| #244 | [SPEC-REVIEW-244-r1.md](SPEC-REVIEW-244-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Не назван пункт DoR «влияние на touch» | `docs/TOUCH-SUPPORT.md` | +| #244 | [SPEC-REVIEW-244-r1.md](SPEC-REVIEW-244-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Не назван пункт DoR «влияние на touch». PROCESS.md §2.5 требует явно назвать влияние на… | `docs/TOUCH-SUPPORT.md` | | #244 | [SPEC-REVIEW-244-r2.md](SPEC-REVIEW-244-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #244 | [CODE-REVIEW-244-r1.md](CODE-REVIEW-244-r1.md) | code · r1 | 🔴 красный | 2 | 0 | Именованный в АС смок demo/smoke_orphan_space_references.mjs красный; Регрессия контракта #113: последнее занятое пространство больше не удаляется | `demo/smoke_orphan_space_references.mjs` `space-deletion.test.mjs` `test_ha_websocket.py` `CONFIG-COMPATIBILITY.md` `USER-GUIDE.md` `demo/smoke_optional_space_model.mjs` | | #244 | [CODE-REVIEW-244-r2.md](CODE-REVIEW-244-r2.md) | code · r2 | ⚪ — | 2 | 0 | — | — | @@ -745,7 +750,7 @@ | #242 | [SPEC-REVIEW-242-r1.md](SPEC-REVIEW-242-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #242 | [CODE-REVIEW-242-r1.md](CODE-REVIEW-242-r1.md) | code · r1 | 🟡 жёлтый | 1 | 1 | AC4 не выполнен: flip_v не меняет направление 10° поворота ворот на общей стене и на не…; заявленный golden-охват в handoff занижен на порядок; обязательные по §12.3 новые сцены… | `src/houseplan-card.ts` `src/render/opening-symbol.ts` `wall-thickness.ts` `docs/WALL-THICKNESS.md` `docs/ARCHITECTURE.md` `docs/ISOMETRIC.md` `docs/USER-GUIDE.ru.md` `test/opening-symbol.test.mjs` | | #242 | [CODE-REVIEW-242-r2.md](CODE-REVIEW-242-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | точный список из 67 существующих golden-сцен на самом деле содержит 2 сцены, не задетые… | `docs/TESTING.md` `demo/golden/matrix.mjs` `test/golden-matrix.test.mjs` | -| #239 | [SPEC-REVIEW-239-r1.md](SPEC-REVIEW-239-r1.md) | spec · r1 | ⚪ — | 0 | 1 | §13 Acceptance criteria не указывает способ доказательства для AC13; §10 «Данные, i18n...» не называет конкретный текст/ключ новой imperial | `docs/specs/230-hatch-density-normalization.md` `docs/specs/238-opening-inner-distances.md` | +| #239 | [SPEC-REVIEW-239-r1.md](SPEC-REVIEW-239-r1.md) | spec · r1 | ⚪ — | 0 | 1 | §13 Acceptance criteria не указывает способ доказательства для AC13, AC14, AC16, и это …; §10 «Данные, i18n...» не называет конкретный текст/ключ новой imperial- подписи внутри … | `docs/specs/230-hatch-density-normalization.md` `docs/specs/238-opening-inner-distances.md` | | #239 | [SPEC-REVIEW-239-r2.md](SPEC-REVIEW-239-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — | — | | #239 | [CODE-REVIEW-239-r1.md](CODE-REVIEW-239-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | demo/smoke_grid_scale_invariance.mjs нестабилен на проверке darkViewPixelsMatch — ~43% … | `demo/smoke_grid_scale_invariance.mjs` `src/styles.ts` `AGENTS.md` | | #239 | [CODE-REVIEW-239-r2.md](CODE-REVIEW-239-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -753,14 +758,14 @@ | #238 | [CODE-REVIEW-238-r1.md](CODE-REVIEW-238-r1.md) | code · r1 | 🔴 красный | 1 | 0 | Продуктовый коммит не обновил скомпилированный бандл; закоммиченный артефакт не содержи… | `dist/houseplan-card.js` `custom_components/houseplan/frontend/houseplan-card.js` `demo/srv/assets/houseplan-card.js` `src/houseplan-card.ts` `src/opening-dimensions.ts` `src/styles.ts` | | #238 | [CODE-REVIEW-238-r2.md](CODE-REVIEW-238-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #238 | [CODE-REVIEW-238-r3.md](CODE-REVIEW-238-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | -| #234 | [SPEC-REVIEW-234-r1.md](SPEC-REVIEW-234-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | раздел i18n из обязательного списка §7.1 отсутствует в документе целиком; граница > 0 vs текущее >= 0 не отражена явно в примерах AC1 | `PROCESS.md` `docs/specs/234-chain-segment-thickness.md` `wall-face-graph.ts` `docs/WALL-THICKNESS.md` | +| #234 | [SPEC-REVIEW-234-r1.md](SPEC-REVIEW-234-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | раздел i18n из обязательного списка §7.1 отсутствует в документе целиком. PROCESS.md §7…; граница > 0 vs текущее >= 0 не отражена явно в примерах AC1. wall-face-graph.ts:69 сего… | `PROCESS.md` `docs/specs/234-chain-segment-thickness.md` `wall-face-graph.ts` `docs/WALL-THICKNESS.md` | | #234 | [SPEC-REVIEW-234-r2.md](SPEC-REVIEW-234-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #234 | [CODE-REVIEW-234-r2.md](CODE-REVIEW-234-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | Диагноз и контракт по коду; Гейты — прогнаны на HEAD (c8e9597) в этой сессии; AC — чем доказано; Взаимодействие с #229 (ребейз) | — | | #233 | [SPEC-REVIEW-233-r1.md](SPEC-REVIEW-233-r1.md) | spec · r1 | ⚪ — | 2 | 0 | Контракт §6 не покрывает открытую сторону, к которой ведёт продуктовое решение §4.3 (High); §7 приписывает thicknessCmAt поведение, которого у неё нет: заявлено фактом, не провере… | `docs/specs/233-resize-inner-dimensions.md` `src/wall-thickness.ts` `docs/WALL-THICKNESS.md` `test/wall-thickness.test.mjs` `wall-thickness.ts` | | #233 | [SPEC-REVIEW-233-r2.md](SPEC-REVIEW-233-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #233 | [CODE-REVIEW-233-r1.md](CODE-REVIEW-233-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | тест AC6b не строит сценарий, который он заявляет (и который был H2); не хватает мутанта из принятого §11 ТЗ | `test/wall-thickness.test.mjs` `docs/specs/233-resize-inner-dimensions.md` `scripts/mutation-gate.mjs` | | #233 | [CODE-REVIEW-233-r2.md](CODE-REVIEW-233-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #231 | [SPEC-REVIEW-231-r1.md](SPEC-REVIEW-231-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Нормативная позиция decor относительно room hover fill не имеет | `docs/specs/231-decor-layer-order.md` `demo/smoke_glow.mjs` `smoke_glow.mjs` | +| #231 | [SPEC-REVIEW-231-r1.md](SPEC-REVIEW-231-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Нормативная позиция decor относительно room hover fill не имеет привязанного AC/доказат… | `docs/specs/231-decor-layer-order.md` `demo/smoke_glow.mjs` `smoke_glow.mjs` | | #231 | [SPEC-REVIEW-231-r2.md](SPEC-REVIEW-231-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #231 | [CODE-REVIEW-231-r1.md](CODE-REVIEW-231-r1.md) | code · r1 | ⚪ — | 0 | 1 | golden regression на трёх существующих large-house сценах не определена и не учтена | `demo/fixtures/large-house.mjs` `large-house.mjs` `docs/TESTING.md` | | #231 | [CODE-REVIEW-231-r2.md](CODE-REVIEW-231-r2.md) | code · r2 | ⚪ — | 0 | 0 | — | — | @@ -778,10 +783,10 @@ | #228 | [CODE-REVIEW-228-r1.md](CODE-REVIEW-228-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | негативный сценарий «hosted opening» не доказан автотестом; неоднозначный «gap > 2 см» диагностируется как единственный | `src/houseplan-card.ts` `docs/specs/228-plan-drawing-problems.md` `test/wall-face-repair.test.mjs` `demo/smoke_plan_drawing_repairs.mjs` | | #228 | [CODE-REVIEW-228-r2.md](CODE-REVIEW-228-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #228 | [CODE-REVIEW-228-r3.md](CODE-REVIEW-228-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | -| #226 | [SPEC-REVIEW-226-r1.md](SPEC-REVIEW-226-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи; Не найдено находок, которые стоило бы фиксировать отдельно и не чинить | `docs/FILTERING.md` `PROCESS.md` | +| #226 | [SPEC-REVIEW-226-r1.md](SPEC-REVIEW-226-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи | `docs/FILTERING.md` `PROCESS.md` | | #226 | [SPEC-REVIEW-226-r2.md](SPEC-REVIEW-226-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #226 | [CODE-REVIEW-226-r1.md](CODE-REVIEW-226-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #225 | [SPEC-REVIEW-225-r1.md](SPEC-REVIEW-225-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи; Не найдено находок, которые стоило бы фиксировать отдельно и не | `import_export.py` | +| #225 | [SPEC-REVIEW-225-r1.md](SPEC-REVIEW-225-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи | `import_export.py` | | #225 | [SPEC-REVIEW-225-r2.md](SPEC-REVIEW-225-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #225 | [CODE-REVIEW-225-r1.md](CODE-REVIEW-225-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | internal_path доверяет path даже при непустых scheme/netloc; заявленный мутационный гейт не зарегистрирован | `scripts/mutation-gate.mjs` `import_export.py` `scripts/backend-test-guard.mjs` `test_ha_import_export.py` `.github/workflows/mutation-gate.yml` | | #225 | [CODE-REVIEW-225-r2.md](CODE-REVIEW-225-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -796,10 +801,10 @@ | #220 | [SPEC-REVIEW-220-r2.md](SPEC-REVIEW-220-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Medium, в скоупе. §17.3 маркирует нормативное требование как «свободно меняемое» | `docs/specs/220-space-tab-reorder.md` | | #220 | [SPEC-REVIEW-220-r3.md](SPEC-REVIEW-220-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — | | #220 | [CODE-REVIEW-220-r1.md](CODE-REVIEW-220-r1.md) | code · r1 | 🔴 красный | 1 | 2 | материализация неверно определяет «зависимые от порядка» маркеры: обычный маркер устрой…; перетаскивание вкладки не захватывает указатель: отпускание за пределами панели оставля…; мутационный гейт реализован не полностью относительно принятого §14 ТЗ | `src/space-order.ts` `src/devices.ts` `houseplan-card.ts` `test/space-order.test.mjs` `docs/TOUCH-SUPPORT.md` `demo/smoke_space_tab_reorder.mjs` `docs/specs/220-space-tab-reorder.md` `scripts/mutation-gate.mjs` | -| #219 | [SPEC-REVIEW-219-r1.md](SPEC-REVIEW-219-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи; Не найдено находок, которые стоило бы фиксировать отдельно и не чинить | `docs/USER-GUIDE.ru.md` `AGENTS.md` `docs/TESTING.md` `TESTING.md` `USER-GUIDE.ru.md` | +| #219 | [SPEC-REVIEW-219-r1.md](SPEC-REVIEW-219-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи | `docs/USER-GUIDE.ru.md` `AGENTS.md` `docs/TESTING.md` `TESTING.md` `USER-GUIDE.ru.md` | | #219 | [SPEC-REVIEW-219-r2.md](SPEC-REVIEW-219-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #219 | [CODE-REVIEW-219-r1.md](CODE-REVIEW-219-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | AC7/§16 не называют все golden-сцены, которые изменит эта правка | — | -| #218 | [SPEC-REVIEW-218-r1.md](SPEC-REVIEW-218-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | отсутствует обязательный раздел «Риски»; §8.1 ТЗ утверждает: «quantum 1e-6 единицы плана = 10⁻⁹ м». Пересчёт по | `docs/specs/218-glow-floor-geometry.md` `SPEC-REVIEW-217-r1.md` `mutation-gate.mjs` `src/space-geometry.ts` `src/houseplan-card.ts` | +| #218 | [SPEC-REVIEW-218-r1.md](SPEC-REVIEW-218-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | отсутствует обязательный раздел «Риски»; §8.1 ТЗ утверждает: «quantum 1e-6 единицы плана = 10⁻⁹ м». Пересчёт по GRID_PITCH = NOR… | `docs/specs/218-glow-floor-geometry.md` `SPEC-REVIEW-217-r1.md` `mutation-gate.mjs` `src/space-geometry.ts` `src/houseplan-card.ts` | | #218 | [SPEC-REVIEW-218-r2.md](SPEC-REVIEW-218-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #218 | [CODE-REVIEW-218-r1.md](CODE-REVIEW-218-r1.md) | code · r1 | ⚪ — | 0 | 0 | двойной проход нормализации на здоровом пути (не блокирует, снято с записью) | `src/physical-geometry.ts` `budgets-glow-smoke.json` | | #217 | [SPEC-REVIEW-217-r1.md](SPEC-REVIEW-217-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | @@ -830,7 +835,7 @@ | #201 | [CODE-REVIEW-201-r1.md](CODE-REVIEW-201-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #200 | [SPEC-REVIEW-200-r1.md](SPEC-REVIEW-200-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | неточная формулировка причины дефекта в §3 ТЗ | `docs/specs/200-room-label-parity.md` `houseplan-card.ts` | | #200 | [CODE-REVIEW-200-r1.md](CODE-REVIEW-200-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #199 | [SPEC-REVIEW-199-r1.md](SPEC-REVIEW-199-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Английский текст сообщения об отказе и подсказки не зафиксирован; $sha.» — переменная не подставлена. Это дефект комментария, не ТЗ; на | `docs/specs/199-optimize-geometry-preflight.md` `docs/specs/223-optimize-coordinate-canonicalization.md` | +| #199 | [SPEC-REVIEW-199-r1.md](SPEC-REVIEW-199-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Английский текст сообщения об отказе и подсказки не зафиксирован дословно — только «экв…; Хендофф-комментарий автора ТЗ в issue содержит артефакт шаблона: «Коммит: $sha.» — пере… | `docs/specs/199-optimize-geometry-preflight.md` `docs/specs/223-optimize-coordinate-canonicalization.md` | | #199 | [SPEC-REVIEW-199-r2.md](SPEC-REVIEW-199-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #199 | [CODE-REVIEW-199-r1.md](CODE-REVIEW-199-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | / информационная — абсолютный p95-бюджет §10 нестабилен в CI-песочнице (не блокирует) | `validate.yml` `performance.yml` | | #198 | [SPEC-REVIEW-198-r1.md](SPEC-REVIEW-198-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | @@ -886,9 +891,9 @@ | #159 | [CODE-REVIEW-159-r1.md](CODE-REVIEW-159-r1.md) | code · r1 | ⚪ — | 1 | 1 | AC4 и AC9 не доказаны: golden:verify красный на финальном SHA, эталоны не приняты; README пакета не фиксирует SHA-256 исходного архива | `golden-report.json` `PROCESS.md` `AGENTS.md` `assets/furniture/houseplan-0.3.0/README.md` `README.md` `pack.json` `docs/FURNITURE.md` `docs/specs/159-furniture-pack.md` | | #159 | [CODE-REVIEW-159-r2.md](CODE-REVIEW-159-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #156 | [CODE-REVIEW-156-r1.md](CODE-REVIEW-156-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | -| #152 | [SPEC-REVIEW-152-r1.md](SPEC-REVIEW-152-r1.md) | spec · r1 | 🔴 красный | 2 | 2 | ни один AC не указывает способ доказательства; потерян отдельный проверяемый AC про синхронность hit targets во время перехода; accessibility-раздел выдаёт «существующую accessible-подпись» за факт, хотя такой досту…; «существующий» double-click/tap fit-all на фоне на деле существует только в kiosk; «нужно изменить UX». По факту #28 закрыт not_planned 2026-08-14 — до | `docs/specs/152-room-click-fit.md` `docs/specs/146-four-phase-sun-background.md` `docs/specs/138-adjacent-room-autoclose.md` `docs/specs/146-...md` `AGENTS.md` `src/houseplan-card.ts` `docs/SCOPE.md` `docs/UX-MODES.md` | +| #152 | [SPEC-REVIEW-152-r1.md](SPEC-REVIEW-152-r1.md) | spec · r1 | 🔴 красный | 2 | 2 | ни один AC не указывает способ доказательства; потерян отдельный проверяемый AC про синхронность hit targets во время перехода; accessibility-раздел выдаёт «существующую accessible-подпись» за факт, хотя такой досту…; «существующий» double-click/tap fit-all на фоне на деле существует только в kiosk; Low-1. §10 обсуждает #28 как открытую задачу, которой перед реализацией «нужно изменить… | `docs/specs/152-room-click-fit.md` `docs/specs/146-four-phase-sun-background.md` `docs/specs/138-adjacent-room-autoclose.md` `docs/specs/146-...md` `AGENTS.md` `src/houseplan-card.ts` `docs/SCOPE.md` `docs/UX-MODES.md` | | #152 | [SPEC-REVIEW-152-r2.md](SPEC-REVIEW-152-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #152 | [CODE-REVIEW-152-r1.md](CODE-REVIEW-152-r1.md) | code · r1 | 🔴 красный | 1 | 2 | demo/smoke_pan_any_zoom.mjs падает необработанным исключением — новый код не переживает…; Подпись комнаты в редакторах Devices/Decor получает нерабочую клавиатурную кнопку — нар…; Защита AC15 (запрет saveZoom для reason room) не зарегистрирована в mutation-gate, хотя…; 1. AC5 (вложенные комнаты) и AC9 (retarget между двумя разными комнатами | `demo/smoke_pan_any_zoom.mjs` `src/houseplan-card.ts` `smoke_backdrop.mjs` `smoke_editor_gestures.mjs` `smoke_hide_layers.mjs` `smoke_pan_any_zoom.mjs` `houseplan-card.ts` `validate.yml` | +| #152 | [CODE-REVIEW-152-r1.md](CODE-REVIEW-152-r1.md) | code · r1 | 🔴 красный | 1 | 2 | demo/smoke_pan_any_zoom.mjs падает необработанным исключением — новый код не переживает…; Подпись комнаты в редакторах Devices/Decor получает нерабочую клавиатурную кнопку — нар…; Защита AC15 (запрет saveZoom для reason room) не зарегистрирована в mutation-gate, хотя…; 1. AC5 (вложенные комнаты) и AC9 (retarget между двумя разными комнатами во время tween… | `demo/smoke_pan_any_zoom.mjs` `src/houseplan-card.ts` `smoke_backdrop.mjs` `smoke_editor_gestures.mjs` `smoke_hide_layers.mjs` `smoke_pan_any_zoom.mjs` `houseplan-card.ts` `validate.yml` | | #152 | [CODE-REVIEW-152-r2.md](CODE-REVIEW-152-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #150 | [CODE-REVIEW-150-r1.md](CODE-REVIEW-150-r1.md) | code · r1 | 🔴 красный | 1 | 0 | Собственный AC7-smoke красный при первом запуске — фикстура не включает show_borders, а… | `demo/smoke_wall_thickness_transition.mjs` `src/wall-thickness.ts` `src/houseplan-card.ts` `demo/smoke_split_corner_wall.mjs` `AGENTS.md` `docs/WALL-THICKNESS.md` `docs/TESTING.md` `smoke_split_corner_wall.mjs` | | #146 | [SPEC-REVIEW-146-r1.md](SPEC-REVIEW-146-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | azimuth тайно расширяет owner-решение о fallback-триггерах на саму фазу; «что человек увидит» длиннее одной фразы и использует термины реализации; нет буквальной touch-editor метки по docs/TOUCH-SUPPORT.md | `docs/specs/146-four-phase-sun-background.md` `docs/TOUCH-SUPPORT.md` | @@ -902,7 +907,7 @@ | #137 | [SPEC-REVIEW-137-r1.md](SPEC-REVIEW-137-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | терминология инструмента «Контур» вместо «Контур комнаты»; «что человек увидит» длиннее одной фразы; типы доказательства AC12–AC14 не входят буквально в перечень §2.5; план golden не описывает явно, чем доказывается forced-colours | `docs/specs/137-plan-snap-overlay.md` `src/i18n/ru.json` `docs/USER-GUIDE.ru.md` `PROCESS.md` `demo/golden/matrix.mjs` `harness.mjs` | | #132 | [SPEC-REVIEW-132-r1.md](SPEC-REVIEW-132-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | §2 использует термин реализации «host-сегмент»; нет обязательного маркера Touch editor: … по docs/TOUCH-SUPPORT.md; i18n-раздел не перечисляет конкретные ключи en/ru | `docs/specs/132-partition-openings.md` `PROCESS.md` `docs/USER-GUIDE.ru.md` `docs/TOUCH-SUPPORT.md` | | #132 | [CODE-REVIEW-132-r1.md](CODE-REVIEW-132-r1.md) | code · r1 | 🔴 красный | 1 | 3 | импорт/дублирование space с partition-hosted проёмом всегда отклоняется; находки (заведены отдельными issue); → #186 — нет jamb safety margin; → #187 — fallback-гвард источника света не fail-dark «по построению»; → #188 — тест junction-patch не умеет падать | `custom_components/houseplan/import_export.py` `custom_components/houseplan/validation.py` `validation.py` `tests_backend/test_ha_import_export.py` `src/partition-openings.ts` `src/space-render.ts` `src/houseplan-card.ts` `src/wall-thickness.ts` | -| #132 | [CODE-REVIEW-132-r2.md](CODE-REVIEW-132-r2.md) | code · r2 | 🟢 зелёный | 0 | 1 | Нет. High-1 из r1 исправлен корректно (см. «Как проверялось» — фикс, тест и; Второй компонент этого коммита восстанавливает presentation-cut для; → #189 — presentation snap-overlay не режет ось независимой перегородки в месте её собс…; Нет новых Low в этом цикле. Три Low из SPEC-REVIEW-132-r1 были закрыты до | `demo/serve.mjs` `src/houseplan-card.ts` `src/plan-snap-overlay.ts` `docs/CANVAS.md` `smoke_partition_openings.mjs` | +| #132 | [CODE-REVIEW-132-r2.md](CODE-REVIEW-132-r2.md) | code · r2 | 🟢 зелёный | 0 | 1 | Нет. High-1 из r1 исправлен корректно (см. «Как проверялось» — фикс, тест и зелёный CI); Второй компонент этого коммита восстанавливает presentation-cut для legacy room-wall op…; → #189 — presentation snap-overlay не режет ось независимой перегородки в месте её собс…; Нет новых Low в этом цикле. Три Low из SPEC-REVIEW-132-r1 были закрыты до начала кода (… | `demo/serve.mjs` `src/houseplan-card.ts` `src/plan-snap-overlay.ts` `docs/CANVAS.md` `smoke_partition_openings.mjs` | | #131 | [SPEC-REVIEW-131-r1.md](SPEC-REVIEW-131-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | плотная формулировка §7.2 про hash/warm-viewport взаимодействие | `docs/specs/131-readonly-cold-start.md` `src/houseplan-card.ts` | | #126 | [SPEC-REVIEW-126-r1.md](SPEC-REVIEW-126-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | в скоупе задачи (возврат автору); снимаются с записью (реализатор решает сам, без возврата цикла) | `docs/specs/126-ha-area-marker-relocation.md` `src/types.ts` `src/houseplan-card.ts` `custom_components/houseplan/validation.py` `src/devices.ts` | | #126 | [SPEC-REVIEW-126-r2.md](SPEC-REVIEW-126-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -941,13 +946,13 @@ | #74 | [CODE-REVIEW-74-r1.md](CODE-REVIEW-74-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | новый Undo/Redo toolbar рендерится без иконок из-за неактуального demo/srv/assets/icons…; AC2 «два устройства в LIFO-порядке» не продемонстрирован реальным перетаскиванием двух …; AC13 «доступные имена на поддерживаемых ширинах» проверены на одной ширине/теме | `demo/srv/assets/icons.js` `docs/specs/074-device-position-undo.md` `demo/smoke_device_position_history.mjs` `src/command-stack.ts` `test/command-stack.test.mjs` `src/houseplan-card.ts` `demo/golden/matrix.mjs` `demo/smoke_editor_tabs.mjs` | | #74 | [CODE-REVIEW-74-r2.md](CODE-REVIEW-74-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #68 | [CODE-REVIEW-issue-068-2026-08-12.md](CODE-REVIEW-issue-068-2026-08-12.md) | code · 2026-08-12 | ⚪ — | 0 | 0 | — | — | -| #62 | [SPEC-REVIEW-62-r1.md](SPEC-REVIEW-62-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | CONTRIBUTING.md останется противоречить новому contribution flow; AC2 не имеет явного маркера «Доказательство:» в отличие от остальных; AC5 и AC8 подмешивают в доказательство слово «inspection» (inspection | `CONTRIBUTING.md` `docs/specs/062-i18n-registry.md` `src/i18n.ts` `src/i18n/registry.ts` `src/editor.ts` | +| #62 | [SPEC-REVIEW-62-r1.md](SPEC-REVIEW-62-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | CONTRIBUTING.md останется противоречить новому contribution flow — AC9 не покрывает сущ…; AC2 не имеет явного маркера «Доказательство:» в отличие от остальных восьми AC. Формули…; AC5 и AC8 подмешивают в доказательство слово «inspection» (inspection compiled schema, … | `CONTRIBUTING.md` `docs/specs/062-i18n-registry.md` `src/i18n.ts` `src/i18n/registry.ts` `src/editor.ts` | | #62 | [SPEC-REVIEW-62-r2.md](SPEC-REVIEW-62-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #62 | [CODE-REVIEW-62-r1.md](CODE-REVIEW-62-r1.md) | code · r1 | 🔴 красный | 1 | 0 | 1 | `src/i18n/registry.ts` `src/i18n.ts` `CONTRIBUTING.md` `registry.ts` `test/i18n.test.mjs` | | #62 | [CODE-REVIEW-62-r2.md](CODE-REVIEW-62-r2.md) | code · r2 | 🟢 зелёный | 1 | 0 | — | — | | #57 | [SPEC-REVIEW-57-r1.md](SPEC-REVIEW-57-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | ТЗ молча сужает названные в issue call sites: «ripple» пропущен, параллельная семья «Об…; нет буквальной декларации Touch editor: … по docs/TOUCH-SUPPORT.md | `docs/specs/057-color-opacity-picker.md` `src/houseplan-card.ts` `houseplan-card.ts` `docs/TOUCH-SUPPORT.md` `docs/specs/068-help-affordance.md` | | #57 | [CODE-REVIEW-57-r1.md](CODE-REVIEW-57-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | реализация меняет визуальный рендер ещё в 4 golden-сценариях, не названных нигде в ТЗ/T… | `docs/TESTING.md` | -| #54 | [SPEC-REVIEW-54-r1.md](SPEC-REVIEW-54-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | нет обязательного раздела «Затронутые файлы и модули»; имя персоны не совпадает с таблицей docs/SCOPE.md; формулировка AC14 «backend/HA contract smoke on Linux CI» не согласована; численные performance-бюджеты не зафиксированы в ТЗ, откладываются на | `PROCESS.md` `226-entity-parent-dedup.md` `238-opening-inner-distances.md` `264-resize-controller.md` `340-config-set-revision.md` `348-german-localization.md` `docs/SCOPE.md` `AGENTS.md` | +| #54 | [SPEC-REVIEW-54-r1.md](SPEC-REVIEW-54-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | нет обязательного раздела «Затронутые файлы и модули». PROCESS.md §2.5 (DoR) требует бу…; имя персоны не совпадает с таблицей docs/SCOPE.md. §1 ТЗ: «Персона — Enthusiast/Power U…; формулировка AC14 «backend/HA contract smoke on Linux CI» не согласована с явным заявле…; численные performance-бюджеты не зафиксированы в ТЗ, откладываются на измеренный dev-ст… | `PROCESS.md` `226-entity-parent-dedup.md` `238-opening-inner-distances.md` `264-resize-controller.md` `340-config-set-revision.md` `348-german-localization.md` `docs/SCOPE.md` `AGENTS.md` | | #54 | [SPEC-REVIEW-54-r2.md](SPEC-REVIEW-54-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #54 | [CODE-REVIEW-54-r1.md](CODE-REVIEW-54-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | невалидный ответ Zigbee2MQTT на верном топике зависает на полный 150-секундный таймаут …; custom_components/houseplan/diagnostics.py:41 отдаёт config.get("settings", {}) без фил…; pushDirectionalLink (zigbee-topology.ts:114-126) маркирует код duplicate_link как для б…; плотность диффа в нескольких местах указывает на автоматическую вставку без переноса ст… | `src/zigbee-topology-runtime.ts` `custom_components/houseplan/diagnostics.py` `docs/CONFIG-COMPATIBILITY.md` `docs/SUPPORT-PRIVACY.md` `support_package.py` `diagnostics.py` `zigbee-topology.ts` `houseplan-card.ts` | | #54 | [CODE-REVIEW-54-r2.md](CODE-REVIEW-54-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | @@ -965,28 +970,28 @@ | #44 | [CODE-REVIEW-44-r1.md](CODE-REVIEW-44-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | у M1/M2 нет отдельного регресс-теста, доказательство — чтение + обратное воспроизведение | — | | #43 | [SPEC-REVIEW-43-r1.md](SPEC-REVIEW-43-r1.md) | spec · r1 | ⚪ — | 0 | 1 | support-relay/ не попадает ни в один класс изменений; отсутствует явная пометка Touch editor: … | `docs/specs/043-private-support-report.md` `AGENTS.md` `process-gate.mjs` `docs/ARCHITECTURE.md` `docs/SUPPORT-PRIVACY.md` `docs/TESTING.md` `docs/TOUCH-SUPPORT.md` | | #43 | [SPEC-REVIEW-43-r2.md](SPEC-REVIEW-43-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — | — | -| #43 | [SPEC-REVIEW-43-r3.md](SPEC-REVIEW-43-r3.md) | spec · r3 | 🟢 зелёный | 0 | 1 | Требование к источнику rate-limit не зафиксировано в ТЗ, хотя код и тесты; Продакшн-канал ha_webhook целиком зависит от одной автоматизации на личном | `docs/specs/043-private-support-report.md` `scripts/support-relay/tests/test_relay.py` `hp_relay/app.py` `app.py` `scripts/support-relay/README.md` | -| #43 | [SPEC-REVIEW-43-r4.md](SPEC-REVIEW-43-r4.md) | spec · r4 | 🟡 жёлтый | 0 | 1 | §9.2 закрывает находку r3 частично: описывает доверие к X-Forwarded-For | `scripts/support-relay/hp_relay/app.py` `config.py` `hp_relay/app.py` | +| #43 | [SPEC-REVIEW-43-r3.md](SPEC-REVIEW-43-r3.md) | spec · r3 | 🟢 зелёный | 0 | 1 | Требование к источнику rate-limit не зафиксировано в ТЗ, хотя код и тесты уже реализуют…; Продакшн-канал ha_webhook целиком зависит от одной автоматизации на личном Home Assista… | `docs/specs/043-private-support-report.md` `scripts/support-relay/tests/test_relay.py` `hp_relay/app.py` `app.py` `scripts/support-relay/README.md` | +| #43 | [SPEC-REVIEW-43-r4.md](SPEC-REVIEW-43-r4.md) | spec · r4 | 🟡 жёлтый | 0 | 1 | §9.2 закрывает находку r3 частично: описывает доверие к X-Forwarded-For как безусловный… | `scripts/support-relay/hp_relay/app.py` `config.py` `hp_relay/app.py` | | #43 | [SPEC-REVIEW-43-r5.md](SPEC-REVIEW-43-r5.md) | spec · r5 | 🟢 зелёный | 0 | 0 | — | — | | #43 | [CODE-REVIEW-43-r1.md](CODE-REVIEW-43-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | 1 Дешёвые гейты (прогнаны лично, HEAD 1ba53630); 2 Бэкенд Python (доступность харнесса); 3 Relay (scripts/support-relay/); 4 Смоки и golden; 5 Инварианты модели; 6 Одно число — один источник | `AGENTS.md` `PROCESS.md` `docs/images/screenshots.json` `houseplan-card.ts` `houseplan-editor-runtime.ts` `validate.yml` `demo/smoke_feedback_v2.mjs` `demo/smoke_help_affordance.mjs` | | #43 | [CODE-REVIEW-43-r2.md](CODE-REVIEW-43-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | -| #42 | [SPEC-REVIEW-42-r1.md](SPEC-REVIEW-42-r1.md) | spec · r1 | ⚪ — | 0 | 2 | AC5 не покрывает коды, эмитируемые не литералом в send_error(...); раздел «i18n» (обязателен по PROCESS.md §7.1) отсутствует; повторное использование err.…; Разделы «UX» и «Модель данных и миграция», формально обязательные по | `docs/specs/042-backend-engineering-quality.md` `websocket_api.py` `validation.py` `junction_limits.py` `houseplan-card.ts` `src/i18n/en.json` `src/i18n/ru.json` | +| #42 | [SPEC-REVIEW-42-r1.md](SPEC-REVIEW-42-r1.md) | spec · r1 | ⚪ — | 0 | 2 | AC5 не покрывает коды, эмитируемые не литералом в send_error(...); раздел «i18n» (обязателен по PROCESS.md §7.1) отсутствует; повторное использование err.…; Разделы «UX» и «Модель данных и миграция», формально обязательные по PROCESS.md §7.1 ка… | `docs/specs/042-backend-engineering-quality.md` `websocket_api.py` `validation.py` `junction_limits.py` `houseplan-card.ts` `src/i18n/en.json` `src/i18n/ru.json` | | #42 | [SPEC-REVIEW-42-r2.md](SPEC-REVIEW-42-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | AC5 и её мутант не синхронизированы с исправленным блоком 5; критерий приёмки снова нед… | `docs/specs/042-backend-engineering-quality.md` | | #42 | [SPEC-REVIEW-42-r3.md](SPEC-REVIEW-42-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | MarkerControlError описан в блоке 5/AC5 только по двум префиксным семействам; ~14 её ли… | `docs/specs/042-backend-engineering-quality.md` `validation.py` `websocket_api.py` | | #42 | [SPEC-REVIEW-42-r4.md](SPEC-REVIEW-42-r4.md) | spec · r4 | 🔴 красный | 0 | 1 | заявленный метод извлечения кода MarkerControlError («regex по вызовам MarkerControlErr… | `docs/specs/042-backend-engineering-quality.md` `validation.py` | | #42 | [CODE-REVIEW-42-r1.md](CODE-REVIEW-42-r1.md) | code · r1 | 🔴 красный | 2 | 0 | no-new-any красный на HEAD: новый необоснованный any; requirements_test.txt невозможно установить: бэкенд-CI не работал ни разу | `src/houseplan-card.ts` `scripts/no-new-any.mjs` `.github/workflows/mutation-gate.yml` | | #42 | [CODE-REVIEW-42-r2.md](CODE-REVIEW-42-r2.md) | code · r2 | 🔴 красный | 2 | 0 | docs-гейт красный: манифест скриншотов не совпадает ни с одним закоммиченным файлом; AC1 (coverage-baseline) недоказан прогоном ветки, но блокер внешний и уже заведён; ruff-долг scripts/+tests_backend/ шире объявленного include, но вне CI-скоупа; golden-расхождений на самом деле 8, не 4, но все вне скоупа #42 | `docs/images/screenshots.json` `capture.mjs` `validate.yml` `tests_backend/test_backend_quality.py` | -| #42 | [CODE-REVIEW-42-r6.md](CODE-REVIEW-42-r6.md) | code · r6 | 🟡 жёлтый | 0 | 1 | Mypy strict (блок 3, AC4) не имеет механизма исполнения в CI — только; 1. pyproject.toml [tool.ruff] include перечисляет | `validate.yml` `mutation-gate.yml` `const.py` `projection.py` `plans.py` `scripts/gate-reuse.mjs` `tests_backend/test_validation.py` `scripts/process-gate.mjs` | +| #42 | [CODE-REVIEW-42-r6.md](CODE-REVIEW-42-r6.md) | code · r6 | 🟡 жёлтый | 0 | 1 | Mypy strict (блок 3, AC4) не имеет механизма исполнения в CI — только текстовый контрак…; 1. pyproject.toml [tool.ruff] include перечисляет scripts/.py и tests_backend//.py нара… | `validate.yml` `mutation-gate.yml` `const.py` `projection.py` `plans.py` `scripts/gate-reuse.mjs` `tests_backend/test_validation.py` `scripts/process-gate.mjs` | | #39 | [SPEC-REVIEW-39-r1.md](SPEC-REVIEW-39-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 4 | нет обязательных продуктовых разделов §7.1 «сценарий» и «что человек увидит»; i18n-раздел не перечисляет ключи, DoR §2.5 не закрыть; нет разделов «Риски» и «Release-артефакты», обязательных по §7.1; AC4 объединяет два разных момента наступления hard без единого UI-контракта | `docs/specs/039-large-backdrops.md` | | #39 | [SPEC-REVIEW-39-r2.md](SPEC-REVIEW-39-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — | — | | #39 | [SPEC-REVIEW-39-r3.md](SPEC-REVIEW-39-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — | — | -| #39 | [CODE-REVIEW-39-r1.md](CODE-REVIEW-39-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | отмена гард-диалога во время busy не отменяет применение; «одно число, один источник» нарушено для HARD_DIMENSION; AC8 (EXIF-ориентация) не доказан ни тестом, ни явной записью; AC3/AC9 в ТЗ помечены «паритет-юнит», а по факту паритет base64 | `src/backdrop-pick.ts` `src/hp-dialog.ts` `demo/serve.mjs` `backdrop-pick.ts` `backdrop-probe.ts` `PROCESS.md` `docs/TESTING.md` `demo/smoke_backdrop_guard.mjs` | +| #39 | [CODE-REVIEW-39-r1.md](CODE-REVIEW-39-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | отмена гард-диалога во время busy не отменяет применение; «одно число, один источник» нарушено для HARD_DIMENSION; AC8 (EXIF-ориентация) не доказан ни тестом, ни явной записью; AC3/AC9 в ТЗ помечены «паритет-юнит», а по факту паритет base64 (b64ParityWithLegacyLoo… | `src/backdrop-pick.ts` `src/hp-dialog.ts` `demo/serve.mjs` `backdrop-pick.ts` `backdrop-probe.ts` `PROCESS.md` `docs/TESTING.md` `demo/smoke_backdrop_guard.mjs` | | #39 | [CODE-REVIEW-39-r2.md](CODE-REVIEW-39-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | два из трёх новых stillCurrent()-чеков не имеют собственного мутанта | `src/backdrop-pick.ts` `src/backdrop-probe.ts` `smoke_backdrop_guard.mjs` | | #33 | [SPEC-REVIEW-33-r1.md](SPEC-REVIEW-33-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | статус implemented не существует ни в перечислении, ни в каноне; 4 из 7 «const-деклараций фронта» для parity-теста не существуют; AC6 описывает несуществующее поведение как «расширение теста» | `scripts/config-field-registry.mjs` `docs/CONFIG-COMPATIBILITY.md` `houseplan-card.ts` `houseplan-editor-runtime.ts` `CONFIG-COMPATIBILITY.md` `src/logic.ts` `src/types.ts` `src/plan-optimizer.ts` | | #33 | [SPEC-REVIEW-33-r2.md](SPEC-REVIEW-33-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #33 | [CODE-REVIEW-33-r1.md](CODE-REVIEW-33-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | AC7-тест не может поймать то, для чего он написан; Дубликат записи в обоих CHANGELOG и в ARCHITECTURE.md; config-audit.mjs расширил exit-code 3 за пределы согласованного контракта, и для decisi… | `test/config-schema-parity.test.mjs` `scripts/config-schema-manifest.json` `scripts/config-schema.json` `src/houseplan-card.ts` `config-schema.json` `docs/CHANGELOG.md` `docs/CHANGELOG.ru.md` `docs/ARCHITECTURE.md` | | #33 | [CODE-REVIEW-33-r2.md](CODE-REVIEW-33-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | AC6 не имеет штатного регрессионного теста на изолированные decision-required/drop-on-v… | `test/config-audit.test.mjs` `oldest-supported.json` | -| #32 | [SPEC-REVIEW-32-r1.md](SPEC-REVIEW-32-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | DoR-пункт «влияние на производительность и бюджеты названо» не закрыт | `docs/specs/032-unified-danger-confirmation.md` `hp-confirm.ts` `AGENTS.md` `docs/specs/337-lazy-editor-chunk.md` `bundle-budget.mjs` | +| #32 | [SPEC-REVIEW-32-r1.md](SPEC-REVIEW-32-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | DoR-пункт «влияние на производительность и бюджеты названо» не закрыт, хотя задача доба… | `docs/specs/032-unified-danger-confirmation.md` `hp-confirm.ts` `AGENTS.md` `docs/specs/337-lazy-editor-chunk.md` `bundle-budget.mjs` | | #32 | [SPEC-REVIEW-32-r2.md](SPEC-REVIEW-32-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #32 | [CODE-REVIEW-32-r1.md](CODE-REVIEW-32-r1.md) | code · r1 | 🟡 жёлтый | 1 | 0 | миграция ломает существующие смоки: 2 дают неверный вердикт, 3 виснут навсегда; шесть старых односложных ключей i18n остались без потребителей | `demo/smoke_free_walls.mjs` `demo/smoke_registryless_opening.mjs` `demo/smoke_binding_picker.mjs` `demo/smoke_hidden_flag.mjs` `demo/smoke_optional_space_model.mjs` `smoke_lock_action.mjs` `smoke_lock_invariant.mjs` `smoke_saved_plans.mjs` | | #32 | [CODE-REVIEW-32-r2.md](CODE-REVIEW-32-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | из r1 — статус: снимаю решением ревьюера, с записью | `test/i18n.test.mjs` | diff --git a/scripts/merge-candidate.mjs b/scripts/merge-candidate.mjs index bd0d7b60..f4f6e1ce 100755 --- a/scripts/merge-candidate.mjs +++ b/scripts/merge-candidate.mjs @@ -22,10 +22,14 @@ import { spawnSync } from 'node:child_process'; import { appendFileSync } from 'node:fs'; import { isMainModule } from './spawn-portable.mjs'; +import { fileURLToPath } from 'node:url'; import { CI_PROOF_POLICIES, evaluateCiProof, githubCandidateTree, loadGithubProofContext, } from './ci-proof.mjs'; +/** Скрипт индекса — по абсолютному пути: слияние работает из чужого cwd (worktree кандидата). */ +const REVIEWS_INDEX_SCRIPT = fileURLToPath(new URL('./reviews-index.mjs', import.meta.url)); + export const MAX_ATTEMPTS = 3; export const VALIDATE_APPEAR_MS = 3 * 60 * 1000; export const VALIDATE_TOTAL_MS = 45 * 60 * 1000; @@ -121,7 +125,7 @@ export const sh = (cmd, args, opts = {}) => { }; export function realOps({ - repo, token, workflow = 'validate.yml', sleep = (ms) => new Promise((r) => setTimeout(r, ms)), + repo, token, issue = '', workflow = 'validate.yml', sleep = (ms) => new Promise((r) => setTimeout(r, ms)), now = Date.now, exec = sh, candidateTree = (sha) => githubCandidateTree({ repo, sha, token }), proofContext = (run) => loadGithubProofContext({ repo, run, token }), @@ -146,6 +150,11 @@ export function realOps({ must(git('checkout', '-q', '-B', 'merge-into-dev', branchTip), 'checkout'); const r = spawnSync('git', ['-c', 'user.name=claude[bot]', '-c', 'user.email=209825114+claude[bot]@users.noreply.github.com', 'rebase', onto], { encoding: 'utf8' }); if (r.status !== 0) { spawnSync('git', ['rebase', '--abort']); return null; } + // #635 r2: dev мог принести новые документы ревью — снимок INDEX.md + // в кандидате их не знает. Коммит индекса — doc-коммит конвейера: + // patch-id его не видит (`:!docs/reviews`), а тест «индекс свеж» в + // Validate кандидата без него был бы красным. + must(exec(process.execPath, [REVIEWS_INDEX_SCRIPT, '--dir=docs/reviews', '--commit-if-stale', `--issue=${issue}`]), 'reviews-index --commit-if-stale'); return must(git('rev-parse', 'HEAD'), 'rev-parse HEAD'); }, pushWithLease: (sha, ref, expected) => { @@ -278,7 +287,7 @@ if (isMainModule(import.meta.url)) { // #496: переносимо для Window console.error('usage: merge-candidate.mjs --branch= --material= --issue= [--repo=owner/name]; HP_PROCESS_TOKEN in env'); process.exit(2); } - const ops = realOps({ repo, token }); + const ops = realOps({ repo, token, issue }); mergeCandidate({ branch, material, issue, ops }).then((r) => { const out = `merged=${r.merged}\nto=${r.to || ''}\naction=${r.action}\ncandidate=${r.candidate}\n`; if (process.env.GITHUB_OUTPUT) appendFileSync(process.env.GITHUB_OUTPUT, out); diff --git a/scripts/mutation-registry.mjs b/scripts/mutation-registry.mjs index 17fd1d2e..5b5b1f28 100644 --- a/scripts/mutation-registry.mjs +++ b/scripts/mutation-registry.mjs @@ -8594,6 +8594,17 @@ const MUTANT_DEFINITIONS = [ replace: " for (const scope of [text]) { // mutant: first match anywhere in the document", }], }, + { + id: 'reviews-index-paragraph-tail', + guard: 'node --test --test-name-pattern="#635 r2: первый абзац" test/reviews-index.test.mjs', + because: 'r2 #635 M1: a finding without a heading is its first paragraph joined from wrapped ' + + 'lines; taking a single physical line yields the tail of a bullet («пусто). Не эскалирую…»)', + patches: [{ + file: 'scripts/reviews-index.mjs', + find: " current.push(line);\n }\n for (const paragraph of paragraphs) {", + replace: " current = [line]; // mutant: last physical line instead of the paragraph\n }\n for (const paragraph of paragraphs) {", + }], + }, { id: 'process-reconcile-restarts-healthy-run', guard: 'node --test test/process-reconcile.test.mjs', diff --git a/scripts/reviews-index.mjs b/scripts/reviews-index.mjs index 1bc68c16..84d723da 100644 --- a/scripts/reviews-index.mjs +++ b/scripts/reviews-index.mjs @@ -9,9 +9,17 @@ // пересобирается конвейером после публикации каждого документа ревью. // // node scripts/reviews-index.mjs [--dir=docs/reviews] [--output=docs/reviews/INDEX.md] [--check] +// node scripts/reviews-index.mjs --commit-if-stale --issue=NN [--dir=…] // -// `--check` — не писать, а сравнить с существующим файлом (гейт «индекс свеж»). +// `--check` — не писать, а сравнить с существующим файлом (гейт «индекс свеж»; +// тот же инвариант держит тест `#635 индекс свеж`). +// `--commit-if-stale` — пересобрать и, если файл изменился, закоммитить его +// коммитом конвейера (класс C). Индекс — снимок каталога: ребейз ветки на +// dev, получивший новые документы, устаревает его молча (r2 #635 H1), поэтому +// конвейер зовёт этот режим после каждого своего ребейза — при приведении к +// dev перед ревью и при слиянии кандидата. import { readdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; import { join } from 'node:path'; import { isMainModule } from './spawn-portable.mjs'; @@ -119,12 +127,42 @@ function severityBlocks(text) { return blocks; } +/** + * Первый абзац тела секции как заголовок находки без заголовка. Абзац — до + * пустой строки, перенесённые строки склеиваются: иначе у буллета, не + * уместившегося в одну физическую строку, брался его хвост (r2 #635 M1, + * `CODE-REVIEW-485-r4`: «пусто). Не эскалирую…»). Маркер буллета и код + * `**M1.**` снимаются; абзац, начинающийся с «не найдено»/«нет», — не находка. + */ +function firstParagraph(body) { + const paragraphs = []; + let current = []; + for (const raw of [...body, '']) { + const line = raw.trim(); + if (!line) { if (current.length) paragraphs.push(current.join(' ')); current = []; continue; } + if (/^[|#<]/.test(line) || /^