14 KiB
SPEC-REVIEW-744-r1
Issue: #744 — «Производительность: кэш чистого пола сбрасывается любой правкой конфига»
Этап: spec (PROCESS.md §2.4) · Трек: ask (§5, критерий «перф») · Заход: r1 · блокирующих циклов 0/4
Материал: тело issue #744 (раздел ## ТЗ), сверено с кодом на origin/dev 8b7725ac (SHA, на который ссылается сам автор) и с рабочей копией 5a49c8c3 — расхождений в затронутых файлах между этими SHA нет (единственный коммит между ними — несвязанный тест луны).
Route: fix (трек уже ask, переквалификация не применяется).
Скоуп
Задача меняет ключи и инвалидацию четырёх структурных геометрических кэшей
этажа (_physicalBodiesCache, _wallUnionGeometry/_wallUnionPool,
_innerRoomContour/_innerContourCache, cleanFloorForRoom/_cleanFloorCache):
сегодня ключ несёт глобальный _cfgEpoch, из-за чего правка одного этажа
«остужает» кэши всех остальных. Цель — ключ на отпечаток содержимого записи
конкретного этажа, без потери инвалидации при правках, которые законно трогают
несколько этажей (лестницы, общие стены). Служит J1/J6 docs/SCOPE.md — отзывчивость
переключения этажей и честность редакторского цикла; видимых новых функций нет.
Как проверялось
Ревью ТЗ на этом этапе не включает выполнение гейтов (код не писался) — проверялась только состоятельность документа: обязательные разделы §7.1, однозначность и доказуемость каждого AC, и — так как расследование опирается на построчные ссылки на код — сверка каждой процитированной строки с реальным деревом, а не с заявлением автора.
Построчно сверено чтением (не исполнением) с текущим деревом:
| Утверждение ТЗ | Файл:строка в ТЗ | Проверено |
|---|---|---|
roomKey/ключ чистого пола, LRU 600 |
src/clean-floor.ts:32–33,64 |
совпадает дословно |
| Ключ оболочки стен, пул LRU 8 | src/houseplan-card.ts:8755,8777 |
совпадает (:8755, lruWrite(... 8) на той же строке диапазона) |
| Ключ внутренних контуров, LRU 600 | :8806 |
совпадает |
| Ключ физических тел, «одна запись» | :9462–9463 |
совпадает — это действительно единственный слот, не Map; автор сам это отмечает («одна запись») |
_saveConfig поднимает эпоху, комментарий «every mutation path ends here» |
:7634–7637 |
совпадает (функция с 7634, _cfgEpoch++ на 7635) |
Замена _serverCfg поднимает эпоху кроме geometry-preserving исключения |
:4019–4025 |
совпадает |
StairsEditor.write поднимает эпоху и чистит _cleanFloorCache целиком |
src/stairs-editor.ts:149–156 |
совпадает (clear() действительно без учёта этажа — текущий баг подтверждён) |
contentFingerprint существует, уже используется для _model |
src/visual-continuity.ts:439, houseplan-card.ts:3817 |
совпадает |
cacheSnapshot считает wallUnion как 0/1, не считает innerContour вовсе |
demo/benchmark_large_house.mjs:163–172 |
совпадает — подтверждает «слепоту» свидетеля #735, на которую опирается AC3 |
Потолок src/houseplan-card.ts — 12896 строк, запас к моменту ТЗ — 4 |
test/core-file-budget.test.mjs:52 |
совпадает: файл сейчас 12892 строки |
| Явные полные сбросы при откате и восстановлении геометрии остаются | src/houseplan-editor-runtime.ts:1474–1477, 1688–1691 |
совпадает |
Фикстуры-прецеденты для нового смока (physicalize, партиции/колонна) |
demo/smoke_space_switch_transitions.mjs:55–66, demo/smoke_space_card.mjs:18–34 |
совпадает по смыслу и содержимому |
performance.yml можно запустить вручную (workflow_dispatch) для AC4 |
.github/workflows/performance.yml:15 |
совпадает |
Ни одно утверждение о текущем поведении кода не разошлось с деревом. Это резко снижает риск «ТЗ описывает код, которого нет».
Находки
Находок High и Medium нет.
Low (снято с записью, не требует правки): раздел «План автотестов» даёт явную красную причину для AC1, AC2а, AC2б, но не называет отдельный красный случай для AC2в (поведение во время resize-превью). Это не защитный AC в смысле §2.7 (не валидация/гард, а утверждение о неизменности поведения, которое уже корректно на dev), и на стадии ТЗ отдельная строка «чем краснеет» для него не обязательна — но на код-ревью пустое место здесь не должно остаться пустым по умолчанию, если тест действительно нечувствителен к ошибке в превью-ветке.
Что проверено и корректно
- Обязательные разделы §7.1 присутствуют все: сценарий (две персоны из
docs/SCOPE.md— админ-десктоп, домочадцы-киоск), что человек увидит до/после (одной фразой, без терминов реализации), проблема (5 нумерованных пунктов с кодовыми ссылками), скоуп и не-скоуп (с явной мотивировкой каждого исключения), контракт поведения К1–К5, UX/данные/i18n/touch (сжато, обоснованно — новых элементов нет), критерии приёмки AC1–AC5 с колонками «Доказательство» и «Oracle», план автотестов, риски, откат, release-артефакты (текст changelog RU+EN уже написан). - Каждый AC однозначен и проверяем конкретным механизмом: AC1/AC2 — новый смок с названным сценарием воздействия и named oracle (независимая карточка, построенная с нуля на том же конфиге — классический oracle против «кэш соврал»); AC3 — правка полей бенчмарка плюс существующий сторож диапазона; AC4 — реальный perf-workflow плюс локальный зонд тем же методом, что в «Итоге исследования»; AC5 — перечисленные гейты и два конкретных мутанта с названными guard AC.
- Защитный AC (К1 «правка другого этажа не остужает этот», К2 «устаревший
кадр не отдаётся») доказывается по правилам §2.7 уже на стадии ТЗ: для
AC1 назван красный случай на текущем коде (эпоха в ключе), для AC2а —
названный мутант без отпечатка содержимого, для AC2б — красный случай на
текущем коде (
StairsEditor.writeчистит чужой кэш). Пустых строк в этой части нет. - Главный риск задачи («устаревший кадр» — неполный ключ отдаст старую геометрию) назван автором явно и закрыт мерой (ключ — отпечаток всей записи этажа «по построению», плюс независимый oracle AC2а) — это ровно то дерево рассуждений, которого требует правка кэша на горячем пути.
- «Принято предположительно» — пять технических решений, явно помеченных как
не-продуктовые и подлежащие пересмотру ревьюером без эскалации владельцу;
каждое обосновано (трейд-офф полнота/скорость ключа, выбор четырёх кэшей на
основе замера, отказ от
StairsEditor.writeчистки по данным замера, смок вместо новой метрики бенчмарка — экономия на правкеbudgets-*.json, отдельный модуль ключа — из-за строкового бюджета). Технических споров, которые требовали бы вердикта вместо решения автора, не нашлось. - Раздел «Вопросы владельцу» — пусто, с явным обоснованием («видимое изменение одно, расширение на четыре кэша — техническое средство без отдельного видимого эффекта»); никакого технического вопроса, спрятанного под видом вопроса владельцу, в тексте нет — весь список открытых решений находится в «Принято предположительно», а не вынесен наружу.
- Трейлер
User-Visible: yesобоснован (один наблюдаемый эффект — отзывчивость переключения этажей после правки) и текст changelog уже подготовлен на русском и английском в самой ТЗ — на коммите кода потребуется перенести его в обаdocs/CHANGELOG*.md, это уже учтено в «Затронутые файлы». - Трек
askобоснован по критерию §5 «перф»: горячий путь переключения этажа, задействованный предыдущими перф-правками (#694/#725/#740), риск неверного кадра, а не просто медленного — ТЗ сама называет этот критерий, совпадает с меткойtrack:askна issue.
Чего не проверял
- Исполнение гейтов (
tsc,npm test,npm run build, golden, perf) — кода ещё нет, этап spec их не требует. - Прогон
smoke-select, мутационных якорей или perf-workflow — неприменимо до реализации. - Фактическую корректность числовых замеров из «Итога исследования» (607 мс, 3 % вклад чистого пола и т. п.) — они явно помечены автором как локальная диагностика, а не доказательство (это доказывает только будущий AC4), и ревью ТЗ не требует их перепроверки.
- Состояние соседней задачи #742 (на неё ссылается пункт 5 «Принято
предположительно» про запас строк) — не часть материала этого ревью; если к
моменту кода запас бюджета будет другим, это всплывёт на гейте
core-file-budget, а не здесь.
Вердикт
Зелёный. Документ ТЗ полон, построчные ссылки на код проверены и совпадают, AC однозначны и снабжены доказательством и oracle, защитные AC доказаны по правилам §2.7 уже на этой стадии, открытых продуктовых вопросов нет. High: 0, Medium: 0.
Материал раунда
- Ветка:
dev, коммит5a49c8c32df9— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
436061a24c6d0fb33f9cc036606d03922b5476a9git log --all --format='%H %T' | grep 436061a24c6d - Тело issue:
9dec80eead95ea0cbc014364d7ed09eaef1f7f45b7e2c70f97f1a95c586ac465 - Вердикт конвейера:
green· High 0 · маршрутfix