mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 12:18:51 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6ec494a1a |
@@ -0,0 +1,254 @@
|
|||||||
|
# Issue #124 — isometric view toggle выполняет Stage 1 performance budget
|
||||||
|
|
||||||
|
- **Issue:** https://github.com/Matysh/houseplan-card/issues/124
|
||||||
|
- **Статус документа:** готово к будущей реализации; issue остаётся на `S3-spec`
|
||||||
|
- **Приоритет:** P2
|
||||||
|
- **Тип:** bug/performance, обычный трек
|
||||||
|
- **Пользовательское изменение:** нет; скрытый Labs UI и pixels сохраняются
|
||||||
|
|
||||||
|
## 1. Симптом и доказательство
|
||||||
|
|
||||||
|
В exact-SHA Full Performance для `v1.63.0-beta.1` (`3270e039…`) профиль
|
||||||
|
`large-house-isometric-v1` измерил:
|
||||||
|
|
||||||
|
- `viewToggleMs.median`: 192.8 ms;
|
||||||
|
- pre-#89 baseline: 31.7 ms;
|
||||||
|
- limit: 131.7 ms (`base + 20% + 100 ms`);
|
||||||
|
- все семь candidate samples: 189.2–213.4 ms.
|
||||||
|
|
||||||
|
Одно переиспользование wall union в экспериментальном `2576d9d` дало около
|
||||||
|
10 ms и не закрыло долг. Точная доминирующая причина не доказана. Полная
|
||||||
|
Lit/DOM смена структурных шаблонов — гипотеза, а не готовое решение.
|
||||||
|
|
||||||
|
#156 не является дублем: его regression run имел зелёный `viewToggleMs` на
|
||||||
|
другой сравнительной линии и прямо исключил #124.
|
||||||
|
|
||||||
|
## 2. Цели
|
||||||
|
|
||||||
|
1. Профилированием установить стоимость Flat → Iso и Iso → Flat.
|
||||||
|
2. Уложить canonical profile в неизменённый budget.
|
||||||
|
3. Сохранить Flat/Iso geometry, live layers, actions, fallback и viewport.
|
||||||
|
4. Не увеличить cache/heap и не перенести стоимость в соседнюю метрику.
|
||||||
|
5. Получить воспроизводимое exact-SHA доказательство закрытия исходного долга.
|
||||||
|
|
||||||
|
## 3. Не входит в задачу
|
||||||
|
|
||||||
|
- ослабление budget/noise/minimum samples;
|
||||||
|
- публичное включение изометрии;
|
||||||
|
- новая Stage 3 геометрия/материалы/камера;
|
||||||
|
- изменение Flat pixels или editors/static card;
|
||||||
|
- скрытие live layers на время toggle;
|
||||||
|
- async loading/network request;
|
||||||
|
- замена renderer architecture без измеренной причины;
|
||||||
|
- переоткрытие #89 или поглощение #156.
|
||||||
|
|
||||||
|
## 4. Канонический benchmark
|
||||||
|
|
||||||
|
`demo/benchmark_large_house.mjs --profile=large-house-isometric-v1` остаётся
|
||||||
|
authority. `viewToggleMs` включает полный user-observable цикл:
|
||||||
|
|
||||||
|
1. `_setProjection('flat')`;
|
||||||
|
2. `updateComplete`;
|
||||||
|
3. `_setProjection('iso')`;
|
||||||
|
4. `updateComplete`.
|
||||||
|
|
||||||
|
Нельзя завершить metric до painted DOM либо заменить его pure geometry timing.
|
||||||
|
Minimum — 7 samples на Linux CI с обычной environment/provenance проверкой.
|
||||||
|
|
||||||
|
Для закрытия нужны два сравнения:
|
||||||
|
|
||||||
|
- **debt closure:** candidate против pre-#89 SHA
|
||||||
|
`316ee76a2913066f8ccd86d27fdf7b17dabaff48`, который использовался как
|
||||||
|
историческая граница до merge #89;
|
||||||
|
- **current regression:** тот же exact candidate против актуального `main`/stable
|
||||||
|
обычным workflow, чтобы оптимизация не ухудшила v1.64 соседние paths.
|
||||||
|
|
||||||
|
Если automation не умеет сохранить pinned comparison artifact, допускается
|
||||||
|
manual workflow input с exact SHA и ссылка на run в review. Один зелёный push
|
||||||
|
candidate-vs-parent, где product code одинаков, не закрывает #124.
|
||||||
|
|
||||||
|
## 5. Обязательное профилирование до изменения продукта
|
||||||
|
|
||||||
|
До выбора реализации author публикует в issue/review:
|
||||||
|
|
||||||
|
- отдельные Flat commit и Iso commit timings;
|
||||||
|
- main-thread flame/trace либо эквивалентные измеренные call stacks;
|
||||||
|
- Lit `performUpdate`/template commit долю;
|
||||||
|
- geometry/cache hit/miss и `_isoScene()` build count;
|
||||||
|
- DOM node add/remove count по классам слоёв;
|
||||||
|
- layout/style/paint долю;
|
||||||
|
- минимум три главных cost centres с абсолютным временем.
|
||||||
|
|
||||||
|
Профилирование выполняется на production bundle и той же fixture. Dev build,
|
||||||
|
один sample или ручное ощущение не являются доказательством.
|
||||||
|
|
||||||
|
Diagnostic instrumentation:
|
||||||
|
|
||||||
|
- живёт в benchmark/harness либо за test-only hook;
|
||||||
|
- не создаёт production console noise;
|
||||||
|
- не меняет timing path в финальном closure run;
|
||||||
|
- удаляется либо остаётся как дешёвый выключенный counter с documented owner.
|
||||||
|
|
||||||
|
## 6. Допустимые направления оптимизации
|
||||||
|
|
||||||
|
Конкретное направление выбирается только по §5. Допустимы:
|
||||||
|
|
||||||
|
- стабилизация shared DOM subtree и переключение минимального structural layer;
|
||||||
|
- reuse уже вычисленной scene/union/index geometry;
|
||||||
|
- разделение structural и live templates, чтобы HA layers не пересоздавались;
|
||||||
|
- memoization чистых template inputs с bounded identity;
|
||||||
|
- уменьшение синхронного layout/measurement после projection commit;
|
||||||
|
- использование части `2576d9d`, если trace подтверждает её вклад.
|
||||||
|
|
||||||
|
Запрещено:
|
||||||
|
|
||||||
|
- держать два полноценных интерактивных дерева, если это дублирует tab order,
|
||||||
|
actions, ids или нарушает heap budget;
|
||||||
|
- CSS screenshot/bitmap вместо живого плана;
|
||||||
|
- пропуск `updateComplete`/paint в benchmark;
|
||||||
|
- debounce, который делает UI быстрым только до позднего тяжёлого commit;
|
||||||
|
- global cache без лимита;
|
||||||
|
- UA-specific fast path.
|
||||||
|
|
||||||
|
## 7. Render и DOM invariants
|
||||||
|
|
||||||
|
- Labs off/expired: iso DOM, geometry work, storage/network path отсутствуют;
|
||||||
|
- Flat остаётся reference и не получает Stage 2 DOM/classes/filters;
|
||||||
|
- editors и `houseplan-space-card` всегда Flat;
|
||||||
|
- Iso использует одну canonical scene/projection snapshot;
|
||||||
|
- room fills/hover, Glow/spill, sun, decor/backdrop, vacuum, devices, labels и
|
||||||
|
opening live panels сохраняются;
|
||||||
|
- DOM/tab order и actions совпадают по semantic targets;
|
||||||
|
- no duplicate ids, focus targets или pointer consumers;
|
||||||
|
- toggle сохраняет logical center и zoom по #89;
|
||||||
|
- failure latch и explicit retry остаются работоспособными.
|
||||||
|
|
||||||
|
Если shared subtree остаётся смонтированным между projections, его inertness,
|
||||||
|
ARIA и pointer policy должны быть доказаны, а не основаны только на opacity.
|
||||||
|
|
||||||
|
## 8. Cache и lifecycle
|
||||||
|
|
||||||
|
- `_isoGeometryCache` cap остаётся 8;
|
||||||
|
- `cacheGrowth.isoGeometry` после profile — 0;
|
||||||
|
- repeated Flat ↔ Iso не добавляет новые entries при том же fingerprint;
|
||||||
|
- HA-only state update не rebuild-ит structural geometry;
|
||||||
|
- theme/locale/live state не меняют geometry key;
|
||||||
|
- config geometry change инвалидирует правильную scene;
|
||||||
|
- Labs expiry/removal немедленно делает effective Flat и не удерживает active
|
||||||
|
iso DOM вне bounded cache;
|
||||||
|
- warm remount не усыновляет viewport другой projection.
|
||||||
|
|
||||||
|
## 9. Соседние performance budgets
|
||||||
|
|
||||||
|
Оптимизация не считается успешной, если `viewToggleMs` зелёный, но ухудшены:
|
||||||
|
|
||||||
|
- model ready / first stable render;
|
||||||
|
- space switch;
|
||||||
|
- HA state update;
|
||||||
|
- pan/zoom и resize preview;
|
||||||
|
- switch cycle;
|
||||||
|
- long-task count/max/total;
|
||||||
|
- heap growth;
|
||||||
|
- Flat `large-house-v1`.
|
||||||
|
|
||||||
|
Все лимиты читаются из текущих versioned budget files; hardcoded threshold в
|
||||||
|
production/test не добавляется.
|
||||||
|
|
||||||
|
## 10. Touch, accessibility и actions
|
||||||
|
|
||||||
|
- projection toggle остаётся hidden Labs control;
|
||||||
|
- touch/kiosk gestures имеют прежний safety contract;
|
||||||
|
- активный dialog/tooltip/focus не дублируется между trees;
|
||||||
|
- tap/long press на room/device/opening вызывает тот же outcome в Flat/Iso;
|
||||||
|
- locks/security и service target не меняются;
|
||||||
|
- keyboard tab order не получает скрытых duplicate nodes;
|
||||||
|
- reduced motion не относится к мгновенному projection toggle и не меняет
|
||||||
|
benchmark semantics.
|
||||||
|
|
||||||
|
## 11. Acceptance criteria
|
||||||
|
|
||||||
|
1. Profiling evidence на production fixture публикует измеренную root cause.
|
||||||
|
2. Pinned pre-#89 exact comparison зелёный по неизменённому `viewToggleMs` budget
|
||||||
|
с ≥7 samples.
|
||||||
|
3. Current-main exact comparison также зелёный.
|
||||||
|
4. Все остальные timing/long-task/heap/cache checks профиля зелёные.
|
||||||
|
5. Flat profile остаётся в budget.
|
||||||
|
6. `isoGeometry` cap/growth равны 8/0, repeated toggle — cache hit.
|
||||||
|
7. Flat/Iso golden и live/touch/action smokes зелёные без несвязанной
|
||||||
|
переакцептации.
|
||||||
|
8. Labs off не создаёт iso work/DOM.
|
||||||
|
9. HA state update не rebuild-ит geometry и не переносит cost из toggle.
|
||||||
|
10. Viewport/fallback/warm-remount contract #89/#122 не регрессирует.
|
||||||
|
|
||||||
|
## 12. План тестирования
|
||||||
|
|
||||||
|
### Unit/source contract
|
||||||
|
|
||||||
|
- cache key/cap/hit/invalidation;
|
||||||
|
- effective projection/fallback;
|
||||||
|
- shared DOM ownership и отсутствие duplicate consumers;
|
||||||
|
- Labs-off source contract;
|
||||||
|
- logical center conversion unchanged.
|
||||||
|
|
||||||
|
### Browser smoke
|
||||||
|
|
||||||
|
- repeated Flat ↔ Iso с layer/action parity;
|
||||||
|
- room/device/opening/vacuum interactions;
|
||||||
|
- Glow/sun/room fills remain mounted and state-stable;
|
||||||
|
- theme/state update during/after toggle;
|
||||||
|
- editor round-trip always Flat;
|
||||||
|
- kiosk/touch and warm remount;
|
||||||
|
- injected geometry exception and explicit retry.
|
||||||
|
|
||||||
|
### Golden
|
||||||
|
|
||||||
|
- все existing Flat и Iso baselines verify;
|
||||||
|
- никакой baseline не принимается только ради performance fix;
|
||||||
|
- если measured solution намеренно меняет DOM без pixels, expected diff = 0.
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
- local 1-sample diagnostic допустим только для итерации;
|
||||||
|
- closure evidence — два Linux exact-SHA runs по §4, ≥7 samples;
|
||||||
|
- artifacts содержат raw samples, summaries, provenance и cache counters.
|
||||||
|
|
||||||
|
## 13. План реализации
|
||||||
|
|
||||||
|
1. Добавить/выполнить profiling instrumentation и опубликовать вывод.
|
||||||
|
2. Выбрать минимальный measured optimization.
|
||||||
|
3. Зафиксировать structural/live DOM и cache invariants тестами.
|
||||||
|
4. Реализовать без visual/action diff.
|
||||||
|
5. Прогнать typecheck, unit и build в цикле.
|
||||||
|
6. Перед beta прогнать targeted smoke/golden и оба performance comparison.
|
||||||
|
|
||||||
|
## 14. Документация и release-артефакты
|
||||||
|
|
||||||
|
- changelog не нужен при чистой performance-починке скрытой функции
|
||||||
|
(`User-Visible: no`);
|
||||||
|
- `docs/ISOMETRIC.md` обновляется measured architecture/root cause;
|
||||||
|
- ADR меняется, только если renderer ownership действительно изменён;
|
||||||
|
- `docs/TESTING.md`/performance README фиксируют pinned closure evidence;
|
||||||
|
- user guide и i18n не меняются;
|
||||||
|
- performance artifacts и review links обязательны;
|
||||||
|
- golden обновлять запрещено без отдельного visual rationale.
|
||||||
|
|
||||||
|
## 15. Риски и откат
|
||||||
|
|
||||||
|
| Риск | Мера |
|
||||||
|
| --- | --- |
|
||||||
|
| Cost просто отложен после metric | painted completion + trace |
|
||||||
|
| Два дерева дублируют actions | DOM/ARIA/pointer contract smoke |
|
||||||
|
| Cache растёт | cap/growth exact assertions |
|
||||||
|
| Flat подорожал | отдельный flat profile |
|
||||||
|
| Решение основано на гипотезе | profiling до product diff |
|
||||||
|
|
||||||
|
Откат возвращает прежний render path. Cache/storage schema не меняются. Если
|
||||||
|
оптимизация ломает Flat/actions, Labs kill switch немедленно даёт effective Flat,
|
||||||
|
но это mitigation, а не критерий принятия красного кода.
|
||||||
|
|
||||||
|
## 16. Принятые технические предположения
|
||||||
|
|
||||||
|
- историческая debt-граница — exact pre-#89 SHA `316ee76…`;
|
||||||
|
- benchmark продолжает измерять полный Flat → Iso → Flat/Iso user cycle;
|
||||||
|
- measured solution может не использовать `2576d9d`;
|
||||||
|
- public activation изометрии остаётся отдельной будущей задачей.
|
||||||
@@ -84,6 +84,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
|
|||||||
| [#107](https://github.com/Matysh/houseplan-card/issues/107) Переключение виртуального источника света «Всегда» | [107-virtual-light-toggle.md](107-virtual-light-toggle.md) |
|
| [#107](https://github.com/Matysh/houseplan-card/issues/107) Переключение виртуального источника света «Всегда» | [107-virtual-light-toggle.md](107-virtual-light-toggle.md) |
|
||||||
| [#122](https://github.com/Matysh/houseplan-card/issues/122) Изометрический режим Stage 2: скрытый режим и визуальная полировка | [122-isometric-stage2.md](122-isometric-stage2.md) |
|
| [#122](https://github.com/Matysh/houseplan-card/issues/122) Изометрический режим Stage 2: скрытый режим и визуальная полировка | [122-isometric-stage2.md](122-isometric-stage2.md) |
|
||||||
| [#123](https://github.com/Matysh/houseplan-card/issues/123) Split из вершины не меняет наружную геометрию стен | [123-corner-split-wall.md](123-corner-split-wall.md) |
|
| [#123](https://github.com/Matysh/houseplan-card/issues/123) Split из вершины не меняет наружную геометрию стен | [123-corner-split-wall.md](123-corner-split-wall.md) |
|
||||||
|
| [#124](https://github.com/Matysh/houseplan-card/issues/124) Performance переключения Flat/Iso | [124-isometric-view-toggle-performance.md](124-isometric-view-toggle-performance.md) |
|
||||||
| [#137](https://github.com/Matysh/houseplan-card/issues/137) Узлы и линии привязки в редакторе Плана | [137-plan-snap-overlay.md](137-plan-snap-overlay.md) |
|
| [#137](https://github.com/Matysh/houseplan-card/issues/137) Узлы и линии привязки в редакторе Плана | [137-plan-snap-overlay.md](137-plan-snap-overlay.md) |
|
||||||
| [#141](https://github.com/Matysh/houseplan-card/issues/141) Бесшовные стыки перегородок и открытых контуров | [141-wall-junctions.md](141-wall-junctions.md) |
|
| [#141](https://github.com/Matysh/houseplan-card/issues/141) Бесшовные стыки перегородок и открытых контуров | [141-wall-junctions.md](141-wall-junctions.md) |
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user