docs(reviews): индекс документов ревью, уроки, пересборка индекса конвейером (#635)

scripts/reviews-index.mjs собирает docs/reviews/INDEX.md: одна строка на
документ — issue, этап, раунд, вердикт (явная строка, раздел «Вердикт»,
свободная форма хвоста; 936 из 986 распознаны), High/Medium по строке вердикта
или заголовкам находок, до шести заголовков находок. Индекс детерминирован,
не индексирует сам себя, перечисляет файлы вне схемы имён; `--check` — гейт
свежести. process.yml публикует INDEX.md тем же коммитом, что документ ревью.

docs/LESSONS.md — датированные уроки со ссылками на источники (12 записей из
аудитов и разборов недели). PROCESS.md §2.10 — где искать решения.

Тесты: разбор имён, вердиктов, счётчиков, находок; фикстурный каталог;
живой каталог (100 % покрытие, >90 % вердиктов); контракт шага конвейера.
Мутанты reviews-index-skips-self-check, reviews-index-verdict-substring.

Issue: #635
User-Visible: no
This commit is contained in:
Claude
2026-09-23 13:52:23 +00:00
committed by claude[bot]
parent f234855e66
commit a50cbd8f91
7 changed files with 1321 additions and 0 deletions
+6
View File
@@ -1400,6 +1400,12 @@ jobs:
# забрал бы всё, что там окажется, а после reset там не должно быть
# ничего постороннего — но полагаться на «не должно» здесь нельзя.
git add -- "$doc" 2>/dev/null || true
# #635: индекс ревью пересобирается тем же коммитом, что и документ —
# иначе он устаревает на первом же раунде. Генерируемый файл, класс C.
if [ -f "$doc" ]; then
node scripts/reviews-index.mjs --dir=docs/reviews
git add -- docs/reviews/INDEX.md
fi
if git diff --cached --quiet; then
# Пустая рабочая копия — ещё не провал: ревьюер иногда коммитит
# документ сам, своим app-токеном мимо этого шага (CODE-REVIEW-150-r1,
+16
View File
@@ -329,6 +329,22 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready →
проверки, со ссылкой на документ того раунда и его материал. Без перечня
сокращение превращается в молчаливое доверие.
**Индекс документов ревью** — `docs/reviews/INDEX.md` (#635): одна строка на
документ — issue, этап, раунд, вердикт, число High/Medium, заголовки находок.
Файл генерируется `node scripts/reviews-index.mjs` и пересобирается конвейером
тем же коммитом, что публикует документ; руками не правится. Прежде чем брать
задачу по подсистеме, стоит прочитать её строки в индексе: что находили и чем
закрывали — там, а не в тысяче файлов. Уроки, пережившие свою задачу,
собираются в `docs/LESSONS.md` с датой и ссылкой на источник.
**Хранение документов** (решение владельца 23.09, #635): в `docs/reviews/`
лежат все раунды всех задач текущей линии — предыдущие раунды нужны ссылкам
«Унаследовано из r<N−1>» и якорям материала. При стабильном релизе документы
задач, вошедших в него (`RELEASE-MEMBERSHIP.json` линии), переносятся в
`legacy/reviews/<vX.Y.Z>/` одним коммитом класса C; индекс пересобирается и
перечисляет только живые. Перенос — часть чеклиста стабильного релиза, не
отдельная задача.
Дешёвые гейты (`typecheck`, `test`, `build` со сверкой копий бандла) гоняются в
каждом раунде: код изменился, а стоят они минуты. Тяжёлые — по дельте (§10.2).
+22
View File
@@ -0,0 +1,22 @@
# Уроки
Датированные выводы, пережившие свою задачу (#635). Каждый — одной мыслью, со
ссылкой на источник: документ ревью, issue, аудит. Полный след решений — в
`docs/reviews/INDEX.md` и комментариях issue; здесь только то, что меняет
поведение на следующей задаче. Конспекты ролей (#634) и промпт ревьюера
ссылаются сюда.
| Дата | Урок | Источник |
|---|---|---|
| 2026-08-23 | Одно число, видимое пользователю дважды (превью/факт, подпись/запись), обязано иметь один источник. | аудит 23.08, #233/#234, тест `single-source-numbers` |
| 2026-09-06 | Число смоков/тестов не живёт в тексте: считается командой (`npm run inventory`). | #472, PROCESS.md |
| 2026-09-09 | Мутанты по диффу — на кандидате, не на каждом push: 48 из 56 часов job-минут за два дня ушли в отменённые прогоны. | #510 |
| 2026-09-13 | Ненулевой exit гарда ≠ «мутант пойман»: setup-failure, invalid-mutation и survived различаются; засчитывается только assertion-killed. | #558, #568 |
| 2026-09-18 | Ревью на не принятых эталонах — потерянный цикл: `golden:verify` ревьюер гоняет лично, эталоны принимаются до `S7`. | CODE-REVIEW-598-r1 H1 |
| 2026-09-20 | Стенд ≠ Home Assistant: нативный `<dialog>` и `ha-dialog` — разные ветки; свидетель для реального HA — фикстура #505, а не golden стенда. | аудит 22.09 A/H1, #607, #609 |
| 2026-09-20 | Контролируемое поле без `live()` показывает не то число, что в состоянии; клампить на коммите (`change`), не на каждом символе. | аудит 22.09 A/H2, #608 |
| 2026-09-21 | Лог без итоговой строки — обрыв, а не «ok»: отчёт судит по маркеру завершения и исходу шага, не по отсутствию `FAIL`. | #604 |
| 2026-09-21 | На `main` после fast-forward `merge-base(dev, HEAD)` = HEAD: пустой дифф пропускает тяжёлые job, а гейт, судящий только самый свежий прогон, объявляет релиз красным. | аудит 22.09 D, #619 |
| 2026-09-22 | Обвязка процесса тоже рождает P1: дефекты #595/#596 нашлись в бою, а не тестами обвязки — тесты по тексту YAML и регэкспам исходников не заменяют фикстурного прогона. | аудит 22.09 |
| 2026-09-23 | Смена события коммита в общем контроле (`input` → `change`) краснит смоки, которые набор контролов не называют: связь символ → смок должна быть явной в `smoke-links`, иначе краснота доживает до ночи. | #639 |
| 2026-09-23 | Ожидание другого workflow внутри job — занятый раннер и потолок бюджета стадии; ждать должно событие (`workflow_run`) с маркером ожидания, а будить без маркера нельзя — это второй вызов модели. | #636 |
+996
View File
@@ -0,0 +1,996 @@
# Индекс ревью
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 990, issue: 343. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок.
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки |
|---|---|---|---|---:|---:|---|
| #639 | [CODE-REVIEW-639-r1.md](CODE-REVIEW-639-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #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-контейнер пересекал … |
| #613 | [SPEC-REVIEW-613-r2.md](SPEC-REVIEW-613-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #613 | [CODE-REVIEW-613-r1.md](CODE-REVIEW-613-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #612 | [CODE-REVIEW-612-r1.md](CODE-REVIEW-612-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #611 | [SPEC-REVIEW-611-r1.md](SPEC-REVIEW-611-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #611 | [SPEC-REVIEW-611-r2.md](SPEC-REVIEW-611-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #611 | [CODE-REVIEW-611-r1.md](CODE-REVIEW-611-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #610 | [SPEC-REVIEW-610-r1.md](SPEC-REVIEW-610-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #610 | [CODE-REVIEW-610-r1.md](CODE-REVIEW-610-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #610 | [CODE-REVIEW-610-r2.md](CODE-REVIEW-610-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #609 | [SPEC-REVIEW-609-r1.md](SPEC-REVIEW-609-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #609 | [CODE-REVIEW-609-r1.md](CODE-REVIEW-609-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #609 | [CODE-REVIEW-609-r2.md](CODE-REVIEW-609-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #608 | [SPEC-REVIEW-608-r1.md](SPEC-REVIEW-608-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | «Шесть потребителей» на самом деле семь вызовов rangeLine; Ответ владельца на Q1–Q3 не оставлен отдельным комментарием |
| #608 | [CODE-REVIEW-608-r1.md](CODE-REVIEW-608-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Русский changelog: сломанное предложение (Medium, в скоупе — правится в этой же задаче) |
| #608 | [CODE-REVIEW-608-r2.md](CODE-REVIEW-608-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #607 | [SPEC-REVIEW-607-r1.md](SPEC-REVIEW-607-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #607 | [CODE-REVIEW-607-r1.md](CODE-REVIEW-607-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #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 | — |
| #604 | [CODE-REVIEW-604-r1.md](CODE-REVIEW-604-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #603 | [SPEC-REVIEW-603-r1.md](SPEC-REVIEW-603-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #603 | [CODE-REVIEW-603-r1.md](CODE-REVIEW-603-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #602 | [SPEC-REVIEW-602-r1.md](SPEC-REVIEW-602-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #602 | [SPEC-REVIEW-602-r2.md](SPEC-REVIEW-602-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #602 | [CODE-REVIEW-602-r1.md](CODE-REVIEW-602-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #602 | [CODE-REVIEW-602-r2.md](CODE-REVIEW-602-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #601 | [CODE-REVIEW-601-r1.md](CODE-REVIEW-601-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #600 | [SPEC-REVIEW-600-r1.md](SPEC-REVIEW-600-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | регресс-гарантия для существующих кнопок действий не названа отдельным AC |
| #600 | [CODE-REVIEW-600-r1.md](CODE-REVIEW-600-r1.md) | code · r1 | 🟡 жёлтый | 0 | 4 | Room settings: подпись «Temperature» в 5-сегменте переносится посреди слова; Device dialog: у Glow radius появилась не согласованная владельцем блокировка Save; Дефект №5 (поповер «?» обрезается границей диалога комнаты) не имеет свидетеля закрытия; ACCEPTANCE.md: заявлено 11 эталонных сцен, фактически принято 13; docs/USER-GUIDE.ru.md:529 — испорченная строка таблицы |
| #600 | [CODE-REVIEW-600-r2.md](CODE-REVIEW-600-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | .hpf-seg label: min-width: fit-content (колонка не сжимается ниже слова) + overflow-wra…; glowRadiusValid/проблема marker-glow-radius удалены целиком; marker-dialog.ts больше не…; Свидетель добавлен: новый смок доказывает исполнением, что подсказка живёт вне скроллер…; Абзац переписан: явно «13 сцен» = 11 из ТЗ + 2 room-temperature-dialog-, с объяснением … |
| #598 | [SPEC-REVIEW-598-r1.md](SPEC-REVIEW-598-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 не имеет обещанного автотеста для диалога «Пространство» (закрыто чтением) |
| #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 | — |
| #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 | — |
| #597 | [CODE-REVIEW-597-r2.md](CODE-REVIEW-597-r2.md) | code · r2 | 🟢 зелёный | 0 | 1 | — |
| #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 | — |
| #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 | 0 | — |
| #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 | — |
| #593 | [SPEC-REVIEW-593-r2.md](SPEC-REVIEW-593-r2.md) | spec · r2 | 🟢 зелёный | 1 | 0 | — |
| #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 | — |
| #593 | [CODE-REVIEW-593-r2.md](CODE-REVIEW-593-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #592 | [SPEC-REVIEW-592-r1.md](SPEC-REVIEW-592-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #588 | [SPEC-REVIEW-588-r2.md](SPEC-REVIEW-588-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #587 | [CODE-REVIEW-587-r1.md](CODE-REVIEW-587-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #586 | [CODE-REVIEW-586-r1.md](CODE-REVIEW-586-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #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 | 0 | — |
| #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 не назван числом, как того требует соб… |
| #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 | — |
| #583 | [CODE-REVIEW-583-r1.md](CODE-REVIEW-583-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #582 | [CODE-REVIEW-582-r1.md](CODE-REVIEW-582-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #582 | [CODE-REVIEW-582-r2.md](CODE-REVIEW-582-r2.md) | code · r2 | 🔴 красный | 0 | 0 | — |
| #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 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #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 | — |
| #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 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #570 | [CODE-REVIEW-570-r1.md](CODE-REVIEW-570-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #569 | [CODE-REVIEW-569-r1.md](CODE-REVIEW-569-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #568 | [CODE-REVIEW-568-r1.md](CODE-REVIEW-568-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #567 | [CODE-REVIEW-567-r1.md](CODE-REVIEW-567-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #566 | [CODE-REVIEW-566-r1.md](CODE-REVIEW-566-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #566 | [CODE-REVIEW-566-r2.md](CODE-REVIEW-566-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #565 | [SPEC-REVIEW-565-r1.md](SPEC-REVIEW-565-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #565 | [CODE-REVIEW-565-r1.md](CODE-REVIEW-565-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #565 | [CODE-REVIEW-565-r2.md](CODE-REVIEW-565-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #564 | [SPEC-REVIEW-564-r1.md](SPEC-REVIEW-564-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | DoR: «затронутые файлы и модули» не названы (Medium, в скоупе); «Сценарий» и «Что человек увидит» объединены без явной персоны на |
| #564 | [SPEC-REVIEW-564-r2.md](SPEC-REVIEW-564-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #564 | [CODE-REVIEW-564-r1.md](CODE-REVIEW-564-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #564 | [CODE-REVIEW-564-r2.md](CODE-REVIEW-564-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #563 | [SPEC-REVIEW-563-r1.md](SPEC-REVIEW-563-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #563 | [CODE-REVIEW-563-r1.md](CODE-REVIEW-563-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #562 | [CODE-REVIEW-562-r1.md](CODE-REVIEW-562-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #562 | [CODE-REVIEW-562-r2.md](CODE-REVIEW-562-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #558 | [CODE-REVIEW-558-r1.md](CODE-REVIEW-558-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #557 | [CODE-REVIEW-557-r1.md](CODE-REVIEW-557-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #556 | [CODE-REVIEW-556-r1.md](CODE-REVIEW-556-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #556 | [CODE-REVIEW-556-r2.md](CODE-REVIEW-556-r2.md) | code · r2 | 🔴 красный | 0 | 0 | — |
| #555 | [CODE-REVIEW-555-r1.md](CODE-REVIEW-555-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #550 | [CODE-REVIEW-550-r1.md](CODE-REVIEW-550-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #549 | [CODE-REVIEW-549-r1.md](CODE-REVIEW-549-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #549 | [CODE-REVIEW-549-r2.md](CODE-REVIEW-549-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #548 | [CODE-REVIEW-548-r1.md](CODE-REVIEW-548-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #547 | [CODE-REVIEW-547-r1.md](CODE-REVIEW-547-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #546 | [CODE-REVIEW-546-r1.md](CODE-REVIEW-546-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #545 | [SPEC-REVIEW-545-r1.md](SPEC-REVIEW-545-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #545 | [CODE-REVIEW-545-r1.md](CODE-REVIEW-545-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #544 | [SPEC-REVIEW-544-r1.md](SPEC-REVIEW-544-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #544 | [CODE-REVIEW-544-r1.md](CODE-REVIEW-544-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #543 | [SPEC-REVIEW-543-r1.md](SPEC-REVIEW-543-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #543 | [SPEC-REVIEW-543-r2.md](SPEC-REVIEW-543-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #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 | — |
| #535 | [CODE-REVIEW-535-r1.md](CODE-REVIEW-535-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #534 | [SPEC-REVIEW-534-r1.md](SPEC-REVIEW-534-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #534 | [SPEC-REVIEW-534-r2.md](SPEC-REVIEW-534-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #534 | [SPEC-REVIEW-534-r3.md](SPEC-REVIEW-534-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — |
| #534 | [CODE-REVIEW-534-r1.md](CODE-REVIEW-534-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #533 | [CODE-REVIEW-533-r1.md](CODE-REVIEW-533-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #533 | [CODE-REVIEW-533-r2.md](CODE-REVIEW-533-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #533 | [CODE-REVIEW-533-r3.md](CODE-REVIEW-533-r3.md) | code · r3 | 🟡 жёлтый | 0 | 0 | — |
| #532 | [SPEC-REVIEW-532-r1.md](SPEC-REVIEW-532-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #532 | [SPEC-REVIEW-532-r2.md](SPEC-REVIEW-532-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #532 | [CODE-REVIEW-532-r1.md](CODE-REVIEW-532-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #532 | [CODE-REVIEW-532-r2.md](CODE-REVIEW-532-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #531 | [SPEC-REVIEW-531-r1.md](SPEC-REVIEW-531-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #531 | [SPEC-REVIEW-531-r2.md](SPEC-REVIEW-531-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #531 | [CODE-REVIEW-531-r1.md](CODE-REVIEW-531-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #531 | [CODE-REVIEW-531-r2.md](CODE-REVIEW-531-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #530 | [SPEC-REVIEW-530-r1.md](SPEC-REVIEW-530-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #530 | [SPEC-REVIEW-530-r2.md](SPEC-REVIEW-530-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #530 | [CODE-REVIEW-530-r1.md](CODE-REVIEW-530-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #529 | [SPEC-REVIEW-529-r1.md](SPEC-REVIEW-529-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #529 | [SPEC-REVIEW-529-r2.md](SPEC-REVIEW-529-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #529 | [CODE-REVIEW-529-r1.md](CODE-REVIEW-529-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #528 | [CODE-REVIEW-528-r1.md](CODE-REVIEW-528-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #526 | [SPEC-REVIEW-526-r1.md](SPEC-REVIEW-526-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #526 | [SPEC-REVIEW-526-r2.md](SPEC-REVIEW-526-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #526 | [CODE-REVIEW-526-r1.md](CODE-REVIEW-526-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #525 | [SPEC-REVIEW-525-r1.md](SPEC-REVIEW-525-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #525 | [CODE-REVIEW-525-r1.md](CODE-REVIEW-525-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #524 | [SPEC-REVIEW-524-r1.md](SPEC-REVIEW-524-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #524 | [CODE-REVIEW-524-r1.md](CODE-REVIEW-524-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #522 | [SPEC-REVIEW-522-r1.md](SPEC-REVIEW-522-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #521 | [SPEC-REVIEW-521-r1.md](SPEC-REVIEW-521-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #521 | [SPEC-REVIEW-521-r2.md](SPEC-REVIEW-521-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #521 | [SPEC-REVIEW-521-r3.md](SPEC-REVIEW-521-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #521 | [CODE-REVIEW-521-r1.md](CODE-REVIEW-521-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #521 | [CODE-REVIEW-521-r2.md](CODE-REVIEW-521-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #520 | [SPEC-REVIEW-520-r1.md](SPEC-REVIEW-520-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | — |
| #520 | [SPEC-REVIEW-520-r2.md](SPEC-REVIEW-520-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #520 | [SPEC-REVIEW-520-r3.md](SPEC-REVIEW-520-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — |
| #520 | [CODE-REVIEW-520-r1.md](CODE-REVIEW-520-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #520 | [CODE-REVIEW-520-r2.md](CODE-REVIEW-520-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | — |
| #520 | [CODE-REVIEW-520-r3.md](CODE-REVIEW-520-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #517 | [SPEC-REVIEW-517-r1.md](SPEC-REVIEW-517-r1.md) | spec · r1 | 🟢 зелёный | 0 | 2 | — |
| #517 | [SPEC-REVIEW-517-r2.md](SPEC-REVIEW-517-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #517 | [CODE-REVIEW-517-r1.md](CODE-REVIEW-517-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #516 | [CODE-REVIEW-516-r1.md](CODE-REVIEW-516-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #516 | [CODE-REVIEW-516-r2.md](CODE-REVIEW-516-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #515 | [CODE-REVIEW-515-r1.md](CODE-REVIEW-515-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #514 | [CODE-REVIEW-514-r4.md](CODE-REVIEW-514-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — |
| #513 | [CODE-REVIEW-513-r1.md](CODE-REVIEW-513-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #513 | [CODE-REVIEW-513-r2.md](CODE-REVIEW-513-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #512 | [SPEC-REVIEW-512-r1.md](SPEC-REVIEW-512-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | ТЗ не учитывает, что правка demo/docs/capture.mjs ломает captureScriptSha256 и красит d… |
| #512 | [SPEC-REVIEW-512-r2.md](SPEC-REVIEW-512-r2.md) | spec · r2 | 🔴 красный | 0 | 0 | — |
| #512 | [CODE-REVIEW-512-r1.md](CODE-REVIEW-512-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #511 | [SPEC-REVIEW-511-r1.md](SPEC-REVIEW-511-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #511 | [SPEC-REVIEW-511-r2.md](SPEC-REVIEW-511-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #511 | [CODE-REVIEW-511-r1.md](CODE-REVIEW-511-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #510 | [SPEC-REVIEW-510-r1.md](SPEC-REVIEW-510-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #510 | [SPEC-REVIEW-510-r2.md](SPEC-REVIEW-510-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #510 | [SPEC-REVIEW-510-r3.md](SPEC-REVIEW-510-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #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 | 0 | — |
| #510 | [CODE-REVIEW-510-r2.md](CODE-REVIEW-510-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #509 | [SPEC-REVIEW-509-r2.md](SPEC-REVIEW-509-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #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 | — |
| #508 | [CODE-REVIEW-508-r3.md](CODE-REVIEW-508-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #506 | [SPEC-REVIEW-506-r1.md](SPEC-REVIEW-506-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #506 | [CODE-REVIEW-506-r1.md](CODE-REVIEW-506-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #505 | [SPEC-REVIEW-505-r1.md](SPEC-REVIEW-505-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #505 | [SPEC-REVIEW-505-r2.md](SPEC-REVIEW-505-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #505 | [CODE-REVIEW-505-r1.md](CODE-REVIEW-505-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #505 | [CODE-REVIEW-505-r2.md](CODE-REVIEW-505-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #502 | [SPEC-REVIEW-502-r1.md](SPEC-REVIEW-502-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #502 | [CODE-REVIEW-502-r1.md](CODE-REVIEW-502-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #500 | [SPEC-REVIEW-500-r1.md](SPEC-REVIEW-500-r1.md) | spec · r1 | 🟡 жёлтый | 2 | 0 | — |
| #500 | [SPEC-REVIEW-500-r2.md](SPEC-REVIEW-500-r2.md) | spec · r2 | 🟡 жёлтый | 1 | 0 | — |
| #500 | [SPEC-REVIEW-500-r3.md](SPEC-REVIEW-500-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — |
| #500 | [CODE-REVIEW-500-r1.md](CODE-REVIEW-500-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #500 | [CODE-REVIEW-500-r2.md](CODE-REVIEW-500-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #500 | [CODE-REVIEW-500-r3.md](CODE-REVIEW-500-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #498 | [SPEC-REVIEW-498-r1.md](SPEC-REVIEW-498-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #498 | [SPEC-REVIEW-498-r2.md](SPEC-REVIEW-498-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #498 | [CODE-REVIEW-498-r1.md](CODE-REVIEW-498-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #495 | [SPEC-REVIEW-495-r1.md](SPEC-REVIEW-495-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #495 | [CODE-REVIEW-495-r1.md](CODE-REVIEW-495-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #493 | [SPEC-REVIEW-493-r1.md](SPEC-REVIEW-493-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #493 | [CODE-REVIEW-493-r1.md](CODE-REVIEW-493-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #492 | [SPEC-REVIEW-492-r1.md](SPEC-REVIEW-492-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #492 | [SPEC-REVIEW-492-r2.md](SPEC-REVIEW-492-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #492 | [CODE-REVIEW-492-r1.md](CODE-REVIEW-492-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #491 | [SPEC-REVIEW-491-r1.md](SPEC-REVIEW-491-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #491 | [CODE-REVIEW-491-r1.md](CODE-REVIEW-491-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #491 | [CODE-REVIEW-491-r2.md](CODE-REVIEW-491-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #490 | [SPEC-REVIEW-490-r1.md](SPEC-REVIEW-490-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #490 | [CODE-REVIEW-490-r1.md](CODE-REVIEW-490-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Recovery-адаптация обходит asset-readiness gate и continuity-overlay (в скоупе, Medium) |
| #490 | [CODE-REVIEW-490-r2.md](CODE-REVIEW-490-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #489 | [SPEC-REVIEW-489-r1.md](SPEC-REVIEW-489-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | Условие существования зум-кнопок противоречит текущему рендеру и не-скоупу (Medium, в с…; Гейт свежести документации (check-docs) не назван обязательным при правке src/ (Medium,…; data-hp-mode="device" расходится с уже опубликованным именем mode-devices (Medium, в ск… |
| #489 | [SPEC-REVIEW-489-r2.md](SPEC-REVIEW-489-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #489 | [CODE-REVIEW-489-r1.md](CODE-REVIEW-489-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #488 | [CODE-REVIEW-488-r1.md](CODE-REVIEW-488-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #487 | [SPEC-REVIEW-487-r1.md](SPEC-REVIEW-487-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #487 | [CODE-REVIEW-487-r1.md](CODE-REVIEW-487-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #486 | [SPEC-REVIEW-486-r1.md](SPEC-REVIEW-486-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | Сверка утверждений о текущем коде с фактическим origin/dev; Проверка полномочий продуктовых решений; Проверка обязательных разделов ТЗ (PROCESS.md §7.1); Проверка непротиворечивости с продуктовым скоупом |
| #486 | [CODE-REVIEW-486-r1.md](CODE-REVIEW-486-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | 1 Дешёвые гейты — приняты по ссылке, не перегонялись; 2 Тяжёлые гейты — не приняты вслепую, прослежены по истории CI ветки; 3 Что прогнал/перепроверил сам; 4 Вывод smoke-select.mjs (для протокола); 5 Таблица гейтов; 1 High — нет |
| #485 | [SPEC-REVIEW-485-r1.md](SPEC-REVIEW-485-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | 0 | — |
| #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 | 🔴 красный | 0 | 0 | — |
| #485 | [CODE-REVIEW-485-r2.md](CODE-REVIEW-485-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #485 | [CODE-REVIEW-485-r3.md](CODE-REVIEW-485-r3.md) | code · r3 | 🟡 жёлтый | 0 | 0 | — |
| #485 | [CODE-REVIEW-485-r4.md](CODE-REVIEW-485-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — |
| #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 | 0 | — |
| #482 | [SPEC-REVIEW-482-r2.md](SPEC-REVIEW-482-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #481 | [SPEC-REVIEW-481-r2.md](SPEC-REVIEW-481-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #481 | [CODE-REVIEW-481-r1.md](CODE-REVIEW-481-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #478 | [SPEC-REVIEW-478-r1.md](SPEC-REVIEW-478-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #478 | [CODE-REVIEW-478-r1.md](CODE-REVIEW-478-r1.md) | code · r1 | 🔴 красный | 2 | 4 | — |
| #478 | [CODE-REVIEW-478-r2.md](CODE-REVIEW-478-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | — |
| #478 | [CODE-REVIEW-478-r3.md](CODE-REVIEW-478-r3.md) | code · r3 | 🔴 красный | 0 | 0 | — |
| #477 | [SPEC-REVIEW-477-r1.md](SPEC-REVIEW-477-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #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 | — |
| #475 | [SPEC-REVIEW-475-r2.md](SPEC-REVIEW-475-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #475 | [CODE-REVIEW-475-r1.md](CODE-REVIEW-475-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #475 | [CODE-REVIEW-475-r2.md](CODE-REVIEW-475-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #474 | [SPEC-REVIEW-474-r1.md](SPEC-REVIEW-474-r1.md) | spec · r1 | 🔴 красный | 0 | 0 | — |
| #474 | [SPEC-REVIEW-474-r2.md](SPEC-REVIEW-474-r2.md) | spec · r2 | 🔴 красный | 0 | 0 | — |
| #474 | [CODE-REVIEW-474-r1.md](CODE-REVIEW-474-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #473 | [SPEC-REVIEW-473-r1.md](SPEC-REVIEW-473-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #473 | [SPEC-REVIEW-473-r2.md](SPEC-REVIEW-473-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #473 | [CODE-REVIEW-473-r1.md](CODE-REVIEW-473-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #472 | [SPEC-REVIEW-472-r1.md](SPEC-REVIEW-472-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #472 | [SPEC-REVIEW-472-r2.md](SPEC-REVIEW-472-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #472 | [CODE-REVIEW-472-r1.md](CODE-REVIEW-472-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Medium, в скоупе. SHA в отчёте — не тот, что был протестирован; Low, не блокирует. Поиск открытого issue по заголовку не проверен вживую |
| #472 | [CODE-REVIEW-472-r2.md](CODE-REVIEW-472-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #471 | [SPEC-REVIEW-471-r1.md](SPEC-REVIEW-471-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #471 | [CODE-REVIEW-471-r1.md](CODE-REVIEW-471-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #464 | [SPEC-REVIEW-464-r1.md](SPEC-REVIEW-464-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #464 | [CODE-REVIEW-464-r1.md](CODE-REVIEW-464-r1.md) | code · r1 | 🟡 жёлтый | 1 | 0 | — |
| #464 | [CODE-REVIEW-464-r2.md](CODE-REVIEW-464-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #463 | [SPEC-REVIEW-463-r1.md](SPEC-REVIEW-463-r1.md) | spec · r1 | ⚪ — | 0 | 0 | — |
| #463 | [SPEC-REVIEW-463-r2.md](SPEC-REVIEW-463-r2.md) | spec · r2 | 🔴 красный | 0 | 0 | — |
| #463 | [CODE-REVIEW-463-r1.md](CODE-REVIEW-463-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #462 | [SPEC-REVIEW-462-r1.md](SPEC-REVIEW-462-r1.md) | spec · r1 | ⚪ — | 0 | 0 | — |
| #462 | [SPEC-REVIEW-462-r2.md](SPEC-REVIEW-462-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #461 | [CODE-REVIEW-461-r1.md](CODE-REVIEW-461-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #461 | [CODE-REVIEW-461-r2.md](CODE-REVIEW-461-r2.md) | code · r2 | 🟢 зелёный | 0 | 1 | — |
| #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 | — |
| #459 | [SPEC-REVIEW-459-r1.md](SPEC-REVIEW-459-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #459 | [SPEC-REVIEW-459-r2.md](SPEC-REVIEW-459-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #459 | [CODE-REVIEW-459-r1.md](CODE-REVIEW-459-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #459 | [CODE-REVIEW-459-r2.md](CODE-REVIEW-459-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #457 | [SPEC-REVIEW-457-r1.md](SPEC-REVIEW-457-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #457 | [CODE-REVIEW-457-r1.md](CODE-REVIEW-457-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #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 отсутствует |
| #456 | [CODE-REVIEW-456-r2.md](CODE-REVIEW-456-r2.md) | code · r2 | 🟡 жёлтый | 0 | 3 | 1 Дешёвые гейты — прогнаны заново (код изменился, стоят минуты); 2 Гейты, закрывающие находки r1 — прогнаны целиком (не только для проверки на слово авт…; 3 Не прогонялось повторно — обосновано в §5 «Унаследовано» |
| #454 | [SPEC-REVIEW-454-r1.md](SPEC-REVIEW-454-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #454 | [SPEC-REVIEW-454-r2.md](SPEC-REVIEW-454-r2.md) | spec · r2 | 🔴 красный | 0 | 0 | — |
| #454 | [CODE-REVIEW-454-r3.md](CODE-REVIEW-454-r3.md) | code · r3 | 🟢 зелёный | 0 | 1 | — |
| #454 | [CODE-REVIEW-454-r4.md](CODE-REVIEW-454-r4.md) | code · r4 | 🟡 жёлтый | 0 | 0 | — |
| #451 | [SPEC-REVIEW-451-r1.md](SPEC-REVIEW-451-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | docs/PERFORMANCE.md не существует, но назван обязательным артефактом (Medium, в скоупе); docs/SCREENSHOTS.md не существует (Medium, в скоупе); верхняя граница диапазона «наблюдавшихся» замеров в §11.3 не подтверждена ни одним исто… |
| #451 | [SPEC-REVIEW-451-r2.md](SPEC-REVIEW-451-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #451 | [CODE-REVIEW-451-r1.md](CODE-REVIEW-451-r1.md) | code · r1 | 🔴 красный | 1 | 2 | — |
| #451 | [CODE-REVIEW-451-r2.md](CODE-REVIEW-451-r2.md) | code · r2 | 🔴 красный | 3 | 0 | — |
| #451 | [CODE-REVIEW-451-r3.md](CODE-REVIEW-451-r3.md) | code · r3 | 🟡 жёлтый | 3 | 1 | не заявленный в ТЗ постоянный отказ от live-preflight на больших планах, противоречит с… |
| #451 | [CODE-REVIEW-451-r4.md](CODE-REVIEW-451-r4.md) | code · r4 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #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 | 🔴 красный | 0 | 0 | — |
| #449 | [CODE-REVIEW-449-r2.md](CODE-REVIEW-449-r2.md) | code · r2 | 🔴 красный | 3 | 2 | — |
| #448 | [SPEC-REVIEW-448-r1.md](SPEC-REVIEW-448-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | 0 | — |
| #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 GRIDSTEPN, ч… |
| #447 | [SPEC-REVIEW-447-r2.md](SPEC-REVIEW-447-r2.md) | spec · r2 | 🔴 красный | 0 | 0 | — |
| #447 | [CODE-REVIEW-447-r1.md](CODE-REVIEW-447-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #445 | [SPEC-REVIEW-445-r1.md](SPEC-REVIEW-445-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #445 | [SPEC-REVIEW-445-r2.md](SPEC-REVIEW-445-r2.md) | spec · r2 | 🟢 зелёный | 0 | 1 | — |
| #445 | [CODE-REVIEW-445-r1.md](CODE-REVIEW-445-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #443 | [SPEC-REVIEW-443-r1.md](SPEC-REVIEW-443-r1.md) | spec · r1 | ⚪ — | 0 | 0 | — |
| #443 | [SPEC-REVIEW-443-r2.md](SPEC-REVIEW-443-r2.md) | spec · r2 | ⚪ — | 0 | 0 | — |
| #443 | [CODE-REVIEW-443-r1.md](CODE-REVIEW-443-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #442 | [SPEC-REVIEW-442-r1.md](SPEC-REVIEW-442-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #442 | [CODE-REVIEW-442-r1.md](CODE-REVIEW-442-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #441 | [CODE-REVIEW-441-r1.md](CODE-REVIEW-441-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #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 | — |
| #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/smokekiosk.mjs падает необработанным исключением на этом SHA; исключение «удалённого устройства» в подсчёте Q2 не имеет свидетеля; tap-target реордер/удаления в форме настроек меньше заявленных 44×44 CSS px; идентичность карточки (AC21) не имеет ни выделенного резолвера, ни свидетеля теста |
| #437 | [CODE-REVIEW-437-r2.md](CODE-REVIEW-437-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #437 | [CODE-REVIEW-437-r3.md](CODE-REVIEW-437-r3.md) | code · r3 | 🟡 жёлтый | 0 | 0 | — |
| #437 | [CODE-REVIEW-437-r4.md](CODE-REVIEW-437-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — |
| #434 | [SPEC-REVIEW-434-r1.md](SPEC-REVIEW-434-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #434 | [SPEC-REVIEW-434-r2.md](SPEC-REVIEW-434-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #434 | [CODE-REVIEW-434-r1.md](CODE-REVIEW-434-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #434 | [CODE-REVIEW-434-r2.md](CODE-REVIEW-434-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #432 | [SPEC-REVIEW-432-r1.md](SPEC-REVIEW-432-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #432 | [CODE-REVIEW-432-r1.md](CODE-REVIEW-432-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #431 | [SPEC-REVIEW-431-r1.md](SPEC-REVIEW-431-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #431 | [CODE-REVIEW-431-r1.md](CODE-REVIEW-431-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #428 | [SPEC-REVIEW-428-r1.md](SPEC-REVIEW-428-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #428 | [CODE-REVIEW-428-r1.md](CODE-REVIEW-428-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | Первопричина и правка contentstate(); contentmanifest() (exporter); Plan-only проекция (projectplanonlydecor, validateplanonlydocument); Тесты (testsbackend/testhaimportexport.py); Документация и changelog (AC8) |
| #427 | [CODE-REVIEW-427-r1.md](CODE-REVIEW-427-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #426 | [SPEC-REVIEW-426-r1.md](SPEC-REVIEW-426-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #426 | [CODE-REVIEW-426-r1.md](CODE-REVIEW-426-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #425 | [SPEC-REVIEW-425-r1.md](SPEC-REVIEW-425-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #425 | [SPEC-REVIEW-425-r2.md](SPEC-REVIEW-425-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #425 | [CODE-REVIEW-425-r1.md](CODE-REVIEW-425-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #424 | [CODE-REVIEW-424-r2.md](CODE-REVIEW-424-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #423 | [SPEC-REVIEW-423-r1.md](SPEC-REVIEW-423-r1.md) | spec · r1 | ⚪ — | 0 | 0 | — |
| #423 | [CODE-REVIEW-423-r1.md](CODE-REVIEW-423-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #422 | [SPEC-REVIEW-422-r1.md](SPEC-REVIEW-422-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #422 | [CODE-REVIEW-422-r1.md](CODE-REVIEW-422-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #422 | [CODE-REVIEW-422-r2.md](CODE-REVIEW-422-r2.md) | code · r2 | 🔴 красный | 1 | 2 | — |
| #421 | [SPEC-REVIEW-421-r1.md](SPEC-REVIEW-421-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #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 | — |
| #418 | [CODE-REVIEW-418-r1.md](CODE-REVIEW-418-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #417 | [CODE-REVIEW-417-r1.md](CODE-REVIEW-417-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #415 | [CODE-REVIEW-415-r1.md](CODE-REVIEW-415-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #415 | [CODE-REVIEW-415-r2.md](CODE-REVIEW-415-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #411 | [CODE-REVIEW-411-r1.md](CODE-REVIEW-411-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #406 | [SPEC-REVIEW-406-r1.md](SPEC-REVIEW-406-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #406 | [SPEC-REVIEW-406-r2.md](SPEC-REVIEW-406-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #406 | [SPEC-REVIEW-406-r3.md](SPEC-REVIEW-406-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | — |
| #406 | [SPEC-REVIEW-406-r4.md](SPEC-REVIEW-406-r4.md) | spec · r4 | 🟢 зелёный | 0 | 0 | — |
| #406 | [CODE-REVIEW-406-r1.md](CODE-REVIEW-406-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #406 | [CODE-REVIEW-406-r2.md](CODE-REVIEW-406-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #405 | [SPEC-REVIEW-405-r1.md](SPEC-REVIEW-405-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | a (Medium, в скоупе) — таблица «Место» неполна: пропущена обёртка houseplan-card.ts:785…; b (Low) — ссылка «#406 «д»» на несуществующий пункт |
| #405 | [SPEC-REVIEW-405-r2.md](SPEC-REVIEW-405-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #405 | [CODE-REVIEW-405-r1.md](CODE-REVIEW-405-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #403 | [SPEC-REVIEW-403-r1.md](SPEC-REVIEW-403-r1.md) | spec · r1 | ⚪ — | 1 | 0 | — |
| #403 | [SPEC-REVIEW-403-r2.md](SPEC-REVIEW-403-r2.md) | spec · r2 | 🟢 зелёный | 1 | 0 | — |
| #403 | [CODE-REVIEW-403-r1.md](CODE-REVIEW-403-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #402 | [SPEC-REVIEW-402-r1.md](SPEC-REVIEW-402-r1.md) | spec · r1 | ⚪ — | 1 | 1 | — |
| #402 | [SPEC-REVIEW-402-r2.md](SPEC-REVIEW-402-r2.md) | spec · r2 | 🔴 красный | 1 | 1 | — |
| #402 | [CODE-REVIEW-402-r1.md](CODE-REVIEW-402-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | AC2 не покрыт смоком буквально (ветки fixedfloor pending/invalid, !space); AC3 не проверен буквальным сценарием issue (клик по корзине → deleteServerPlan); AC8: тап по scrim не проверен явно; confirmDanger не проверяет языковой гейт warm явно |
| #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 | 0 | — |
| #400 | [CODE-REVIEW-400-r2.md](CODE-REVIEW-400-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #399 | [SPEC-REVIEW-399-r2.md](SPEC-REVIEW-399-r2.md) | spec · r2 | 🟢 зелёный | 0 | 1 | — |
| #399 | [CODE-REVIEW-399-r1.md](CODE-REVIEW-399-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #399 | [CODE-REVIEW-399-r2.md](CODE-REVIEW-399-r2.md) | code · r2 | 🟡 жёлтый | 1 | 0 | — |
| #398 | [SPEC-REVIEW-398-r1.md](SPEC-REVIEW-398-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #398 | [SPEC-REVIEW-398-r2.md](SPEC-REVIEW-398-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #398 | [SPEC-REVIEW-398-r3.md](SPEC-REVIEW-398-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #398 | [CODE-REVIEW-398-r1.md](CODE-REVIEW-398-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #397 | [SPEC-REVIEW-397-r1.md](SPEC-REVIEW-397-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #397 | [SPEC-REVIEW-397-r2.md](SPEC-REVIEW-397-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #397 | [CODE-REVIEW-397-r1.md](CODE-REVIEW-397-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #397 | [CODE-REVIEW-397-r2.md](CODE-REVIEW-397-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #396 | [SPEC-REVIEW-396-r1.md](SPEC-REVIEW-396-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | — |
| #396 | [SPEC-REVIEW-396-r2.md](SPEC-REVIEW-396-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #396 | [SPEC-REVIEW-396-r3.md](SPEC-REVIEW-396-r3.md) | spec · r3 | 🔴 красный | 0 | 0 | — |
| #396 | [CODE-REVIEW-396-r1.md](CODE-REVIEW-396-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #396 | [CODE-REVIEW-396-r2.md](CODE-REVIEW-396-r2.md) | code · r2 | ⚪ — | 0 | 0 | — |
| #391 | [SPEC-REVIEW-391-r1.md](SPEC-REVIEW-391-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #391 | [CODE-REVIEW-391-r1.md](CODE-REVIEW-391-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | 0 | — |
| #385 | [SPEC-REVIEW-385-r2.md](SPEC-REVIEW-385-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #384 | [SPEC-REVIEW-384-r1.md](SPEC-REVIEW-384-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #384 | [SPEC-REVIEW-384-r2.md](SPEC-REVIEW-384-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #384 | [CODE-REVIEW-384-r1.md](CODE-REVIEW-384-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #383 | [SPEC-REVIEW-383-r1.md](SPEC-REVIEW-383-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #383 | [CODE-REVIEW-383-r1.md](CODE-REVIEW-383-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #383 | [CODE-REVIEW-383-r2.md](CODE-REVIEW-383-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #381 | [SPEC-REVIEW-381-r1.md](SPEC-REVIEW-381-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #381 | [SPEC-REVIEW-381-r2.md](SPEC-REVIEW-381-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #381 | [CODE-REVIEW-381-r1.md](CODE-REVIEW-381-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #378 | [SPEC-REVIEW-378-r1.md](SPEC-REVIEW-378-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #378 | [CODE-REVIEW-378-r1.md](CODE-REVIEW-378-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #378 | [CODE-REVIEW-378-r2.md](CODE-REVIEW-378-r2.md) | code · r2 | 🟢 зелёный | 0 | 1 | — |
| #377 | [SPEC-REVIEW-377-r1.md](SPEC-REVIEW-377-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #377 | [SPEC-REVIEW-377-r2.md](SPEC-REVIEW-377-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #377 | [CODE-REVIEW-377-r1.md](CODE-REVIEW-377-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #377 | [CODE-REVIEW-377-r2.md](CODE-REVIEW-377-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #376 | [SPEC-REVIEW-376-r1.md](SPEC-REVIEW-376-r1.md) | spec · r1 | 🔴 красный | 1 | 2 | — |
| #376 | [SPEC-REVIEW-376-r2.md](SPEC-REVIEW-376-r2.md) | spec · r2 | 🟢 зелёный | 1 | 2 | Тело issue #376, строка сразу после заголовка «# ТЗ (лёгкий трек, редакция 2)»; gh issu…; Тело issue #376, раздел 6 (отсутствовал в редакции 1); Тело issue #376, раздел «2. AC», пункты 2 и 4 (в редакции 1 их не было — было только AC… |
| #376 | [CODE-REVIEW-376-r1.md](CODE-REVIEW-376-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #376 | [CODE-REVIEW-376-r2.md](CODE-REVIEW-376-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #376 | [CODE-REVIEW-376-r3.md](CODE-REVIEW-376-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #375 | [SPEC-REVIEW-375-r1.md](SPEC-REVIEW-375-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #375 | [SPEC-REVIEW-375-r2.md](SPEC-REVIEW-375-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #375 | [CODE-REVIEW-375-r1.md](CODE-REVIEW-375-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #374 | [SPEC-REVIEW-374-r1.md](SPEC-REVIEW-374-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #374 | [CODE-REVIEW-374-r1.md](CODE-REVIEW-374-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #373 | [SPEC-REVIEW-373-r1.md](SPEC-REVIEW-373-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #373 | [CODE-REVIEW-373-r1.md](CODE-REVIEW-373-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #373 | [CODE-REVIEW-373-r2.md](CODE-REVIEW-373-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #372 | [SPEC-REVIEW-372-r1.md](SPEC-REVIEW-372-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #372 | [CODE-REVIEW-372-r1.md](CODE-REVIEW-372-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #371 | [SPEC-REVIEW-371-r1.md](SPEC-REVIEW-371-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #371 | [SPEC-REVIEW-371-r2.md](SPEC-REVIEW-371-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #371 | [CODE-REVIEW-371-r1.md](CODE-REVIEW-371-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #371 | [CODE-REVIEW-371-r2.md](CODE-REVIEW-371-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #369 | [SPEC-REVIEW-369-r1.md](SPEC-REVIEW-369-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | — |
| #369 | [CODE-REVIEW-369-r3.md](CODE-REVIEW-369-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #368 | [CODE-REVIEW-368-r1.md](CODE-REVIEW-368-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #366 | [SPEC-REVIEW-366-r1.md](SPEC-REVIEW-366-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #366 | [SPEC-REVIEW-366-r2.md](SPEC-REVIEW-366-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #366 | [CODE-REVIEW-366-r1.md](CODE-REVIEW-366-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #363 | [SPEC-REVIEW-363-r1.md](SPEC-REVIEW-363-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | — |
| #363 | [CODE-REVIEW-363-r2.md](CODE-REVIEW-363-r2.md) | code · r2 | ⚪ — | 0 | 0 | — |
| #362 | [SPEC-REVIEW-362-r1.md](SPEC-REVIEW-362-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #362 | [CODE-REVIEW-362-r1.md](CODE-REVIEW-362-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #361 | [SPEC-REVIEW-361-r1.md](SPEC-REVIEW-361-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #361 | [SPEC-REVIEW-361-r2.md](SPEC-REVIEW-361-r2.md) | spec · r2 | 🟢 зелёный | 0 | 1 | — |
| #361 | [CODE-REVIEW-361-r1.md](CODE-REVIEW-361-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #361 | [CODE-REVIEW-361-r2.md](CODE-REVIEW-361-r2.md) | code · r2 | ⚪ — | 0 | 1 | — |
| #360 | [SPEC-REVIEW-360-r1.md](SPEC-REVIEW-360-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #359 | [SPEC-REVIEW-359-r1.md](SPEC-REVIEW-359-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #359 | [SPEC-REVIEW-359-r2.md](SPEC-REVIEW-359-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #359 | [CODE-REVIEW-359-r1.md](CODE-REVIEW-359-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #359 | [CODE-REVIEW-359-r2.md](CODE-REVIEW-359-r2.md) | code · r2 | 🔴 красный | 0 | 0 | — |
| #358 | [SPEC-REVIEW-358-r1.md](SPEC-REVIEW-358-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #358 | [CODE-REVIEW-358-r1.md](CODE-REVIEW-358-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #357 | [SPEC-REVIEW-357-r1.md](SPEC-REVIEW-357-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #357 | [CODE-REVIEW-357-r1.md](CODE-REVIEW-357-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #356 | [CODE-REVIEW-356-r1.md](CODE-REVIEW-356-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #354 | [SPEC-REVIEW-354-r1.md](SPEC-REVIEW-354-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #354 | [CODE-REVIEW-354-r1.md](CODE-REVIEW-354-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #354 | [CODE-REVIEW-354-r2.md](CODE-REVIEW-354-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #353 | [SPEC-REVIEW-353-r1.md](SPEC-REVIEW-353-r1.md) | spec · r1 | 🟡 жёлтый | 1 | 1 | — |
| #353 | [SPEC-REVIEW-353-r2.md](SPEC-REVIEW-353-r2.md) | spec · r2 | 🟡 жёлтый | 1 | 1 | — |
| #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 унаследует «ß», хотя стандартная швейцарская орфография его не использует; явного блока «принято предположительно, поменять свободно» в конце документа нет |
| #348 | [CODE-REVIEW-348-r1.md](CODE-REVIEW-348-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #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 | 🔴 красный | 0 | 0 | — |
| #337 | [CODE-REVIEW-337-r2.md](CODE-REVIEW-337-r2.md) | code · r2 | 🔴 красный | 0 | 0 | — |
| #337 | [CODE-REVIEW-337-r3.md](CODE-REVIEW-337-r3.md) | code · r3 | 🔴 красный | 1 | 0 | — |
| #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 | — |
| #335 | [SPEC-REVIEW-335-r2.md](SPEC-REVIEW-335-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #335 | [CODE-REVIEW-335-r1.md](CODE-REVIEW-335-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #333 | [SPEC-REVIEW-333-r1.md](SPEC-REVIEW-333-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | AC4 называет способ доказательства, который не проверяет заявленное (Medium, в скоупе з… |
| #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 | — |
| #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 | — |
| #331 | [SPEC-REVIEW-331-r2.md](SPEC-REVIEW-331-r2.md) | spec · r2 | 🔴 красный | 0 | 1 | — |
| #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-артефакты |
| #330 | [SPEC-REVIEW-330-r2.md](SPEC-REVIEW-330-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #330 | [CODE-REVIEW-330-r2.md](CODE-REVIEW-330-r2.md) | code · r2 | ⚪ — | 0 | 1 | — |
| #330 | [CODE-REVIEW-330-r3.md](CODE-REVIEW-330-r3.md) | code · r3 | 🔴 красный | 1 | 0 | докс-гейт красный на HEAD ревью (в скоупе, блокирует) |
| #330 | [CODE-REVIEW-330-r4.md](CODE-REVIEW-330-r4.md) | code · r4 | 🟡 жёлтый | 1 | 0 | — |
| #329 | [SPEC-REVIEW-329-r1.md](SPEC-REVIEW-329-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #329 | [SPEC-REVIEW-329-r2.md](SPEC-REVIEW-329-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #329 | [SPEC-REVIEW-329-r3.md](SPEC-REVIEW-329-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #329 | [CODE-REVIEW-329-r1.md](CODE-REVIEW-329-r1.md) | code · r1 | 🔴 красный | 1 | 4 | — |
| #329 | [CODE-REVIEW-329-r2.md](CODE-REVIEW-329-r2.md) | code · r2 | 🔴 красный | 1 | 4 | — |
| #329 | [CODE-REVIEW-329-r3.md](CODE-REVIEW-329-r3.md) | code · r3 | 🔴 красный | 0 | 0 | — |
| #324 | [CODE-REVIEW-324-r1.md](CODE-REVIEW-324-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #323 | [CODE-REVIEW-323-r1.md](CODE-REVIEW-323-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #319 | [SPEC-REVIEW-319-r1.md](SPEC-REVIEW-319-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #317 | [CODE-REVIEW-317-r1.md](CODE-REVIEW-317-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #316 | [SPEC-REVIEW-316-r1.md](SPEC-REVIEW-316-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #316 | [SPEC-REVIEW-316-r2.md](SPEC-REVIEW-316-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #316 | [SPEC-REVIEW-316-r3.md](SPEC-REVIEW-316-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | — |
| #316 | [SPEC-REVIEW-316-r4.md](SPEC-REVIEW-316-r4.md) | spec · r4 | 🟢 зелёный | 0 | 0 | — |
| #316 | [CODE-REVIEW-316-r1.md](CODE-REVIEW-316-r1.md) | code · r1 | 🔴 красный | 1 | 1 | — |
| #316 | [CODE-REVIEW-316-r2.md](CODE-REVIEW-316-r2.md) | code · r2 | 🔴 красный | 1 | 1 | — |
| #314 | [SPEC-REVIEW-314-r1.md](SPEC-REVIEW-314-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #314 | [CODE-REVIEW-314-r1.md](CODE-REVIEW-314-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | — |
| #313 | [SPEC-REVIEW-313-r1.md](SPEC-REVIEW-313-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #313 | [CODE-REVIEW-313-r1.md](CODE-REVIEW-313-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #313 | [CODE-REVIEW-313-r2.md](CODE-REVIEW-313-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #310 | [SPEC-REVIEW-310-r1.md](SPEC-REVIEW-310-r1.md) | spec · r1 | 🔴 красный | 0 | 0 | — |
| #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 | ⚪ — | 0 | 0 | — |
| #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 | 0 | — |
| #309 | [SPEC-REVIEW-309-r2.md](SPEC-REVIEW-309-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #309 | [SPEC-REVIEW-309-r3.md](SPEC-REVIEW-309-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | — |
| #309 | [CODE-REVIEW-309-r1.md](CODE-REVIEW-309-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #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 | — |
| #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 Что НЕ прогонялось и почему |
| #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 | — |
| #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-тестов в отчёте разработчика на единицу отличается от факта |
| #302 | [SPEC-REVIEW-302-r1.md](SPEC-REVIEW-302-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #302 | [CODE-REVIEW-302-r1.md](CODE-REVIEW-302-r1.md) | code · r1 | ⚪ — | 0 | 2 | — |
| #302 | [CODE-REVIEW-302-r2.md](CODE-REVIEW-302-r2.md) | code · r2 | ⚪ — | 0 | 1 | — |
| #302 | [CODE-REVIEW-302-r4.md](CODE-REVIEW-302-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — |
| #301 | [SPEC-REVIEW-301-r1.md](SPEC-REVIEW-301-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #301 | [CODE-REVIEW-301-r1.md](CODE-REVIEW-301-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #300 | [SPEC-REVIEW-300-r1.md](SPEC-REVIEW-300-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #300 | [SPEC-REVIEW-300-r2.md](SPEC-REVIEW-300-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #300 | [SPEC-REVIEW-300-r3.md](SPEC-REVIEW-300-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 1 | — |
| #300 | [SPEC-REVIEW-300-r4.md](SPEC-REVIEW-300-r4.md) | spec · r4 | 🟡 жёлтый | 0 | 0 | — |
| #299 | [SPEC-REVIEW-299-r1.md](SPEC-REVIEW-299-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #298 | [SPEC-REVIEW-298-r1.md](SPEC-REVIEW-298-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #298 | [SPEC-REVIEW-298-r2.md](SPEC-REVIEW-298-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #298 | [CODE-REVIEW-298-r1.md](CODE-REVIEW-298-r1.md) | code · r1 | 🔴 красный | 2 | 0 | — |
| #296 | [SPEC-REVIEW-296-r1.md](SPEC-REVIEW-296-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #296 | [CODE-REVIEW-296-r1.md](CODE-REVIEW-296-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #295 | [SPEC-REVIEW-295-r1.md](SPEC-REVIEW-295-r1.md) | spec · r1 | 🟡 жёлтый | 1 | 1 | — |
| #295 | [SPEC-REVIEW-295-r2.md](SPEC-REVIEW-295-r2.md) | spec · r2 | 🟡 жёлтый | 1 | 1 | — |
| #295 | [CODE-REVIEW-295-r1.md](CODE-REVIEW-295-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #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 | 0 | — |
| #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 | — |
| #294 | [CODE-REVIEW-294-r2.md](CODE-REVIEW-294-r2.md) | code · r2 | 🟢 зелёный | 0 | 2 | — |
| #293 | [SPEC-REVIEW-293-r1.md](SPEC-REVIEW-293-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #293 | [SPEC-REVIEW-293-r2.md](SPEC-REVIEW-293-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #293 | [CODE-REVIEW-293-r1.md](CODE-REVIEW-293-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #292 | [SPEC-REVIEW-292-r1.md](SPEC-REVIEW-292-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | 0 | — |
| #291 | [SPEC-REVIEW-291-r2.md](SPEC-REVIEW-291-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #291 | [SPEC-REVIEW-291-r3.md](SPEC-REVIEW-291-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #291 | [CODE-REVIEW-291-r1.md](CODE-REVIEW-291-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #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 | 0 | — |
| #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 — реальные планы |
| #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 | — |
| #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 | — |
| #289 | [SPEC-REVIEW-289-r2.md](SPEC-REVIEW-289-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #289 | [CODE-REVIEW-289-r1.md](CODE-REVIEW-289-r1.md) | code · r1 | 🟢 зелёный | 1 | 1 | Незапланированный код #260 в ветке #289 ломает два golden-эталона, третий не принят (Hi…; Golden-эталон safe-resize-handles-clamp-{dark,light} не обновлён под настоящее поведени… |
| #289 | [CODE-REVIEW-289-r2.md](CODE-REVIEW-289-r2.md) | code · r2 | 🟢 зелёный | 1 | 1 | — |
| #288 | [SPEC-REVIEW-288-r1.md](SPEC-REVIEW-288-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | — |
| #288 | [SPEC-REVIEW-288-r2.md](SPEC-REVIEW-288-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #288 | [CODE-REVIEW-288-r1.md](CODE-REVIEW-288-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #288 | [CODE-REVIEW-288-r2.md](CODE-REVIEW-288-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #288 | [CODE-REVIEW-288-r3.md](CODE-REVIEW-288-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #282 | [SPEC-REVIEW-282-r1.md](SPEC-REVIEW-282-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #282 | [SPEC-REVIEW-282-r2.md](SPEC-REVIEW-282-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #282 | [CODE-REVIEW-282-r1.md](CODE-REVIEW-282-r1.md) | code · r1 | 🔴 красный | 2 | 4 | #278-guard «отклонить правку деградированного пространства» больше не срабатывает; Широкая регрессия структурных операций редактирования; AC15 добавил новую строку в Optimize-диалог — golden baseline не обновлён; AC5 «executable source/AST guard + bypass mutant for each writer family» реализован уже…; wallmodelclientoutdated не срабатывает в реалистичном сценарии старого клиента; Регрессионный тест issue #248 ослаблен без обновления фикстуры |
| #282 | [CODE-REVIEW-282-r2.md](CODE-REVIEW-282-r2.md) | code · r2 | 🔴 красный | 2 | 0 | npm test красный: диагностика больше не соответствует контракту, который сама же проверяет; AC7 нарушен: opening на обычной стене исчезает со Static-карточки после миграции в v8 |
| #282 | [CODE-REVIEW-282-r3.md](CODE-REVIEW-282-r3.md) | code · r3 | 🔴 красный | 1 | 0 | AC7 всё ещё нарушен: Static-карточка рисует сплошную стену прямо по месту прохода после… |
| #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 | 0 | — |
| #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 | — |
| #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 реального плана |
| #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 | 0 | — |
| #277 | [CODE-REVIEW-277-r2.md](CODE-REVIEW-277-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #276 | [SPEC-REVIEW-276-r1.md](SPEC-REVIEW-276-r1.md) | spec · r1 | 🔴 красный | 1 | 3 | — |
| #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 | — |
| #276 | [CODE-REVIEW-276-r1.md](CODE-REVIEW-276-r1.md) | code · r1 | 🟡 жёлтый | 0 | 3 | AC11 (перф-бюджет §10) не доказан ни автотестом, ни явным; AC3 «несколько hosted openings на одной partition» не покрыто тестом; AC5 «targeted golden» не добавлен ни в каком виде |
| #276 | [CODE-REVIEW-276-r2.md](CODE-REVIEW-276-r2.md) | code · r2 | 🟡 жёлтый | 0 | 3 | r2 (Medium, в скоупе, чинится тем же автором) — benchmark:coincident-partitions даёт си… |
| #276 | [CODE-REVIEW-276-r3.md](CODE-REVIEW-276-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | — |
| #275 | [SPEC-REVIEW-275-r1.md](SPEC-REVIEW-275-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #275 | [SPEC-REVIEW-275-r2.md](SPEC-REVIEW-275-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #275 | [SPEC-REVIEW-275-r3.md](SPEC-REVIEW-275-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #275 | [CODE-REVIEW-275-r1.md](CODE-REVIEW-275-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #274 | [SPEC-REVIEW-274-r1.md](SPEC-REVIEW-274-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #274 | [CODE-REVIEW-274-r1.md](CODE-REVIEW-274-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #273 | [SPEC-REVIEW-273-r1.md](SPEC-REVIEW-273-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #273 | [SPEC-REVIEW-273-r2.md](SPEC-REVIEW-273-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #273 | [CODE-REVIEW-273-r1.md](CODE-REVIEW-273-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #272 | [SPEC-REVIEW-272-r1.md](SPEC-REVIEW-272-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #272 | [SPEC-REVIEW-272-r2.md](SPEC-REVIEW-272-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #272 | [CODE-REVIEW-272-r1.md](CODE-REVIEW-272-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #271 | [SPEC-REVIEW-271-r1.md](SPEC-REVIEW-271-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #271 | [CODE-REVIEW-271-r1.md](CODE-REVIEW-271-r1.md) | code · r1 | 🔴 красный | 1 | 1 | — |
| #271 | [CODE-REVIEW-271-r2.md](CODE-REVIEW-271-r2.md) | code · r2 | 🟢 зелёный | 1 | 1 | — |
| #271 | [CODE-REVIEW-271-r3.md](CODE-REVIEW-271-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #269 | [CODE-REVIEW-269-r1.md](CODE-REVIEW-269-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #267 | [SPEC-REVIEW-267-r1.md](SPEC-REVIEW-267-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #267 | [CODE-REVIEW-267-r1.md](CODE-REVIEW-267-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #267 | [CODE-REVIEW-267-r2.md](CODE-REVIEW-267-r2.md) | code · r2 | 🔴 красный | 0 | 0 | — |
| #266 | [SPEC-REVIEW-266-r1.md](SPEC-REVIEW-266-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | Medium (в скоупе) — заявленный «объективный критерий» (golden) не видит два реальных CS…; Low — неверная классификация вспомогательного скрипта; Low (наблюдение, не требует правки ТЗ) — лимит «≤ 1200 строк» на файл (AC2) может не вы… |
| #266 | [SPEC-REVIEW-266-r2.md](SPEC-REVIEW-266-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Medium (в скоупе) — новый AC2 противоречит сам себе: заявленный порог суммы уже нарушен… |
| #266 | [SPEC-REVIEW-266-r3.md](SPEC-REVIEW-266-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #266 | [CODE-REVIEW-266-r1.md](CODE-REVIEW-266-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #265 | [SPEC-REVIEW-265-r1.md](SPEC-REVIEW-265-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 4 | «что человек увидит» слито со сценарием и написано языком реализации; поверхность/touch…; AC10 хеджирует «если отчёт станет виден пользователю», хотя §9 безусловно описывает нов…; AC1–AC9 не называют способ доказательства (в отличие от требования DoR и от прямого сос…; нет отдельного обязательного раздела «Риски» |
| #265 | [SPEC-REVIEW-265-r2.md](SPEC-REVIEW-265-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | AC10 называет несуществующий гейт check-i18n как обязательное доказательство (Medium, в… |
| #265 | [SPEC-REVIEW-265-r3.md](SPEC-REVIEW-265-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — |
| #265 | [CODE-REVIEW-265-r1.md](CODE-REVIEW-265-r1.md) | code · r1 | 🔴 красный | 1 | 2 | — |
| #264 | [SPEC-REVIEW-264-r1.md](SPEC-REVIEW-264-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #264 | [SPEC-REVIEW-264-r2.md](SPEC-REVIEW-264-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #264 | [CODE-REVIEW-264-r1.md](CODE-REVIEW-264-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #262 | [SPEC-REVIEW-262-r1.md](SPEC-REVIEW-262-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #262 | [CODE-REVIEW-262-r1.md](CODE-REVIEW-262-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #261 | [SPEC-REVIEW-261-r1.md](SPEC-REVIEW-261-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #258 | [CODE-REVIEW-258-r1.md](CODE-REVIEW-258-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 | — |
| #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 | 0 | — |
| #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 | — |
| #251 | [SPEC-REVIEW-251-r1.md](SPEC-REVIEW-251-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | не проговорено соответствие toast'а формулировке владельца «стандартными средствами HA»; не решён смешанный secure + unavailable случай в группе controls |
| #251 | [CODE-REVIEW-251-r1.md](CODE-REVIEW-251-r1.md) | code · r1 | ⚪ — | 1 | 0 | — |
| #251 | [CODE-REVIEW-251-r2.md](CODE-REVIEW-251-r2.md) | code · r2 | 🔴 красный | 1 | 0 | — |
| #251 | [CODE-REVIEW-251-r3.md](CODE-REVIEW-251-r3.md) | code · r3 | 🔴 красный | 1 | 0 | — |
| #250 | [SPEC-REVIEW-250-r1.md](SPEC-REVIEW-250-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #250 | [CODE-REVIEW-250-r1.md](CODE-REVIEW-250-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #250 | [CODE-REVIEW-250-r2.md](CODE-REVIEW-250-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #249 | [SPEC-REVIEW-249-r1.md](SPEC-REVIEW-249-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #249 | [SPEC-REVIEW-249-r2.md](SPEC-REVIEW-249-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #249 | [CODE-REVIEW-249-r1.md](CODE-REVIEW-249-r1.md) | code · r1 | 🔴 красный | 1 | 1 | — |
| #249 | [CODE-REVIEW-249-r2.md](CODE-REVIEW-249-r2.md) | code · r2 | ⚪ — | 0 | 0 | — |
| #248 | [SPEC-REVIEW-248-r1.md](SPEC-REVIEW-248-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | 0 | — |
| #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 | — |
| #244 | [CODE-REVIEW-244-r2.md](CODE-REVIEW-244-r2.md) | code · r2 | ⚪ — | 2 | 0 | — |
| #244 | [CODE-REVIEW-244-r3.md](CODE-REVIEW-244-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #243 | [SPEC-REVIEW-243-r1.md](SPEC-REVIEW-243-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #243 | [CODE-REVIEW-243-r1.md](CODE-REVIEW-243-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #243 | [CODE-REVIEW-243-r2.md](CODE-REVIEW-243-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #242 | [CODE-REVIEW-242-r2.md](CODE-REVIEW-242-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | — |
| #239 | [SPEC-REVIEW-239-r1.md](SPEC-REVIEW-239-r1.md) | spec · r1 | ⚪ — | 0 | 0 | — |
| #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 | — |
| #239 | [CODE-REVIEW-239-r2.md](CODE-REVIEW-239-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #238 | [SPEC-REVIEW-238-r1.md](SPEC-REVIEW-238-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #238 | [CODE-REVIEW-238-r1.md](CODE-REVIEW-238-r1.md) | code · r1 | 🔴 красный | 1 | 0 | Продуктовый коммит не обновил скомпилированный бандл; закоммиченный артефакт не содержи… |
| #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 | — |
| #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 поведение, которого у неё нет: заявлено фактом, не провере… |
| #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 ТЗ |
| #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 | — |
| #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 | — |
| #231 | [CODE-REVIEW-231-r2.md](CODE-REVIEW-231-r2.md) | code · r2 | ⚪ — | 0 | 0 | — |
| #230 | [SPEC-REVIEW-230-r1.md](SPEC-REVIEW-230-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #230 | [SPEC-REVIEW-230-r2.md](SPEC-REVIEW-230-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #230 | [CODE-REVIEW-230-r1.md](CODE-REVIEW-230-r1.md) | code · r1 | 🟡 жёлтый | 0 | 0 | — |
| #230 | [CODE-REVIEW-230-r2.md](CODE-REVIEW-230-r2.md) | code · r2 | 🟡 жёлтый | 2 | 0 | — |
| #229 | [SPEC-REVIEW-229-r1.md](SPEC-REVIEW-229-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #229 | [SPEC-REVIEW-229-r2.md](SPEC-REVIEW-229-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #229 | [SPEC-REVIEW-229-r3.md](SPEC-REVIEW-229-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #229 | [CODE-REVIEW-229-r1.md](CODE-REVIEW-229-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #229 | [CODE-REVIEW-229-r2.md](CODE-REVIEW-229-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | — |
| #229 | [CODE-REVIEW-229-r3.md](CODE-REVIEW-229-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #228 | [SPEC-REVIEW-228-r1.md](SPEC-REVIEW-228-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #228 | [CODE-REVIEW-228-r1.md](CODE-REVIEW-228-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #228 | [CODE-REVIEW-228-r2.md](CODE-REVIEW-228-r2.md) | code · r2 | 🟢 зелёный | 0 | 2 | — |
| #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 | — |
| #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 | — |
| #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 | — |
| #225 | [CODE-REVIEW-225-r2.md](CODE-REVIEW-225-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #224 | [SPEC-REVIEW-224-r1.md](SPEC-REVIEW-224-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #224 | [CODE-REVIEW-224-r1.md](CODE-REVIEW-224-r1.md) | code · r1 | 🔴 красный | 1 | 2 | golden не остаётся прежним, вопреки AC12 и §2/§15 ТЗ (High, в скоупе); check-docs.mjs красный: отпечаток скриншотов не обновлён (Medium, в скоупе); AC6 заявляет доказательство, которого нет (Medium, в скоупе); двойной инкремент cfgEpoch в writeConfig (Low) |
| #224 | [CODE-REVIEW-224-r2.md](CODE-REVIEW-224-r2.md) | code · r2 | 🔴 красный | 0 | 0 | — |
| #223 | [SPEC-REVIEW-223-r1.md](SPEC-REVIEW-223-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #223 | [SPEC-REVIEW-223-r2.md](SPEC-REVIEW-223-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 2 | — |
| #223 | [SPEC-REVIEW-223-r3.md](SPEC-REVIEW-223-r3.md) | spec · r3 | 🟢 зелёный | 0 | 1 | — |
| #223 | [CODE-REVIEW-223-r1.md](CODE-REVIEW-223-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #220 | [SPEC-REVIEW-220-r1.md](SPEC-REVIEW-220-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | Medium, в скоупе. Отсутствует обязательная touch-классификация; Medium, в скоупе. §9 утверждает «нет нового поля», хотя §8.3/§17.3 предполагают обратное |
| #220 | [SPEC-REVIEW-220-r2.md](SPEC-REVIEW-220-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | Medium, в скоупе. §17.3 маркирует нормативное требование как «свободно меняемое» |
| #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 | — |
| #219 | [SPEC-REVIEW-219-r1.md](SPEC-REVIEW-219-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #219 | [SPEC-REVIEW-219-r2.md](SPEC-REVIEW-219-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #219 | [CODE-REVIEW-219-r1.md](CODE-REVIEW-219-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #218 | [SPEC-REVIEW-218-r1.md](SPEC-REVIEW-218-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #217 | [SPEC-REVIEW-217-r1.md](SPEC-REVIEW-217-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #217 | [CODE-REVIEW-217-r1.md](CODE-REVIEW-217-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #213 | [SPEC-REVIEW-213-r1.md](SPEC-REVIEW-213-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #213 | [CODE-REVIEW-213-r1.md](CODE-REVIEW-213-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #212 | [SPEC-REVIEW-212-r1.md](SPEC-REVIEW-212-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #212 | [CODE-REVIEW-212-r1.md](CODE-REVIEW-212-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | три существующих regression-смока сломаны миграцией mouse→pointer событий (Medium, в ск…; hp-device-preview.ts гейтирует hover, но никто не выставляет ему атрибут (Medium, в ско… |
| #212 | [CODE-REVIEW-212-r2.md](CODE-REVIEW-212-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | исправлено, доказано реальным поведением, не только тестом; исправлено, доказано смоком, который умеет упасть |
| #211 | [SPEC-REVIEW-211-r1.md](SPEC-REVIEW-211-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | целевое соотношение «MDI viewport = 0.5 × core» не подтверждено ни одним источником арх…; §4 называет нормативным источником несуществующий файл COMPARISONNOTES.md; обязательный тег Touch editor: … присутствует по смыслу, но не дословно |
| #211 | [SPEC-REVIEW-211-r2.md](SPEC-REVIEW-211-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #211 | [CODE-REVIEW-211-r1.md](CODE-REVIEW-211-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #211 | [CODE-REVIEW-211-r2.md](CODE-REVIEW-211-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #210 | [SPEC-REVIEW-210-r1.md](SPEC-REVIEW-210-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | контракт не говорит явно, что очистка floor в GUI должна удалять ключ, а не записывать …; обязательный раздел «i18n» присутствует по содержанию, но не оформлен отдельным заголовком |
| #210 | [SPEC-REVIEW-210-r2.md](SPEC-REVIEW-210-r2.md) | spec · r2 | 🟢 зелёный | 0 | 1 | — |
| #210 | [CODE-REVIEW-210-r1.md](CODE-REVIEW-210-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #209 | [SPEC-REVIEW-209-r1.md](SPEC-REVIEW-209-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #209 | [CODE-REVIEW-209-r1.md](CODE-REVIEW-209-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #205 | [SPEC-REVIEW-205-r1.md](SPEC-REVIEW-205-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #205 | [CODE-REVIEW-205-r1.md](CODE-REVIEW-205-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #205 | [CODE-REVIEW-205-r2.md](CODE-REVIEW-205-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #204 | [SPEC-REVIEW-204-r1.md](SPEC-REVIEW-204-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #204 | [CODE-REVIEW-204-r1.md](CODE-REVIEW-204-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #203 | [SPEC-REVIEW-203-r1.md](SPEC-REVIEW-203-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #203 | [SPEC-REVIEW-203-r2.md](SPEC-REVIEW-203-r2.md) | spec · r2 | 🟢 зелёный | 0 | 1 | — |
| #203 | [CODE-REVIEW-203-r1.md](CODE-REVIEW-203-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #201 | [SPEC-REVIEW-201-r1.md](SPEC-REVIEW-201-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #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 | — |
| #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 | — |
| #198 | [SPEC-REVIEW-198-r1.md](SPEC-REVIEW-198-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #198 | [CODE-REVIEW-198-r1.md](CODE-REVIEW-198-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #198 | [CODE-REVIEW-198-r2.md](CODE-REVIEW-198-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | — |
| #198 | [CODE-REVIEW-198-r3.md](CODE-REVIEW-198-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #197 | [SPEC-REVIEW-197-r1.md](SPEC-REVIEW-197-r1.md) | spec · r1 | 🔴 красный | 1 | 1 | — |
| #197 | [SPEC-REVIEW-197-r3.md](SPEC-REVIEW-197-r3.md) | spec · r3 | 🟢 зелёный | 0 | 0 | — |
| #197 | [CODE-REVIEW-197-r1.md](CODE-REVIEW-197-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #196 | [SPEC-REVIEW-196-r1.md](SPEC-REVIEW-196-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #196 | [CODE-REVIEW-196-r1.md](CODE-REVIEW-196-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #195 | [CODE-REVIEW-195-r1.md](CODE-REVIEW-195-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #195 | [CODE-REVIEW-195-r2.md](CODE-REVIEW-195-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #193 | [SPEC-REVIEW-193-r1.md](SPEC-REVIEW-193-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #193 | [CODE-REVIEW-193-r1.md](CODE-REVIEW-193-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #192 | [SPEC-REVIEW-192-r1.md](SPEC-REVIEW-192-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #192 | [CODE-REVIEW-192-r1.md](CODE-REVIEW-192-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #192 | [CODE-REVIEW-192-r2.md](CODE-REVIEW-192-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #189 | [CODE-REVIEW-189-r1.md](CODE-REVIEW-189-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #187 | [CODE-REVIEW-187-r1.md](CODE-REVIEW-187-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #186 | [SPEC-REVIEW-186-r1.md](SPEC-REVIEW-186-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | — |
| #186 | [SPEC-REVIEW-186-r2.md](SPEC-REVIEW-186-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #186 | [CODE-REVIEW-186-r1.md](CODE-REVIEW-186-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #184 | [CODE-REVIEW-184-r1.md](CODE-REVIEW-184-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #180 | [SPEC-REVIEW-180-r1.md](SPEC-REVIEW-180-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #180 | [CODE-REVIEW-180-r1.md](CODE-REVIEW-180-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #180 | [CODE-REVIEW-180-r2.md](CODE-REVIEW-180-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #179 | [SPEC-REVIEW-179-r1.md](SPEC-REVIEW-179-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 5 | цвет внешней тени искажён относительно нормативного источника; цвет continuous-пульсации для reason presence не определён; easing для Short и Alert не зафиксирован; стоимость и выбор backdrop-blur для Dark не решены; не назван обязательный тег Touch editor: из TOUCH-SUPPORT.md; Light-only combo-эталоны (Selected + Hover/Working/Green/Alert, |
| #179 | [SPEC-REVIEW-179-r2.md](SPEC-REVIEW-179-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | Обе Light-тени переписаны на rgb(37 40 45 / 12%) / rgb(37 40 45 / 18%); §10.1/§10.4 получили mapping presence→green, running/working/open/unlocked→amber, neutr…; Обе секции получили cubic-bezier(.22,.61,.36,1); §7.1 фиксирует production = Dark/Icon Default No Blur.svg, backdrop-filter запрещён; ри…; Добавлена строка Touch editor: best effort / intentionally degraded в §11 |
| #179 | [CODE-REVIEW-179-r1.md](CODE-REVIEW-179-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #179 | [CODE-REVIEW-179-r2.md](CODE-REVIEW-179-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #178 | [SPEC-REVIEW-178-r1.md](SPEC-REVIEW-178-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | — |
| #178 | [SPEC-REVIEW-178-r2.md](SPEC-REVIEW-178-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #178 | [CODE-REVIEW-178-r1.md](CODE-REVIEW-178-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #176 | [SPEC-REVIEW-176-r1.md](SPEC-REVIEW-176-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #176 | [CODE-REVIEW-176-r1.md](CODE-REVIEW-176-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #174 | [SPEC-REVIEW-174-r1.md](SPEC-REVIEW-174-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #174 | [CODE-REVIEW-174-r1.md](CODE-REVIEW-174-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #173 | [SPEC-REVIEW-173-r1.md](SPEC-REVIEW-173-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #173 | [CODE-REVIEW-173-r1.md](CODE-REVIEW-173-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #173 | [CODE-REVIEW-173-r2.md](CODE-REVIEW-173-r2.md) | code · r2 | 🟢 зелёный | 0 | 2 | — |
| #172 | [SPEC-REVIEW-172-r1.md](SPEC-REVIEW-172-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #172 | [CODE-REVIEW-172-r1.md](CODE-REVIEW-172-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #172 | [CODE-REVIEW-172-r2.md](CODE-REVIEW-172-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #162 | [SPEC-REVIEW-162-r1.md](SPEC-REVIEW-162-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #162 | [SPEC-REVIEW-162-r2.md](SPEC-REVIEW-162-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #162 | [CODE-REVIEW-162-r1.md](CODE-REVIEW-162-r1.md) | code · r1 | 🔴 красный | 1 | 1 | — |
| #162 | [CODE-REVIEW-162-r2.md](CODE-REVIEW-162-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #160 | [SPEC-REVIEW-160-r1.md](SPEC-REVIEW-160-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #160 | [CODE-REVIEW-160-r1.md](CODE-REVIEW-160-r1.md) | code · r1 | 🔴 красный | 1 | 3 | node scripts/check-docs.mjs красный: скриншоты документации не пересняты (High, блокирует); floor anchor opening lock badge вычисляется двумя независимыми формулами (Medium, в ско…; реальный алгоритм isoRoomSafePoint (grid-search fallback) не покрыт ни одним тестом (Me…; leafBasis (src/iso-openings.ts:187-209): flipH не тестируется независимо от flipV (Medi… |
| #160 | [CODE-REVIEW-160-r2.md](CODE-REVIEW-160-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | новый M2-тест не независимо доказывает «вне любой дыры» (Low, запись без блокировки); приёмка скриншотов сменила заявленную платформу на win32 без видимого основания в хендо… |
| #159 | [SPEC-REVIEW-159-r1.md](SPEC-REVIEW-159-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #159 | [CODE-REVIEW-159-r1.md](CODE-REVIEW-159-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #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 | — |
| #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 | — |
| #152 | [CODE-REVIEW-152-r2.md](CODE-REVIEW-152-r2.md) | code · r2 | 🔴 красный | 1 | 2 | — |
| #150 | [CODE-REVIEW-150-r1.md](CODE-REVIEW-150-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #146 | [SPEC-REVIEW-146-r1.md](SPEC-REVIEW-146-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | — |
| #146 | [CODE-REVIEW-146-r1.md](CODE-REVIEW-146-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #146 | [CODE-REVIEW-146-r2.md](CODE-REVIEW-146-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #141 | [SPEC-REVIEW-141-r1.md](SPEC-REVIEW-141-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #141 | [CODE-REVIEW-141-r1.md](CODE-REVIEW-141-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #140 | [CODE-REVIEW-140-r1.md](CODE-REVIEW-140-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #138 | [SPEC-REVIEW-138-r1.md](SPEC-REVIEW-138-r1.md) | spec · r1 | 🔴 красный | 1 | 0 | — |
| #138 | [SPEC-REVIEW-138-r2.md](SPEC-REVIEW-138-r2.md) | spec · r2 | 🔴 красный | 1 | 0 | — |
| #137 | [SPEC-REVIEW-137-r1.md](SPEC-REVIEW-137-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #132 | [SPEC-REVIEW-132-r1.md](SPEC-REVIEW-132-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #132 | [CODE-REVIEW-132-r1.md](CODE-REVIEW-132-r1.md) | code · r1 | 🔴 красный | 1 | 3 | — |
| #132 | [CODE-REVIEW-132-r2.md](CODE-REVIEW-132-r2.md) | code · r2 | 🟢 зелёный | 1 | 3 | — |
| #131 | [SPEC-REVIEW-131-r1.md](SPEC-REVIEW-131-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #126 | [SPEC-REVIEW-126-r1.md](SPEC-REVIEW-126-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #126 | [SPEC-REVIEW-126-r2.md](SPEC-REVIEW-126-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #126 | [CODE-REVIEW-126-r1.md](CODE-REVIEW-126-r1.md) | code · r1 | 🟡 жёлтый | 1 | 1 | — |
| #126 | [CODE-REVIEW-126-r2.md](CODE-REVIEW-126-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #123 | [SPEC-REVIEW-123-r1.md](SPEC-REVIEW-123-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #123 | [CODE-REVIEW-123-r1.md](CODE-REVIEW-123-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #122 | [SPEC-REVIEW-122-r1.md](SPEC-REVIEW-122-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #122 | [CODE-REVIEW-122-r1.md](CODE-REVIEW-122-r1.md) | code · r1 | 🔴 красный | 2 | 1 | — |
| #122 | [CODE-REVIEW-122-r2.md](CODE-REVIEW-122-r2.md) | code · r2 | 🟢 зелёный | 2 | 1 | — |
| #117 | [SPEC-REVIEW-117-r1.md](SPEC-REVIEW-117-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #117 | [CODE-REVIEW-117-r1.md](CODE-REVIEW-117-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #117 | [CODE-REVIEW-117-r2.md](CODE-REVIEW-117-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #113 | [SPEC-REVIEW-113-r1.md](SPEC-REVIEW-113-r1.md) | spec · r1 | 🟢 зелёный | 0 | 1 | — |
| #113 | [CODE-REVIEW-113-r1.md](CODE-REVIEW-113-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #113 | [CODE-REVIEW-113-r2.md](CODE-REVIEW-113-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #113 | [CODE-REVIEW-113-r3.md](CODE-REVIEW-113-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #107 | [SPEC-REVIEW-107-r1.md](SPEC-REVIEW-107-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #107 | [CODE-REVIEW-107-r1.md](CODE-REVIEW-107-r1.md) | code · r1 | 🔴 красный | 1 | 1 | — |
| #103 | [SPEC-REVIEW-103-r1.md](SPEC-REVIEW-103-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #103 | [CODE-REVIEW-103-r1.md](CODE-REVIEW-103-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #94 | [CODE-REVIEW-issue-094-2026-08-12.md](CODE-REVIEW-issue-094-2026-08-12.md) | code · 2026-08-12 | ⚪ — | 0 | 0 | — |
| #89 | [SPEC-REVIEW-089-isometric-view-stage1.md](SPEC-REVIEW-089-isometric-view-stage1.md) | spec · isometric-view-stage1 | 🔴 красный | 0 | 8 | Spike ADR должен фиксировать больше, чем выбор renderer; Fingerprint перечисляет не все входы iso geometry; since/expires требуют точной version semantics; Не определён runtime owner механизма Labs; Scope houseplan-space-card не указан; Performance contract не совпадает с существующей инфраструктурой |
| #89 | [SPEC-REVIEW-89-r1.md](SPEC-REVIEW-89-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | риски не собраны в отдельный раздел; «нормативная» таблица слоёв формально противоречит собственному запрету ТЗ на новый око… |
| #89 | [CODE-REVIEW-89-r2.md](CODE-REVIEW-89-r2.md) | code · r2 | 🔴 красный | 1 | 0 | обязательный по ТЗ смок demo/smokeisometriclivetouch.mjs красный на сданном коммите; три файла с лишней пустой строкой в конце (git diff --check) |
| #89 | [CODE-REVIEW-89-r3.md](CODE-REVIEW-89-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — |
| #86 | [CODE-REVIEW-86-r1.md](CODE-REVIEW-86-r1.md) | code · r1 | ⚪ — | 2 | 1 | Манифест скриншотов документации подделан, а не пересчитан (High, в скоупе); npm run golden:verify красный: 6 эталонов расходятся с рендером (High, в скоупе); Onboarding-путь 5 space-подсказок не доказан исполнением (Medium, в скоупе); .help-ключ не совпадает буквально с ключом видимого label (Low, снимается без правки) |
| #86 | [CODE-REVIEW-86-r2.md](CODE-REVIEW-86-r2.md) | code · r2 | 🟡 жёлтый | 0 | 1 | AC7 «browser zoom 200%» не доказан ничем (Medium, в скоупе); .help-ключ не совпадает буквально с ключом видимого label (Low, снимается без правки) |
| #86 | [CODE-REVIEW-86-r3.md](CODE-REVIEW-86-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | AC7 «представительный reviewed golden» для browser zoom 200% так и не появился (Medium,…; .help-ключ не совпадает буквально с ключом видимого label (Low, снимается без правки) |
| #86 | [CODE-REVIEW-86-r4.md](CODE-REVIEW-86-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — |
| #86 | [CODE-REVIEW-86-r5.md](CODE-REVIEW-86-r5.md) | code · r5 | 🟢 зелёный | 0 | 0 | — |
| #82 | [SPEC-REVIEW-82-r1.md](SPEC-REVIEW-82-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #82 | [CODE-REVIEW-82-r1.md](CODE-REVIEW-82-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #82 | [CODE-REVIEW-82-r2.md](CODE-REVIEW-82-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #74 | [SPEC-REVIEW-74-r1.md](SPEC-REVIEW-74-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #74 | [CODE-REVIEW-74-r1.md](CODE-REVIEW-74-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #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 | — |
| #62 | [SPEC-REVIEW-62-r2.md](SPEC-REVIEW-62-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 1 | — |
| #62 | [CODE-REVIEW-62-r1.md](CODE-REVIEW-62-r1.md) | code · r1 | 🔴 красный | 1 | 0 | — |
| #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 | — |
| #57 | [CODE-REVIEW-57-r1.md](CODE-REVIEW-57-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #54 | [SPEC-REVIEW-54-r1.md](SPEC-REVIEW-54-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 1 | — |
| #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 | — |
| #54 | [CODE-REVIEW-54-r2.md](CODE-REVIEW-54-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #53 | [SPEC-REVIEW-53-r1.md](SPEC-REVIEW-53-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 4 | — |
| #53 | [SPEC-REVIEW-53-r2.md](SPEC-REVIEW-53-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — |
| #53 | [CODE-REVIEW-53-r1.md](CODE-REVIEW-53-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
| #51 | [SPEC-REVIEW-51-r1.md](SPEC-REVIEW-51-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #51 | [CODE-REVIEW-51-r1.md](CODE-REVIEW-51-r1.md) | code · r1 | ⚪ — | 0 | 0 | — |
| #51 | [CODE-REVIEW-51-r2.md](CODE-REVIEW-51-r2.md) | code · r2 | 🟡 жёлтый | 1 | 3 | — |
| #51 | [CODE-REVIEW-51-r3.md](CODE-REVIEW-51-r3.md) | code · r3 | 🟡 жёлтый | 0 | 1 | — |
| #51 | [CODE-REVIEW-51-r4.md](CODE-REVIEW-51-r4.md) | code · r4 | ⚪ — | 0 | 0 | — |
| #44 | [SPEC-REVIEW-44-r1.md](SPEC-REVIEW-44-r1.md) | spec · r1 | 🔴 красный | 2 | 0 | Сценарий и AC4 построены на неверном факте: причина «исключена; Контракт №3 («оба значения читаются из одного источника всеми; Название вкладки инбокса не совпадает с интерфейсным словарём |
| #44 | [SPEC-REVIEW-44-r2.md](SPEC-REVIEW-44-r2.md) | spec · r2 | 🔴 красный | 0 | 1 | Ревизия 3 не убрала два места, где документ прямо утверждает то, что H1 уже опроверг: п… |
| #44 | [SPEC-REVIEW-44-r3.md](SPEC-REVIEW-44-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #44 | [CODE-REVIEW-44-r1.md](CODE-REVIEW-44-r1.md) | code · r1 | 🟡 жёлтый | 0 | 2 | — |
| #43 | [SPEC-REVIEW-43-r1.md](SPEC-REVIEW-43-r1.md) | spec · r1 | ⚪ — | 0 | 0 | — |
| #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 | 0 | — |
| #43 | [SPEC-REVIEW-43-r4.md](SPEC-REVIEW-43-r4.md) | spec · r4 | 🟡 жёлтый | 0 | 0 | — |
| #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 Одно число — один источник |
| #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 | 0 | — |
| #42 | [SPEC-REVIEW-42-r2.md](SPEC-REVIEW-42-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #42 | [SPEC-REVIEW-42-r3.md](SPEC-REVIEW-42-r3.md) | spec · r3 | 🟡 жёлтый | 0 | 0 | — |
| #42 | [SPEC-REVIEW-42-r4.md](SPEC-REVIEW-42-r4.md) | spec · r4 | 🟡 жёлтый | 0 | 0 | — |
| #42 | [CODE-REVIEW-42-r1.md](CODE-REVIEW-42-r1.md) | code · r1 | 🔴 красный | 0 | 0 | — |
| #42 | [CODE-REVIEW-42-r2.md](CODE-REVIEW-42-r2.md) | code · r2 | 🔴 красный | 2 | 0 | — |
| #42 | [CODE-REVIEW-42-r6.md](CODE-REVIEW-42-r6.md) | code · r6 | 🟡 жёлтый | 0 | 1 | — |
| #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-контракта |
| #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 не отменяет применение; «одно число, один источник» нарушено для HARDDIMENSION; AC8 (EXIF-ориентация) не доказан ни тестом, ни явной записью |
| #39 | [CODE-REVIEW-39-r2.md](CODE-REVIEW-39-r2.md) | code · r2 | 🟡 жёлтый | 0 | 0 | два из трёх новых stillCurrent()-чеков не имеют собственного мутанта |
| #33 | [SPEC-REVIEW-33-r1.md](SPEC-REVIEW-33-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 3 | статус implemented не существует ни в перечислении, ни в каноне; 4 из 7 «const-деклараций фронта» для parity-теста не существуют; AC6 описывает несуществующее поведение как «расширение теста» |
| #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… |
| #33 | [CODE-REVIEW-33-r2.md](CODE-REVIEW-33-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | AC6 не имеет штатного регрессионного теста на изолированные decision-required/drop-on-v… |
| #32 | [SPEC-REVIEW-32-r1.md](SPEC-REVIEW-32-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 0 | — |
| #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 остались без потребителей |
| #32 | [CODE-REVIEW-32-r2.md](CODE-REVIEW-32-r2.md) | code · r2 | 🟡 жёлтый | 1 | 0 | — |
| #29 | [SPEC-REVIEW-29-r1.md](SPEC-REVIEW-29-r1.md) | spec · r1 | 🟡 жёлтый | 0 | 2 | — |
| #29 | [SPEC-REVIEW-29-r2.md](SPEC-REVIEW-29-r2.md) | spec · r2 | 🟡 жёлтый | 0 | 0 | — |
| #29 | [CODE-REVIEW-29-r1.md](CODE-REVIEW-29-r1.md) | code · r1 | ⚪ — | 1 | 1 | demo/smokeeditortabs.mjs сломан этим диффом (High, в скоупе); «комната» в каталоге — это имя HA-зоны, а не название комнаты плана (Medium, в скоупе); DeviceInboxRow.canOpenHa — мёртвое поле (Low) |
| #29 | [CODE-REVIEW-29-r2.md](CODE-REVIEW-29-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — |
| #20 | [SPEC-REVIEW-20-r1.md](SPEC-REVIEW-20-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — |
| #20 | [CODE-REVIEW-20-r1.md](CODE-REVIEW-20-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — |
+23
View File
@@ -8560,6 +8560,29 @@ const MUTANT_DEFINITIONS = [
replace: " const codeRounds = completed.map((issue) => issue.s7Requests).filter(Boolean); // mutant: rounds = S7 events",
}],
},
// #635: индекс ревью — база знаний; молчаливо неполный индекс хуже отсутствующего.
{
id: 'reviews-index-skips-self-check',
guard: 'node --test --test-name-pattern="#635 индекс покрывает" test/reviews-index.test.mjs',
because: 'the index must list every review document and never itself; indexing INDEX.md makes '
+ 'the generator non-deterministic and hides documents behind its own entry (#635)',
patches: [{
file: 'scripts/reviews-index.mjs',
find: " const names = readdirSync(dir).filter((name) => name.endsWith('.md') && name !== INDEX_FILE).sort();",
replace: " const names = readdirSync(dir).filter((name) => name.endsWith('.md')).sort(); // mutant: indexes itself",
}],
},
{
id: 'reviews-index-verdict-substring',
guard: 'node --test --test-name-pattern="#635 вердикт" test/reviews-index.test.mjs',
because: 'a colour word inside another word is not a verdict; JS \\b is ASCII-only, so the '
+ 'Cyrillic guard is an explicit negative lookahead (#635)',
patches: [{
file: 'scripts/reviews-index.mjs',
find: "const VERDICT_LINE_RE = /(?:[Вв]ердикт|[Vv]erdict)[^\\n]{0,60}?\\**\\s*(зелёный|зеленый|жёлтый|желтый|красный|green|yellow|red)(?![а-яёa-z])/i;",
replace: "const VERDICT_LINE_RE = /(?:[Вв]ердикт|[Vv]erdict)[^\\n]{0,60}?\\**\\s*(зелёный|зеленый|жёлтый|желтый|красный|green|yellow|red)/i; // mutant: substring verdict",
}],
},
{
id: 'process-reconcile-restarts-healthy-run',
guard: 'node --test test/process-reconcile.test.mjs',
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env node
// #635: индекс документов ревью — база знаний решений, которую можно прочитать
// за одно чтение.
//
// В `docs/reviews/` ≈ 1 000 документов; что находили по файлу, диалогу или
// подсистеме, узнать можно было только перечитав их. Индекс сводит каждый
// документ в одну строку: issue, этап, раунд, вердикт, число High/Medium и
// заголовки находок. Он генерируется (класс C), а не пишется руками, и
// пересобирается конвейером после публикации каждого документа ревью.
//
// node scripts/reviews-index.mjs [--dir=docs/reviews] [--output=docs/reviews/INDEX.md] [--check]
//
// `--check` — не писать, а сравнить с существующим файлом (гейт «индекс свеж»).
import { readdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { isMainModule } from './spawn-portable.mjs';
export const INDEX_FILE = 'INDEX.md';
const DOC_NAME = /^(CODE|SPEC)-REVIEW-(?:issue-)?(\d+)(?:-r(\d+))?(?:-([a-z0-9-]+))?\.md$/i;
const COLOUR = {
'зелёный': 'зелёный', 'зеленый': 'зелёный', green: 'зелёный',
'жёлтый': 'жёлтый', 'желтый': 'жёлтый', yellow: 'жёлтый',
'красный': 'красный', red: 'красный',
};
const COLOUR_RE = /(зелёный|зеленый|жёлтый|желтый|красный|green|yellow|red)(?![а-яёa-z])/i;
const VERDICT_LINE_RE = /(?:[Вв]ердикт|[Vv]erdict)[^\n]{0,60}?\**\s*(зелёный|зеленый|жёлтый|желтый|красный|green|yellow|red)(?![а-яёa-z])/i;
/** Разобрать имя документа: этап, issue, раунд. */
export function parseDocName(name) {
const match = DOC_NAME.exec(String(name));
if (!match) return null;
return {
stage: match[1].toUpperCase() === 'CODE' ? 'code' : 'spec',
issue: Number(match[2]),
round: match[3] ? Number(match[3]) : null,
suffix: match[4] || null,
};
}
/** Вердикт: явная строка «Вердикт: **цвет**», иначе — по разделу «Вердикт», иначе «—». */
export function parseVerdict(text) {
const explicit = VERDICT_LINE_RE.exec(text);
if (explicit) return COLOUR[explicit[1].toLowerCase()];
const heading = /^#{1,4}\s*(?:\d+\.\s*)?(?:Вердикт|Verdict|Итог)(?![а-яё])[^\n]*\n([\s\S]*?)(?=\n#{1,4}\s|(?![\s\S]))/m.exec(text);
if (heading) {
const section = heading[1];
const colour = COLOUR_RE.exec(section);
if (colour) return COLOUR[colour[1].toLowerCase()];
if (/блокиру|не принят|отклон|red/i.test(section)) return 'красный';
if (/принят|принимается|готов|без замечаний|можно сливать|регрессий нет|proceed|approved/i.test(section)) return 'зелёный';
}
// Старые документы пишут «зелёный вердикт» в свободной форме — ищем в хвосте.
const tail = /(зелёный|зеленый|жёлтый|желтый|красный|green|yellow|red)\**\s+вердикт/i.exec(text.slice(-2500));
if (tail) return COLOUR[tail[1].toLowerCase()];
return '—';
}
/** Числа High/Medium из строки вердикта либо из заголовков находок. */
export function parseCounts(text) {
const high = /High:\s*(\d+)/.exec(text);
const medium = /Medium:\s*(\d+)/.exec(text);
if (high || medium) return { high: high ? Number(high[1]) : 0, medium: medium ? Number(medium[1]) : 0 };
const headings = [...text.matchAll(/^#{2,4}\s*(H\d+|M\d+)\b/gm)].map((m) => m[1][0]);
return { high: headings.filter((h) => h === 'H').length, medium: headings.filter((h) => h === 'M').length };
}
/**
* Заголовки находок: `### 1. …`, `### H1 — …`, `### M2: …`, строки таблиц с
* severity в первых ячейках. Обрезаются до 90 символов; не больше `limit`.
*/
export function parseFindings(text, limit = 6) {
const out = [];
const seen = new Set();
const push = (raw) => {
const title = String(raw).replace(/[`*_]/g, '').replace(/\s+/g, ' ').trim().replace(/[.:;—–-]+$/, '').trim();
if (!title || seen.has(title)) return;
seen.add(title);
out.push(title.length > 90 ? `${title.slice(0, 87)}…` : title);
};
for (const m of text.matchAll(/^#{3,4}\s*(?:(?:H|M|L)\d+\s*[—–:.-]\s*|\d+\.\s*)([^\n]+)/gm)) push(m[1]);
for (const m of text.matchAll(/^\|\s*(?:\*\*)?(?:H\d+|M\d+|High|Medium)(?:\*\*)?\s*\|(?:[^|\n]*\|)?\s*([^|\n]+)\|/gm)) push(m[1]);
return out.slice(0, limit);
}
/** Одна запись индекса по документу. */
export function indexEntry(name, text) {
const meta = parseDocName(name);
if (!meta) return null;
return {
name, ...meta,
verdict: parseVerdict(text),
...parseCounts(text),
findings: parseFindings(text),
};
}
export function collectEntries(dir, read = (name) => readFileSync(join(dir, name), 'utf8')) {
const names = readdirSync(dir).filter((name) => name.endsWith('.md') && name !== INDEX_FILE).sort();
const entries = [];
const skipped = [];
for (const name of names) {
const entry = indexEntry(name, read(name));
if (entry) entries.push(entry); else skipped.push(name);
}
return { entries, skipped };
}
const badge = (verdict) => ({ 'зелёный': '🟢', 'жёлтый': '🟡', 'красный': '🔴' }[verdict] || '⚪');
export function renderIndex({ entries, skipped = [] }) {
const byIssue = new Map();
for (const entry of entries) {
const list = byIssue.get(entry.issue) || [];
list.push(entry);
byIssue.set(entry.issue, list);
}
const issues = [...byIssue.keys()].sort((a, b) => b - a);
const lines = [];
lines.push('# Индекс ревью');
lines.push('');
lines.push(`Генерируется \`node scripts/reviews-index.mjs\` (#635) — не редактировать руками. Документов: ${entries.length}, issue: ${issues.length}. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок.`);
lines.push('');
lines.push('| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки |');
lines.push('|---|---|---|---|---:|---:|---|');
for (const issue of issues) {
const docs = byIssue.get(issue).sort((a, b) => (a.stage === b.stage ? (a.round || 0) - (b.round || 0) : a.stage === 'spec' ? -1 : 1));
for (const doc of docs) {
const round = doc.round ? `r${doc.round}` : (doc.suffix || '—');
lines.push(`| #${issue} | [${doc.name}](${doc.name}) | ${doc.stage} · ${round} | ${badge(doc.verdict)} ${doc.verdict} | ${doc.high} | ${doc.medium} | ${doc.findings.join('; ').replace(/\|/g, '\\|') || '—'} |`);
}
}
if (skipped.length) {
lines.push('');
lines.push(`Вне схемы имён (не индексируются): ${skipped.map((name) => `\`${name}\``).join(', ')}.`);
}
return `${lines.join('\n')}\n`;
}
export function buildIndex(dir) {
return renderIndex(collectEntries(dir));
}
if (isMainModule(import.meta.url)) {
const arg = (name, fallback) => process.argv.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3) ?? fallback;
const dir = arg('dir', 'docs/reviews');
const output = arg('output', join(dir, INDEX_FILE));
const markdown = buildIndex(dir);
if (process.argv.includes('--check')) {
const current = existsSync(output) ? readFileSync(output, 'utf8') : '';
if (current !== markdown) {
console.error(`${output} устарел — пересобрать: node scripts/reviews-index.mjs`);
process.exit(1);
}
console.log(`${output} свеж`);
} else {
writeFileSync(output, markdown, 'utf8');
console.log(`${output}: ${markdown.split('\n').length} строк`);
}
}
+99
View File
@@ -0,0 +1,99 @@
// #635: индекс ревью — одна строка на документ, детерминированно, 100 % каталога.
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, writeFileSync, rmSync, readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import {
buildIndex, collectEntries, indexEntry, parseCounts, parseDocName, parseFindings, parseVerdict, renderIndex,
} from '../scripts/reviews-index.mjs';
test('#635 имена документов: этап, issue, раунд; INDEX и чужое — вне схемы', () => {
assert.deepEqual(parseDocName('CODE-REVIEW-600-r2.md'), { stage: 'code', issue: 600, round: 2, suffix: null });
assert.deepEqual(parseDocName('SPEC-REVIEW-7-r1.md'), { stage: 'spec', issue: 7, round: 1, suffix: null });
assert.deepEqual(parseDocName('CODE-REVIEW-issue-5.md'), { stage: 'code', issue: 5, round: null, suffix: null });
assert.equal(parseDocName('INDEX.md'), null);
assert.equal(parseDocName('README.md'), null);
});
test('#635 вердикт: явная строка, раздел «Вердикт», свободная форма хвоста, иначе «—»', () => {
assert.equal(parseVerdict('- Вердикт: **зелёный**'), 'зелёный');
assert.equal(parseVerdict('Вердикт: жёлтый · заход r1 · High: 0 · Medium: 4'), 'жёлтый');
assert.equal(parseVerdict('Verdict: **red** · cycle r2/4'), 'красный');
assert.equal(parseVerdict('## 6. Вердикт\n\nH1 воспроизведён. Это High: блокирует.\n\n## 7. Прочее'), 'красный');
assert.equal(parseVerdict('## Вердикт\n\nПродуктовый код не менялся, регрессий нет.\n'), 'зелёный');
assert.equal(parseVerdict('текст без вердикта'), '—');
assert.equal(parseVerdict('…поэтому **зелёный вердикт**.'), 'зелёный');
assert.equal(parseVerdict('зелёныйзаголовок вердикта'), '—', 'цвет как часть слова не считается');
assert.equal(parseVerdict('Вердикт: зелёныйзаголовок без цвета'), '—', 'JS \\b не знает кириллицы — граница слова явная');
});
test('#635 счётчики и находки', () => {
assert.deepEqual(parseCounts('Вердикт: жёлтый · High: 1 · Medium: 3'), { high: 1, medium: 3 });
assert.deepEqual(parseCounts('### H1 — a\n### M1 — b\n### M2 — c\n### L1 — d'), { high: 1, medium: 2 });
assert.deepEqual(parseCounts('ничего'), { high: 0, medium: 0 });
const findings = parseFindings([
'### 1. Room settings: подпись переносится посреди слова',
'### H1 — диалог невидим после крестика',
'### M2: `rangeLine` клампит каждый символ.',
'| M3 | `src/x.ts:1` | поле пустое, состояние старое | почему |',
'| **High** | `y.ts` | импорт теряет маршруты | … |',
'### 1. Room settings: подпись переносится посреди слова',
`### 2. ${'очень длинный заголовок '.repeat(8)}`,
].join('\n'));
assert.equal(findings[0], 'Room settings: подпись переносится посреди слова');
assert.equal(findings[1], 'диалог невидим после крестика');
assert.equal(findings[2], 'rangeLine клампит каждый символ');
assert.ok(findings.includes('поле пустое, состояние старое'));
assert.ok(findings.includes('импорт теряет маршруты'));
assert.equal(findings.length, 6, 'дубль снят, потолок 6');
assert.ok(findings.every((f) => f.length <= 90));
});
test('#635 индекс покрывает каталог целиком, детерминирован и не индексирует сам себя', () => {
const dir = mkdtempSync(join(tmpdir(), 'hp-reviews-index-'));
try {
writeFileSync(join(dir, 'CODE-REVIEW-600-r1.md'), '# x\nВердикт: **жёлтый** · High: 0 · Medium: 4\n### 1. Первая\n### 2. Вторая\n');
writeFileSync(join(dir, 'CODE-REVIEW-600-r2.md'), '# x\nВердикт: **зелёный** · High: 0 · Medium: 0\n');
writeFileSync(join(dir, 'SPEC-REVIEW-600-r1.md'), '- Вердикт: **зелёный**\n');
writeFileSync(join(dir, 'CODE-REVIEW-601-r1.md'), '## Вердикт\n\nсвободная форма\n');
writeFileSync(join(dir, 'INDEX.md'), 'старый индекс');
writeFileSync(join(dir, 'notes.md'), 'постороннее');
const { entries, skipped } = collectEntries(dir);
assert.equal(entries.length, 4);
assert.deepEqual(skipped, ['notes.md']);
const md = buildIndex(dir);
assert.equal(md, buildIndex(dir), 'детерминирован');
assert.match(md, /Документов: 4, issue: 2/);
const rows = md.split('\n').filter((l) => l.startsWith('| #'));
assert.deepEqual(rows.map((r) => r.split('|')[2].trim()), [
'[CODE-REVIEW-601-r1.md](CODE-REVIEW-601-r1.md)',
'[SPEC-REVIEW-600-r1.md](SPEC-REVIEW-600-r1.md)',
'[CODE-REVIEW-600-r1.md](CODE-REVIEW-600-r1.md)',
'[CODE-REVIEW-600-r2.md](CODE-REVIEW-600-r2.md)',
], 'новые issue сверху; внутри issue — ТЗ, затем код по раундам');
assert.match(md, /\| #600 \| \[CODE-REVIEW-600-r1\.md\][^\n]*\| code · r1 \| 🟡 жёлтый \| 0 \| 4 \| Первая; Вторая \|/);
assert.match(md, /\| #601 \|[^\n]*⚪ — \|/);
assert.match(md, /Вне схемы имён[^\n]*`notes\.md`/);
assert.ok(!md.includes('INDEX.md](INDEX.md)'), 'индекс не индексирует себя');
assert.equal(indexEntry('INDEX.md', 'x'), null);
assert.equal(renderIndex({ entries: [] }).includes('Документов: 0'), true);
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
test('#635 живой каталог docs/reviews: индекс свеж и покрывает все документы', () => {
const { entries, skipped } = collectEntries(fileURLToPath(new URL('../docs/reviews/', import.meta.url)));
assert.equal(skipped.length, 0, `вне схемы имён: ${skipped.join(', ')}`);
assert.ok(entries.length > 900);
const recognised = entries.filter((e) => e.verdict !== '—').length;
assert.ok(recognised / entries.length > 0.9, `вердикт распознан у ${recognised} из ${entries.length}`);
});
test('#635 конвейер пересобирает индекс тем же коммитом, что и документ ревью', () => {
const wf = new URL('../.github/workflows/process.yml', import.meta.url);
const text = readFileSync(wf, 'utf8');
assert.match(text, /node scripts\/reviews-index\.mjs --dir=docs\/reviews\n\s+git add -- docs\/reviews\/INDEX\.md/);
});