mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
Вход агента до первого файла кода стоил ≈ 26 700 слов (аудит 22.09). - docs/process/AUTHOR.md и REVIEWER.md — выжимки PROCESS.md: каждый пункт ссылается на раздел канона, ключевые формулировки дословные; test/process-digests.test.mjs сверяет якоря, ссылки и правила. - scripts/entry-cost.mjs — маршрут чтения по роли и бюджет (автор ≤ 12 000 слов, AC1); AGENTS.md «Read this first» называет те же маршруты. - docs/STATUS.md: блок Snapshot генерирует scripts/status-snapshot.mjs (версии — release-contract, счётчики — inventory, теги — git); feature surface и ранние milestones перенесены дословно в docs/STATUS-FEATURES.md. - docs/TESTING.md — действующая инструкция (684 строки, AC3); ручные чек-листы и приложения по issue перенесены дословно в docs/testing-notes/ с индексом и тестом на полноту. - Промпт ревьюера в process.yml читает конспект вместо пересказа правил; машинные требования (строка вердикта, REVIEW_DOC, запрет fetch, таблица «чем краснеет», разделы повторного раунда) сохранены и закреплены тестом. - PROCESS.md: правила не менялись; добавлены ссылка на конспекты в шапке и уточнение в §10.4, что ревьюер конвейера читает конспект. - 7 мутантов в реестре. Issue: #634 User-Visible: no
18 KiB
18 KiB
Диалоги, формы и сводная панель
Приложение к
docs/TESTING.md: перенесено оттуда дословно (#634). Индекс всех приложений —README.md.
Вопрос о несохранённых настройках (#610)
- В русской локали четыре формы настроек показывают Вернуться и
Не сохранять: первая кнопка сохраняет черновик, вторая закрывает
форму без сохранения [auto:
demo/smoke_discard_copy.mjs]. - Заголовок и кнопка потери черновика используют
mdi:content-save-off-outline; обычный warning без override сохраняет иконки открытого замка [auto:demo/smoke_discard_copy.mjs; mutation:discard-confirm-action-icon-falls-back-to-lock]. - RU/EN/DE/FR на 320–640 px, light/dark и DPR 1/2 сохраняют одну строку,
полный текст, безопасный autofocus и возврат к форме
[auto:
demo/smoke_dialog_polish_603.mjs].
Числовые поля со слайдером (#608)
- В настройках комнаты поле размера имени принимает
120посимвольно: до выхода из поля черновик и слайдер остаются на прежнем значении, после выхода оба показывают 120; очистка поля возвращает последнее подтверждённое значение [auto:demo/smoke_range_line_draft.mjs]. - В настройках пространства
123становится 125 только после завершения ввода; движение слайдера во время незавершённого ввода отбрасывает текст и сразу синхронизирует поле [auto:demo/smoke_range_line_draft.mjs,demo/smoke_dialog_config_parity.mjs]. - Возврат раннего clamp на каждом
inputделает свидетель красным [mutation:range-line-clamps-every-keystroke].
Toggle confirmation state (#103)
- Every executable
ToggleNextEffectformats current and expected lines without deriving direction from the state label;togglenames Home Assistant as the authority and a no-operation intent produces no lines [unit:device-toggle.test.mjs]. - All-off/mixed/partial groups use only executable targets for their
active/total count and show skipped targets as a separate line
[unit:
device-toggle.test.mjs]. - EN/RU confirmation renders prompt → current → expected → skipped before
the buttons, wraps a long name at 390 px and has no horizontal scroll
[auto:
smoke_toggle_confirmation.mjs]. - A state race with the same target executes the newly resolved direction;
a changed target set makes zero service calls and shows the existing
retry toast [auto:
smoke_toggle_confirmation.mjs]. - Cover, virtual-light, HA-control and Run confirmations keep their
existing actuation/cancel contracts [auto:
smoke_cover_tap,smoke_virtual_light_toggle,smoke_ha_controls,smoke_controls,smoke_tap_run].
Unified color and opacity picker (#57)
- RGB↔HSV round trips stay within one RGB channel; 3/6-digit HEX input is
normalized and invalid drafts never become persisted colors
[unit:
color-picker.test.mjs]. - Every existing
hp-color-opacityconsumer receives per-card localized labels through the unchanged color/opacity event contract, and the shared component contains no nativeinput[type=color][unit:color-picker.test.mjs]. - The localized full-width OK button is the final picker control, remains at
least 40 CSS px high in native and fallback surfaces, and closes without a
duplicate value event or click-through to the parent card
[unit:
color-picker.test.mjs, auto:smoke_color_picker.mjs,smoke_help_affordance.mjs]. - Invalid HEX keeps the picker open and focused on its error even after a
repeated OK; only new valid HEX input unlocks confirmation, while live
color/opacity updates and the existing outside/trigger/Escape close paths
retain their values [auto:
smoke_color_picker.mjs]. - At 390 px the one surface exposes hue, saturation, brightness, HEX and
opacity without horizontal overflow; keyboard Shift+Arrow, touch pointer
cancellation, invalid HEX recovery, Escape focus return and disabled mode
remain safe [auto:
smoke_color_picker.mjs]. - The color-only Glow consumer keeps the same picker without an opacity row,
and native/fallback floating surfaces remain mutually exclusive with help
[auto:
smoke_help_affordance.mjs]. - The Hue range keeps
0…359, step 1 and its existing input events while its WebKit/Blink and Gecko tracks expose the same cyclic spectrum. A dual theme-aware ring keeps the native thumb distinct from every hue, while forced-colors falls back to system track/thumb rendering [unit:color-picker.test.mjs, auto:smoke_color_picker.mjs]. - The dark mobile and light desktop open-picker goldens are reviewed from the
complete Linux artifact before a beta; baseline acceptance is not part of
the implementation loop [golden:
decor-color-popover-mobile-ru,decor-color-popover-desktop-en].
Unified picker coverage for every color field (#180)
- A recursive source contract rejects every native
input[type=color]in product TypeScript and fixes the complete shared-component inventory at 13 template instances [unit:color-picker.test.mjs]. - The 11 general light/temperature/LQI/Glow/wall palettes and the space room
colour move their existing opacity into the unified picker; color and
alpha update one parent draft atomically [unit:
color-picker.test.mjs, auto:smoke_color_picker_consumers.mjs]. - Global background, space background and activity ripple are color-only;
opening/closing does not materialize an inherited/default value, and
Default/Inherit restore
nullwithout adding alpha [auto:smoke_color_picker_consumers.mjs]. - General settings keep one exclusive picker open among 12 swatches; marker
activity colour and ripple size use separate, non-overlapping mobile rows,
ripple size remains independent, and cancelling the space dialog writes
no color draft [unit:
color-picker.test.mjs, auto:smoke_color_picker_consumers.mjs]. - The three new dialog families are reviewed from the complete Linux
artifact before a beta; implementation does not accept their baselines
[golden:
general-color-popover-desktop-en,device-ripple-color-popover-mobile-ru,space-room-color-popover-desktop-ru].
Contextual help (issues #68 and #86)
- A setting with complete EN/RU/DE/FR help body and ARIA copy shows one 32 px
desktop / 40 px coarse-pointer button with the outlined circled-question
icon. Mouse hover, keyboard focus and tap open the same text surface
[auto:
smoke_help_affordance]. - Empty or whitespace-only help body produces no trigger. A non-empty body
without a complete ARIA label also produces no trigger; neither case adds
a tab stop or reserves visible space [auto:
smoke_help_affordance]. - Escape, outside pointer, owning-dialog scroll, toast and a competing colour
picker close help in the documented order. The Popover and portal fallback
paths stay inside the visual viewport [auto:
smoke_help_affordance]. - Opening help by hover, focus or tap changes neither
clientHeight,scrollHeightnorscrollTopof the owning dialog body. The native Popover and forced portal fallback have the same no-layout-shift contract [auto:smoke_help_affordance]. - Party 1 contains exactly the 11 agreed logical settings: space scale,
general and device Glow radius, room fill, source role and controlled
sources, general/space north, general/space background, zero-thickness
wall style and the show-hidden catalog filter. The regular and onboarding
space dialogs expose the same five space-help controls; opening help does
not change a draft setting or the session-only filter
[unit:
i18n.test; auto:smoke_help_affordance; mutation:settings-help-party1-placement-removed]. marker.controls_hint,gs.bg_daynight_hint,gs.north_hintandspace.zero_wall_helpare absent from all four dictionaries and production templates; state-specific sun/Glow notes remain visible [unit:i18n.test].
Help & private feedback (#43)
- Header order is Fit/zoom → General settings → Help; Help has a 44×44
target, remains available in View and all editors, and is absent in kiosk.
About appears once in Help, Russian routes to the Russian User Guide and
every other locale routes to English [unit:
support-feedback.test.mjs; pre-beta: support dialog smoke/golden matrix]. - A fresh dialog has empty message/contact and attachment off. Empty or
over-limit Unicode input cannot submit; Ctrl/Cmd+Enter uses the same
guard [unit:
support-feedback.test.mjs; pre-beta: phone validation smoke]. - Preview builds no external request and exposes exact JSON bytes, size and
hash. Download equals preview; refresh changes the package namespace;
expiry/discard/replacement and successful submit invalidate only the
intended owner/draft token [backend:
test_support_package.py,test_ha_websocket.py; pre-beta: browser network capture]. - Forbidden sentinels (raw and escaped/base64), unknown fields, names, HA
ids, URLs/paths and live states never reach package bytes. Geometry and
referential pseudonyms survive [backend:
test_support_package.py]. - Relay transport uses only the compiled HTTPS host, follows no redirect,
bounds timeouts/response and never reflects provider text. Relay request,
rate/idempotency, spool-before-delivery and purge tests run in CI
[backend:
test_ha_support_transport.py; relay:python -m unittest discover -s scripts/support-relay/tests -q]. - Success keeps a copyable report id; failure keeps the draft and exact attachment with Retry, Copy message, Download and manual links. Old or mismatched backend leaves About/Guide usable but exposes no fake submit [pre-beta: success/429/timeout/unknown-command smokes in light/dark].
v1.71 audit polish (#434)
- Physical decor inventory counts exact lower-hex allow-listed blob files
and their real sizes independently of sidecars; a valid-shaped sidecar
without its blob remains absent from catalog/list/resolve
[backend:
test_decor_assets.py; mutations:decor-physical-inventory-follows-sidecars,decor-catalog-accepts-sidecar-without-blob]. - Exact orphan re-upload repairs metadata at a full physical quota with
reused:false; valid catalog reuse staystrue, and digest mismatch changes no file. Explicit delete removes all and only exact allow-listed blob names plus the sidecar [HA:test_ha_websocket.py; mutations:decor-orphan-repair-runs-after-quota,decor-orphan-repair-claims-reuse,decor-delete-skips-orphan-blobs]. - Static cards learn exact
decor_assets_api:1only from fresh config/get, revoke it on downgrade and never resolve without it. Positive and missing resolve caches share only connection + config revision + sorted id set; failed calls retry [unit:config-store,space-card-audit-lows,decor-assets; smoke:smoke_space_card_decor_capability]. - Ready→warm cancels an existing dangerous-action promise and removes its
dialog while preserving the committed body; a request in warm refuses,
and warm→ready allows immediately before another render
[smoke:
smoke_danger_confirm_branches; mutations:danger-confirm-warm-language-guard-removed,danger-confirm-warm-transition-cancel-removed]. - Area absence evidence cannot outlive its current snapshot binding
[unit:
device-area-relocation; mutation:area-cleanup-keeps-candidate-outside-current-snapshot]. - The smoke job has its own 20-minute bound and each file is wrapped by GNU
timeout --kill-after=10s 180s; both German route waits have one-second diagnostics [unit:smoke-exception-guard; CI:validate.yml]. - Every well-formed token from an invalid, stale or locally unadoptable
support preview response is discarded exactly once; malformed tokens are
not echoed and cleanup never hides the original failure
[smoke:
smoke_support_feedback; mutation:support-invalid-response-leaks-issued-token].
Надёжность сводной панели (#493)
test/summary-panel.test.mjsстроит индекс по 10 000 HA entities, находит exactentity_idчерез полный индекс, ограничивает выдачу 100 строками и доказывает 0 rebuild при смене state value и ровно один при add/remove/friendly-name change.test/summary-panel-runtime.test.mjsдоказывает authority локальных 200%/150% при repeated same-keysetConfig, stable-id ownership после reorder/delete и lifecycle generation при route/user/permission/kiosk, disconnect/reconnect и поздних async completion.tests_backend/test_summary_panel.py,test_ha_websocket.pyиtest_ha_import_export.pyпроверяют одну writer matrix: omission/explicit empty, readable и старую broken reference, Optimize, full/space/plan-only import, Optimize/Import Undo, copy и delete вместе с independent-setting sentinels.- Перед
S7-code-review:node demo/smoke_summary_panel.mjs. Fixture содержит 200 rows и 10 000 states; закрытые строки не содержат entity options, открыт ровно один picker (до 100 entity + 3 system + current broken), а после трёх warmups и 20 samples действуют бюджеты open p95 ≤250 ms и input p95 ≤50 ms. Тот же smoke проверяет 320/390 CSS px, RU/EN, light/dark, admin/household/kiosk и 200% text без горизонтального overflow и с targets не меньше 44 px. node scripts/mutation-gate.mjs --changed origin/dev..HEADобязан поймать снятие DOM bound, state-value rebuild, local-scale authority, lifecycle generation и Optimize writer guard. Полные golden/smoke/performance и Linux CI HA harness остаются обязательным гейтом точного SHA беты.
Идентичность сводной панели в Masonry (#561)
test/summary-panel.test.mjsпересоздаёт весь production-shapedhui-masonry-view: canonicalcards=[A,B,C], wide-колонки[A,C] [B]и новый narrow DOM[A,B,C]. Slots обязаны остатьсяmasonry-v2:0/1/2, без коллизии old C → new B.- Тот же unit проверяет live reflow, nested stack через ShadowRoot,
remount внутренней House Plan card, два nested instances и повторную
попытку resolution после временно отсутствующего
masonry.cards. test/summary-panel-runtime.test.mjsдоказывает отсутствие localStorage read/write при unresolved identity, отсутствие импорта/удаления старого DOM-path key и независимое восстановление show/scale одинаковых карточек после полного reload.- Мутант
summary-masonry-identity-uses-visual-dom-pathвозвращает структурный DOM path вместо canonical index; focused #561 unit обязан покраснеть. Перед бетой selected summary-panel smoke проверяет ротацию touch/kiosk viewport по общему release-процессу.
Доступность основного View (#565)
test/device-presentation.test.mjsдоказывает whole-segment дедупликацию доступного имени во всех четырёх локалях, сохранение порядка и отсутствие ложного удаления при частичном совпадении.demo/smoke_household_journeys.mjsпроверяет именованную навигацию и единственныйaria-current="page", реальный Tab-focus tooltip, переход к следующему устройству, blur-cleanup и попадание подсказки в viewport. Комбинированный mouse+keyboard сценарий доказывает, что комната не заменяет focus-tooltip, другое устройство сохраняет обычный hover, а pointerleave восстанавливает подсказку всё ещё сфокусированного устройства.demo/smoke_space_card.mjsсчитает сегменты тревоги в доступном имени статической карточки и не добавляет ей интерактивность.- Мутанты
view-current-space-aria-removed,device-accessible-label-dedup-removed,device-focus-tooltip-handler-removedиdevice-focus-tooltip-blur-cleanup-removed, а также мутанты раунда r2device-focus-tooltip-room-hover-overwritesиdevice-pointer-leave-clears-focus-fallbackобязаны покраснеть на своих заявленных гардах.