mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
docs: specify iso perf witnesses and diff-aware performance smoke
User-Visible: no Issue: #473
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# #473 — Свидетели перф-дельты #160 и диффозависимый перф-смок в Validate
|
||||
|
||||
- **Issue:** https://github.com/Matysh/houseplan-card/issues/473
|
||||
- **Тип / приоритет:** infra, process / P2
|
||||
- **Трек:** полный — две поверхности: свидетели на продуктовом коде и workflow с бюджетами
|
||||
- **Оценка:** ценность для разработки 8/10; сложность 3/10; риск 2/10
|
||||
- **Связано:** #160, #451, #458, #466, #467; `PROCESS.md` §8, §11.4
|
||||
|
||||
## 1. Проблема
|
||||
|
||||
Первый кандидат `v1.73.0-beta.1` (`de215578`) упал на полных бенчмарках с
|
||||
регрессией Stage 3 изометрии: первый кадр 1 516 → 9 870 мс, цикл 12 пространств
|
||||
1 746 → 30 545 мс (прогон 34013995127). Два раунда код-ревью #160 её не
|
||||
увидели — и не могли: ревью по §8 гоняет typecheck, unit и build, а
|
||||
`performance_smoke` в Validate меряет только два glow-профиля. Изометрический
|
||||
профиль с потолком первого кадра `hardMaxMs: 3500` существует, но в смоке не
|
||||
участвует.
|
||||
|
||||
Починено по §11.4 четырьмя коммитами (`f1b9bbf3`, `b69743c0`, `196fa096`,
|
||||
`b3ca0ca2`, +301/−64 в `iso-overlays.ts`, `iso-scene-render.ts`,
|
||||
`houseplan-card.ts`) без ревью. Двенадцать мутантов `stage3-w1…w12` защищают
|
||||
визуальный контракт Stage 3; **ни один не патчит механизмы перф-дельты**:
|
||||
LRU-кэш размещений с подписью, кэш по идентичности массива силуэтов, повторное
|
||||
использование при зуме внутрь, AABB-отсечение, envelope без коллизий.
|
||||
|
||||
Два дефекта одного класса: горячий код без свидетелей и гейт, который есть, но
|
||||
не там, где нужен.
|
||||
|
||||
## 2. Скоуп
|
||||
|
||||
1. Свидетели на четыре механизма перф-дельты (§4) — через них проходит и
|
||||
постфактум-ревью этого кода.
|
||||
2. Диффозависимый набор профилей у существующего `performance_smoke` (§5).
|
||||
|
||||
## 3. Не-скоуп
|
||||
|
||||
- Изменение самих механизмов кэширования #160 — если свидетель найдёт дефект,
|
||||
он заводится отдельным issue.
|
||||
- Полные бенчмарки в код-ревью или в Validate.
|
||||
- Пересмотр §11.4.
|
||||
- Пороги полных профилей (`hardMaxMs` и регрессионные коэффициенты).
|
||||
|
||||
## 4. Контракт свидетелей
|
||||
|
||||
Каждый мутант — на один защитный контракт, с гардом-юнитом в
|
||||
`test/iso-scene-render.test.mjs` / `test/iso-overlays.test.mjs`, проверенным
|
||||
отрицательным прогоном штатным раннером.
|
||||
|
||||
| Свидетель | Контракт | Мутация | Чем краснеет |
|
||||
|---|---|---|---|
|
||||
| `iso-placement-cache-ignores-selected` | подпись кэша (`iso-scene-render.ts:805-807`) включает все входы, меняющие размещение | `selected ? 1 : 0` выброшен из `shapeSignature` | плита с `selected=true` после `selected=false` при том же id обязана дать иное размещение, а не кэшированное |
|
||||
| `iso-placement-cache-survives-silhouette-change` | кэш размещений привязан к **идентичности** массива силуэтов (`WeakMap`, `:783`), новая геометрия — новый ключ | ключ WeakMap заменён константным объектом | два вызова с разными массивами силуэтов при тех же плитах обязаны дать разные размещения там, где стена появилась |
|
||||
| `iso-zoom-in-reuses-near-wall-plate` | повторное использование при зуме внутрь (`:812-822`) только для плит, не бывших у стены, либо очищенных в пределах cap | гард `!previous.nearWallBefore \|\|` снят | плита у стены при зуме внутрь обязана пройти точный резолвер, а не вернуть прежний объект |
|
||||
| `iso-aabb-rejects-touching-wall` | AABB-отсечение (`iso-overlays.ts:342-345`) не отбрасывает силуэт, пересекающий плиту | `boundsNear` требует строгого перекрытия без `gap` и без равенства | плита, касающаяся стены ровно по границе с зазором `gap`, обязана считаться «у стены» |
|
||||
|
||||
Пятый контракт — envelope без коллизий (`resolveCollisions === false`) даёт те
|
||||
же границы, что точный резолвер до nudge, — юнитом без мутанта: его
|
||||
нарушение меняет fit, а не картинку, и у него нет однозначной мутации.
|
||||
|
||||
Все четыре гарда — чистые юниты на экспортах `buildIsoOverlayRenderScene` и
|
||||
`resolveIsoOverlayPlacement`; фикстура — три комнаты, одна стена, одна плита у
|
||||
стены и одна вдали, как в существующих тестах.
|
||||
|
||||
## 5. Контракт перф-смока
|
||||
|
||||
`performance_smoke` в `validate.yml` становится диффозависимым:
|
||||
|
||||
- всегда — два glow-профиля, как сегодня;
|
||||
- дифф задел `src/iso-*` — добавляется `large-house-isometric-v1`;
|
||||
- дифф задел `src/live-*`, `src/render-*`, `src/houseplan-render-lifecycle.ts`,
|
||||
`src/houseplan-card.ts` — добавляется `large-house-interaction-v1`.
|
||||
|
||||
Классификацию делает `changes` (существующий job) двумя новыми выходами
|
||||
`perf_iso` и `perf_interaction` по тем же `has(...)`-шаблонам. Профили идут с
|
||||
`--variants=60 --samples=3 --warmups=1 --absolute-only` и **своими
|
||||
smoke-бюджетами** `budgets-isometric-smoke.json`, `budgets-interaction-smoke.json`
|
||||
(`minimumSamples: 3`, потолки — `hardMaxMs` из полных профилей). Регрессионные
|
||||
коэффициенты в смоке не участвуют: сравнивать не с чем, абсолютный потолок
|
||||
достаточен — 9 870 мс против 3 500 он ловит с одного образца.
|
||||
|
||||
Ключ переиспользования `performance_smoke` (`reuse`) включает набор профилей:
|
||||
кэшированный результат glow-only не засчитывается прогону, которому нужен
|
||||
изометрический.
|
||||
|
||||
Ревью-промпт не меняется: он уже принимает зелёный Validate на SHA как
|
||||
подтверждение дешёвых гейтов, а смок — часть Validate.
|
||||
|
||||
## 6. Совместимость и откат
|
||||
|
||||
Продуктовый код не меняется. Откат §5 — одним коммитом убрать выходы и
|
||||
условные шаги; свидетели §4 остаются, они безвредны.
|
||||
|
||||
## 7. Критерии приёмки
|
||||
|
||||
| AC | Критерий | Доказательство |
|
||||
|---|---|---|
|
||||
| AC1 | Четыре свидетеля §4 в реестре, каждый ловится: «тест покраснел, поймано 1 из 1» | отрицательный прогон `--id=` штатным раннером |
|
||||
| AC2 | Envelope без коллизий равен точному до nudge | unit |
|
||||
| AC3 | `changes` отдаёт `perf_iso` и `perf_interaction`; смок добавляет профиль ровно при своём выходе | контрактный тест на YAML |
|
||||
| AC4 | Smoke-бюджеты новых профилей валидны для `benchmark:compare --absolute-only` и повторяют `hardMaxMs` полных | unit: чтение обоих файлов, сравнение потолков |
|
||||
| AC5 | Ключ `reuse` для `performance_smoke` различает наборы профилей | контрактный тест на YAML |
|
||||
| AC6 | Воспроизведение: на дереве `de215578` изометрический smoke-бюджет краснеет по первому кадру | замер один раз при реализации, результат в issue с командой |
|
||||
| AC7 | На текущем `dev` оба новых профиля укладываются в потолки за 3 образца | прогон в CI этой ветки |
|
||||
|
||||
## 8. Release-артефакты
|
||||
|
||||
`User-Visible: no`; changelog не трогается. Документация: абзац в
|
||||
`docs/PROCESS.md` §8 о диффозависимых профилях смока.
|
||||
|
||||
## 9. Затронутые файлы
|
||||
|
||||
- `scripts/mutation-gate.mjs` — четыре мутанта;
|
||||
- `test/iso-scene-render.test.mjs`, `test/iso-overlays.test.mjs` — гарды и AC2;
|
||||
- `.github/workflows/validate.yml` — выходы `changes`, условные шаги смока, ключ `reuse`;
|
||||
- `demo/performance/budgets-isometric-smoke.json`, `budgets-interaction-smoke.json` — новые;
|
||||
- `test/validate-workflow.test.mjs` — AC3, AC5; `test/performance-budget.test.mjs` — AC4;
|
||||
- `PROCESS.md` §8.
|
||||
|
||||
## 10. Принятые предположения
|
||||
|
||||
- Изометрический профиль на 3 образцах укладывается в 20-минутный лимит job
|
||||
вместе с glow-профилями; если нет — лимит поднимается в этой же задаче с
|
||||
замером.
|
||||
- Мутация AABB (`boundsNear` без `gap`) достижима существующей фикстурой «плита
|
||||
у стены»; если фикстура даёт перекрытие, а не касание, добавляется касание.
|
||||
@@ -186,6 +186,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
|
||||
| [#460](https://github.com/Matysh/houseplan-card/issues/460) Детерминированное завершение кадра живого редактора | [460-live-editor-settlement.md](460-live-editor-settlement.md) |
|
||||
| [#461](https://github.com/Matysh/houseplan-card/issues/461) Быстрый commit промежуточной точки цепочки стен | [461-wall-draw-click-performance.md](461-wall-draw-click-performance.md) |
|
||||
| [#464](https://github.com/Matysh/houseplan-card/issues/464) Верхний контекстный слой Zigbee-топологии | [464-zigbee-topology-layer-order.md](464-zigbee-topology-layer-order.md) |
|
||||
| [#473](https://github.com/Matysh/houseplan-card/issues/473) Свидетели перф-дельты #160 и диффозависимый перф-смок | [473-iso-perf-witnesses-and-smoke.md](473-iso-perf-witnesses-and-smoke.md) |
|
||||
|
||||
## P3
|
||||
|
||||
|
||||
Reference in New Issue
Block a user