Каталог (id, группа, размеры) остаётся eager; SVG-пути 44 дизайнерских
символов — отдельный чанк за FurnitureArtRuntime (ready|pending|fallback,
нонс на повторе, отпечаток сборки, осевший отказ). Запуск при приёме плана,
бут-вуаль ждёт арт в пределах BOOT_MAX_MS, редактор отдаёт арт рантайму
синхронно (adopt при загрузке чанка). Магнит проверяет каталог, не арт.
Потолок initial View 300 500 → 290 500. Семь свидетелей, смок
smoke_furniture_lazy_art, golden-harness требует все предметы после бута.
Ядро −2 строки.
Issue: #474
User-Visible: no
#451 принёс 1 651 строку в восьми новых модулях, а единственный мутант
того релиза патчил houseplan-card.ts и houseplan-editor-runtime.ts —
места, ОТКУДА код ушёл. Вынос в модули был правильным решением, но
защита осталась смотреть на старые файлы.
Восемь мутантов, семь модулей, все прогнаны штатным раннером (чистый
прогон зелёный, мутант красный):
- live-editor-view-mode-routes-live — режим View обязан оставаться
реактивным: живой путь редактора там означает план, который перестал
отвечать на Home Assistant у двух персон из трёх;
- live-editor-first-gesture-frame-goes-live — первый кадр жеста меняет
выделение и хром и обязан остаться реактивным;
- pointer-move-queue-keeps-first-move — очередь last-wins: сохранение
ПЕРВОГО коллбэка кадра рисует план там, где палец уже не находится;
- live-hass-tick-never-deferred — тик состояния посреди жеста
откладывается намеренно, и флаг отложенности гарантирует его
воспроизведение после;
- live-viewport-identity-projection-not-recognized — см. ниже;
- render-invalidation-unknown-key-ignored — классификатор обязан
ошибаться в сторону перерисовки на незнакомых ключах hass;
- resize-live-preflight-keeps-every-room — живой resize проверяет только
задетые комнаты, иначе каждый кадр становится полной проверкой плана;
- render-lifecycle-diagnostics-cache-never-invalidated — кэш диагностики
обязан сбрасываться, иначе красная точка нового устройства не загорится.
Мутант на live-viewport пришлось заменить, и это стоит записать. Issue
предлагал снять `setLayerProjection(layer, null)` из
`commitHouseplanViewport` — прогон показал, что тест остаётся ЗЕЛЁНЫМ:
следом идёт `paintLiveViewport(root, painted, painted)`, который на
равных аргументах даёт identity и обнуляет проекцию сам. Тот цикл —
подстраховка, а не контракт. Настоящий контракт — распознавание identity
(`isIdentityLiveLayerProjection`), потому что даже единичный transform
переключает путь композитинга и сдвигает установившийся растр на
несколько уровней цвета. Мутируется теперь он.
`src/live-hover.ts` остался без мутанта сознательно: его контракты либо
чисто производительные (мемо по наведённой комнате), либо доменные
(подсветка комнаты, застрявшая после ухода курсора). Первое мутантом не
ловится в принципе, второе — только браузерным смоком, которого в
песочнице нет. Записано в тесте и в issue.
Чтобы требование не жило в памяти, добавлен гейт: у каждого модуля
горячего пути обязан быть свой мутант, и он не имеет права патчить
houseplan-card.ts или houseplan-editor-runtime.ts — то есть исходный
дефект #458 больше не воспроизводим молча. Проверено отрицательным
прогоном: перевод патча любого из модулей на старое ядро краснит гейт.
Гейты: npm test 1960 tests, 1959 pass, 0 fail; typecheck зелёный;
mutation-gate --check зелёный на всех якорях; каждый из восьми мутантов
прогнан отдельно.
Issue: #458
User-Visible: no
Treat explicit empty route lists as authoritative, preserve them through single-space export, group deleted-space routes, and render vacuums from the immutable vacuum-only snapshot subset.
Issue: #443
User-Visible: yes