18 KiB
CODE-REVIEW-735-r1
Issue: #735 · Этап: code · Заход: r1 · Трек: show · Материал: ff8638b6a9ca3577ff2e28a768e7d88ff2bf164a (origin/dev..HEAD — один коммит)
Скоуп
Перф-харнесс demo/benchmark_large_house.mjs до этой правки включал в тёплый
12-шаговый цикл switchCycle первый (холодный) заход на этаж 3 — каждый
образец монтирует новую карточку, успевшую посетить только этажи 1 и 2.
Холодная сборка чистого пола (а в 2.5D — ещё геометрии и структурная сборка)
занимала примерно половину метрики, документированной как «тёплая
навигация». В large-house-interaction-v1 холодным оказывался и этаж 1:
серия редактора двигает _cfgEpoch, который входит в ключ кэша чистого пола.
Правка (класс B, харнесс, продукт не меняется):
- Прогрев всех этажей фикстуры по порядку цикла после закрытия диалога
настроек и до окна
switchCycle, вне любого замеряемого окна и окна Long Task; возврат на этаж 2 перед стартом цикла. - Сторож окна:
cacheSnapshot/isoStructuralBuildCountдо и после цикла; рост любого кэша или счётчика структурных сборок роняет образец. demo/performance/README.md— абзац о ступеньке абсолютного уровняswitchCycleMs, явно: сравнение база/кандидат не задето (обе стороны меряет раннер кандидата), бюджеты иhardMaxMsне менялись.test/performance-workflow.test.mjs— unit-якорь#735.
Это закрытая задача из «Не-скоуп» ТЗ #725, track: show, оценка автора —
ценность 4/10, сложность 2/10. User-Visible: no, продуктовый код
(src/**) не тронут — диф целиком в demo/** и test/**.
Маршрут §5
| Критерий | Проходит |
|---|---|
| complexity ≤3 | да — один точечный механизм (прогрев + сторож) в одном файле харнесса |
| surfaces — одна поверхность | да — перф-раннер demo/benchmark_large_house.mjs; README и unit-тест обслуживают ту же поверхность |
| migration | да — нет конфига, нет compatibility-полей |
| ux-contract | да — продуктовое поведение не меняется, User-Visible: no подтверждён диффом (нет правок src/**, changelog, USER-GUIDE.ru.md) |
| perf-touch | да — меняется только методика измерения, не продуктовая производительность и не touch-контракт; бюджеты/hardMaxMs/workflow/фикстура не тронуты (проверено git diff --stat по этим путям — пусто) |
| undocumented | да — контракт «тёплый цикл» уже был заявлен в README/комментарии кода; правка приводит измерение в соответствие уже описанному, а не вводит новое поведение |
Все критерии пройдены → route: fix.
Как проверялось
- Полностью прочитан дифф (
git diff origin/dev...HEAD, 3 файла, 80 вставок/1 удаление) и окружающий кодdemo/benchmark_large_house.mjs(прогрев, сторож,cacheSnapshot,isoStructuralBuildCount,duration,frame) — построчно. - Прочитано тело issue #735 (ТЗ, предположения, риски) и итоговый комментарий автора с отчётом по AC1–AC3.
- Структурная сверка: других вызовов
_pickSpaceмеждуspaceSwitch(:477–480, этаж 2) и закрытием диалога настроек (:1121) нет (grep -n "_pickSpace") — подтверждает заявление «до прогрева посещены только этажи 1 и 2» и что прогрев/возврат на этаж 2 не меняют состояние перед другими уже существующими окнами. npx tsc --noEmit— чисто (не обязателен по §8 для этого диффа, прогнан попутно при локальной сборке).node --test test/performance-workflow.test.mjs— 7/7 зелёных, включая новый#735 switchCycle times warmed navigation and fails on a floor build inside its window.- Проверка «тест умеет падать»: прогнал тот же regex-блок якоря против
текста раннера на
origin/dev(git show origin/dev:demo/benchmark_large_house.mjs) — падает на первой же проверке (every fixture floor must be visited once before the switchCycle window), как и заявлено в AC3 («На dev якорь красный»). git diff --statпоdemo/performance/budgets*.json,.github/workflows/performance.yml,demo/fixtures/large-house.mjs— пусто; подтверждает заявление «бюджеты,hardMaxMs, профили, фикстура не меняются».- Сверены оба трейлера коммита:
Issue: #735,User-Visible: no— присутствуют; приnochangelog не требуется и не тронут (проверено). - AC2 — реальный прогон, не пересказ. Проверил оба упомянутых прогона
через
gh run view:36821241343(«Полные бенчмарки производительности») —headSha= материал ревьюff8638b6…,conclusion: success, все 9 job зелёные. В логах шага «Enforce relative and absolute performance budget» дляlarge-house/isometric/interaction/plan-snap/isometric-stage3медианыswitchCycleMs(683.3 / 1051 / 754.1 / 700.1 / 983.2) совпадают с числами из комментария автора день-в-день; строкиswitchCycle built a floor inside the windowв логах нет ни на одной стороне — сторож ни разу не сработал на зелёном материале.36821012618(«Проверка (CI)», Validate) —headSha=ff8638b6…,conclusion: success. Это и есть «дешёвые гейты уже подтверждены», упомянутые в задаче на ревью;tsc/npm test/npm run buildс бандл-политикой на этом SHA повторно не гонял.- Issue #747 и #744 (объявленные «кандидаты в новые issue») существуют и открыты — не декларация без следа.
- AC1 — попытка прогнать смок сама. Issue называет конкретный смок
(
npm run benchmark:large-house -- --samples=3 --warmups=1), поэтому попытался прогнать его в своей песочнице (npm run build, затемnpm run benchmark:large-house -- --samples=1 --warmups=0). Браузер Chromium в окружении есть, но прогон падает наFailed to fetch dynamically imported module: http://demo.local/assets/.../TimeoutErrorпри ожиданииwindow.__card— это сетевое ограничение песочницы ревью (перехват маршрутов Playwright работает только для самого документа, динамический импорт модуля блокируется), а не дефект кода: то же самое происходит при--no-sandbox. Записано в «Чего не проверял». Поведение AC1 принято по (а) чтению кода сторожа — логика симметрична описанной в ТЗ и сторож технически не может не сработать при росте любого из восьми отслеживаемых ключей; (б) реальному зелёному прогону AC2 на точном SHA, который исполняет тот же код сторожа на 9 профилях и 0 раз его не срабатывает; (в) сообщённому автором witness-прогону (раннер без прогрева падает на первом образце сcleanFloor +20и т. п.) — это заявление автора, не перепроверено исполнением.
AC · чем доказан · чем краснеет
| AC | Чем доказан | Чем краснеет |
|---|---|---|
| AC1 (прогрев + сторож) | Код прочитан построчно; реальный зелёный прогон AC2 на материале SHA исполняет тот же путь 9×; witness-прогон автора (не переисполнен мной) | Сторож: switchCycleCachesAfter[key] > …Before[key] по любому из 8 ключей cacheSnapshot, либо isoStructuralBuildsAfter !== …Before при не-null счётчике — рост бросает Error. Независимо перепроверено regex-сравнением с origin/dev: без прогрева заявленный автором витнес-прогон обязан упасть (структурно подтверждено по коду: без прогрева шаг 2 цикла строит этаж 3 внутри окна) |
| AC2 (CI, вся матрица) | Исполнено реально — прогон 36821241343, headSha и числа сверены мной напрямую через gh run view, не из пересказа |
Любой профиль с нарушением бюджета или строкой сторожа в логе красит job; conclusion каждого из 9 job — success, строки сторожа нет |
| AC3 (гейт + якорь) | node --test локально, 7/7 зелёных; regex-блок якоря самостоятельно прогнан против origin/dev и упал — тест умеет падать |
Любое смещение прогрева относительно card._settingsDialog = null;/const switchCycle = …, пропуск одного из полей сторожа в тексте раннера или выпадение из порядка 2 -> 1 красят якорь |
Находки
Нет. Ни High, ни Medium, ни Low.
Что проверено и корректно
- Прогрев обходит этажи
1..fixture.counts.floors(не хардкод "3"), переживёт сменуFLOOR_COUNT, как заявлено в «Принято предположительно» п.2. - Прогрев и возврат на этаж 2 не входят ни в
duration(), ни в окно Long Task (структурно внеstartLongTaskWindow/durationблоков — проверено по расположению кода и подтверждено третьей частью regex-якоря!warmup.includes('duration(') && !warmup.includes('startLongTaskWindow(')). isoStructuralBuildCountкорректно возвращаетnullдля профилей без 2.5D (Number.isFiniteнаundefined→false), и сторож явно пропускает проверку счётчика приnull— старая база (без 2.5D инструментирования) не ложно красится.cacheSnapshotчитает отсутствующие у старой базы кэши как0(?.size ?? 0/? 1 : 0), рост от0возможен только при реальном появлении кэша — не создаёт ложных срабатываний на старой базе; это и подтвердил прогон AC2 против v1.78.0 со стороны base (сторож молчал). (в этом коммите сторож проверен только по работе на кандидате, со стороны base это уже проверка AC2, исполненная раннером кандидата по дизайну задачи — не предмет этой правки).- README-абзац не вводит число, у которого есть второй источник истины:
budgets-*.jsonне менялись (проверено диффом), числа в README — историческая справка с явной ссылкой на issue, а не гейтуемая величина; «одно число — один источник» не нарушено. - Трейлеры корректны:
Issue: #735,User-Visible: no; changelog иUSER-GUIDE.ru.mdне тронуты — согласовано. - Диапазон диффа ограничен тремя поверхностями, названными в оценке автора
(
demo/benchmark_large_house.mjs,demo/performance/README.md,test/performance-workflow.test.mjs) — лишних файлов нет. - Временный зонд, упомянутый в ТЗ («в ветку не идёт»), в диффе действительно отсутствует.
Чего не проверял
- Браузерный смок AC1 не исполнен в этой сессии: сетевая песочница ревью
блокирует динамический импорт бандла демо-сервером (
demo.local), что не зависит от диффа (см. «Как проверялось»). Принято по чтению кода и по реальному зелёному прогону AC2 на точном материале SHA, который исполняет тот же путь на 9 профилях. npx tsc --noEmit/npm test(полный) /npm run buildс сверкой бандла — не перегонялись по новой: Validate на материале SHA (36821012618) зелёный, сверено напрямую черезgh run view(headSha совпадает).npx tsc --noEmitвсё же прогнан попутно (чисто) иnode --test test/performance-workflow.test.mjs— прицельно по изменённому файлу.npm run mutation-gate -- --checkне прогонял: задача явно освобождена от мутационных гейтов на ветке (§2.7, #709), автор сообщил «3 предупреждения, как на dev» — не перепроверено, не требуется по заголовку ревью («мутанты по диффу на материале: не запрашивались»).golden:verify— не применим, нет меткиci:golden, дифф не трогает рендер продукта.pytest tests_backend— не применим,custom_components/**/*.pyне тронут.npm run invariants— не применим, геометрия модели и ссылки на неё не тронуты (дифф целиком вdemo/**/test/**).- Полный
npm run benchmark:*матрица (9 профилей, несколько образцов) локально не воспроизводилась — дорогой прогон, уже воспроизведён в CI (AC2) на точном материале; повтор не добавил бы доказательной силы сверх уже исполненного прогона на том же SHA. - Старая (прошлая)
switchCycleMs-история наdevдо #735 (прогон36803711867) — проверено только то, что workflow существует, зелёный и датирован раньше ветки; содержимое его логов (конкретные медианы «до») не сверялось построчно — не является частью AC этой задачи, только контекст README-абзаца.
Вердикт
Зелёный. Диапазон диффа узкий, строго по заявленным трём поверхностям,
логика сторожа и прогрева прочитана и подтверждена независимым прогоном
unit-якоря против dev (красный) и против ветки (зелёный), AC2 подтверждён
прямым обращением к реальному CI-прогону на точном SHA с числами,
совпадающими с комментарием автора. Находок нет.
Материал раунда
- Ветка:
issue/735-bench-cold-floor3, коммитff8638b6a9ca— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
c7a3cc4364510ebb6ee6453286da468d7f0b4d9egit log --all --format='%H %T' | grep c7a3cc436451 - Тело issue:
eb4f5583553212b688d5e458cb0c49dbff43bf09171217dd7278f2844195a094 - Вердикт конвейера:
green· High 0 · маршрутfix