Merge origin/dev into issue/663-stairs

Issue: #663
User-Visible: no
This commit is contained in:
Matysh
2026-09-26 21:45:22 +03:00
25 changed files with 239 additions and 76 deletions
+1 -1
View File
@@ -406,7 +406,7 @@ committed copy (#657):
npm run bundle:sync # build + dist → demo/srv/assets (#255)
npm run bundle:clean # before an ordinary commit: dist back to the committed copy (#657)
npm run bundle:release # candidate only: build + dist → custom_components + demo/srv/assets
npm run bundle:budget # initial View graph <= 256000 B gzip (#337)
npm run bundle:budget # initial View graph within INITIAL_VIEW_GZIP_BUDGET (scripts/bundle-budget.mjs, #337/#367)
```
CI (`bundle-policy --verify`) checks the fresh build's integrity on every push
+15 -8
View File
@@ -104,9 +104,12 @@ tree repeatedly. Do **not** replace it with `--depth=1`: a shallow clone is abou
the same size but has no `merge-base`, so the process gate, `smoke-select` and
every `origin/dev..HEAD` range stop working.
The HA-harness backend tests (`tests_backend/test_ha_*.py`) need Python ≥3.13 and
`pytest-homeassistant-custom-component home-assistant-frontend`; CI runs them on
every push — locally they are skipped when `homeassistant` is not importable.
The HA-harness backend tests (`tests_backend/test_ha_*.py`) need the
repository-pinned Python (`.python-version`) and
`pytest-homeassistant-custom-component home-assistant-frontend`; their canon is
Linux CI or WSL (`bash scripts/wsl-setup.sh --verify`). Without an importable
`homeassistant` they are not collected at all — not skipped — and pytest prints
`HA harness NOT collected: …` (#630).
## Ground rules
@@ -114,8 +117,10 @@ every push — locally they are skipped when `homeassistant` is not importable.
`docs/STATUS.md` for state changes; `docs/DEVELOPMENT.md` for new gotchas.
- Every UI string goes through `src/i18n/<lang>.json`; follow the
[Translations](#translations) flow for registry and backend parity.
- The built card must be committed in sync: `cp dist/houseplan-card.js
custom_components/houseplan/frontend/` (CI compares them byte-for-byte).
- The committed bundle changes only in a release candidate: `npm run
bundle:release` in a commit with a `Release:` trailer (#657). An ordinary task
restores it with `npm run bundle:clean` before committing — the `commit-msg`
hook refuses a bundle change otherwise.
- Tap actions have a security model (locks/alarms never toggle from the plan) —
see `resolveToggleIntent` in `src/device-toggle.ts`; don't weaken it.
- Every commit follows the issue and trailer contract in `PROCESS.md`.
@@ -125,6 +130,8 @@ every push — locally they are skipped when `homeassistant` is not importable.
## Architecture
Start with `docs/ARCHITECTURE.md` (data model, WS API, coordinate system) and
`docs/STATUS.md` (current state). Release: bump the version in `package.json`,
`manifest.json`, `const.py`, `CARD_VERSION`, tag `vX.Y.Z`, publish a GitHub release —
the workflow attaches the card bundle.
`docs/STATUS.md` (current state). Release mechanics live in `docs/STATUS.md` › Workflow: the version sources are
the ones checked by `scripts/release-contract.mjs`, prereleases go through
`npm run release:prerelease -- <tag> --issues=… --yes` (or the manual
`Publish prerelease` workflow), and stable installable assets are published only
by `release.yml` (#540).
+2 -2
View File
@@ -61,8 +61,8 @@ sync across screens.
1. Install the integration and open **House Plan** in the Home Assistant sidebar.
2. Create the first **space**: upload SVG/PNG/JPG/WebP, reuse an uploaded image,
or choose no image and draw the plan by hand.
3. In Plan, select **Room outline**, place vertices, and click the first point to
close the outline.
3. In Plan, select **Walls** and draw one continuous chain around the room: when
it closes an area, the room dialog opens.
4. Name the room and bind it to a Home Assistant area. Use “No area” for a room
that has no devices.
5. Open Device: devices from the bound area are already placed; drag their
+2 -2
View File
@@ -59,8 +59,8 @@ Assistant — и устройства появятся на плане авто
1. Установите интеграцию и откройте **House Plan** в боковом меню Home Assistant.
2. Создайте первое **пространство**: загрузите SVG/PNG/JPG/WebP либо выберите
вариант без изображения, чтобы нарисовать план вручную.
3. В редакторе «План» выберите **Контур комнаты**, поставьте вершины и замкните
контур нажатием на первую точку.
3. В редакторе «План» выберите **Стены** и нарисуйте непрерывную цепочку по
периметру комнаты: когда она замкнёт область, откроется диалог комнаты.
4. Назовите комнату и свяжите её с зоной Home Assistant. Для помещения без
устройств выберите «Без зоны».
5. Откройте «Устройства»: устройства связанной зоны уже размещены автоматически;
+1 -4
View File
@@ -49,10 +49,7 @@ houseplan-card/
│ ├─ space-model-selection.ts # active-or-first and exact optional space selectors
│ ├─ render/opening-tunnels.ts # immutable SVG projection of resolved tunnel geometry/fills
│ ├─ editor.ts # GUI config editor (ha-form + selectors)
│ ├─ rules.ts # icon rules (iconFor), filtering, groups, fallback order
│ └─ data/
│ ├─ house.ts # geometry: ROOMS (rooms→area), FLOOR_VB (viewBox), names
│ └─ backgrounds.ts # VECTOR plans (SVG base64) + FLOOR_BG_RECT (positioning)
│ └─ rules.ts # icon rules (iconFor), filtering, groups, fallback order
├─ dist/ # entry + manifest + content-hashed JS chunks
├─ demo/golden/ # deterministic HP-QA-01 matrix, capture/verify/accept
├─ demo/performance/ # large-house budgets and same-runner comparison
+1 -1
View File
@@ -341,7 +341,7 @@ commands and the explicit review workflow are documented in
```bash
cd /tmp/hpc && npm ci # once
npm run bundle:sync # build + entry/manifest/chunks → demo
npm run bundle:budget # initial View graph must stay <= 256000 B gzip
npm run bundle:budget # initial View graph within INITIAL_VIEW_GZIP_BUDGET (scripts/bundle-budget.mjs)
npm run bundle:clean # before an ordinary commit (#657)
npm run bundle:release # candidate only: also → custom_components/houseplan/frontend
node scripts/bundle-tree.mjs dist custom_components/houseplan/frontend # candidate parity
+1 -1
View File
@@ -2,7 +2,7 @@
Этот документ — developer-facing канон для issue
[#267](https://github.com/Matysh/houseplan-card/issues/267). Пользовательские
названия и обещания остаются в [USER-GUIDE.ru.md](USER-GUIDE.ru.md#12-отображение-устройств);
названия и обещания остаются в [USER-GUIDE.ru.md](USER-GUIDE.ru.md#12-визуальные-состояния-устройств);
здесь зафиксировано, как уже разрешённые факты превращаются в одно «лицо»
маркера. Любое изменение результата требует изменения строки, fixture и
mutation evidence в одном pull request.
+6
View File
@@ -119,6 +119,9 @@ the exact Linux CI SHA.
## Stage 2 composition (#122)
> Historical: written while 2.5D was a hidden `hp_alpha` experiment. Since #649
> it is public; activation is described in [Activation](#activation).
Stage 2 evolves the same hidden `iso` experiment; it does not add a flag,
setting or public activation path. The accepted implementation contract is
`docs/specs/122-isometric-stage2.md` and the fixed composition decisions are in
@@ -204,6 +207,9 @@ budget nor treats fallback as benchmark success.
## Stage 4 visual handoff (#570)
> Historical: written while 2.5D was a hidden `hp_alpha` experiment. Since #649
> it is public; activation is described in [Activation](#activation).
Stage 4 refines the same hidden `iso` presentation behind `hp_alpha`; it adds no
public switch, configuration field or experiment id. Stage 3 history remains in
`docs/specs/160-isometric-stage3.md` and
+2 -4
View File
@@ -2,9 +2,7 @@
Этот каталог — точка входа в русскоязычную документацию House Plan.
> **Сверено с версией v1.60.0.** Продукт с тех пор ушёл вперёд (линия 1.64);
> при расхождении этого каталога с `docs/USER-GUIDE.ru.md` и changelog верить им.
> Пересверка каталога — отдельная документационная задача.
> При расхождении этого каталога с `docs/USER-GUIDE.ru.md` и changelog верить им.
| Документ | Для кого | Что внутри |
|---|---|---|
@@ -12,7 +10,7 @@
| [Радары присутствия](RADAR.md) | Пользователи, администраторы и интеграторы | Поддерживаемые профили, привязка источников, установка и калибровка, статусы данных, приватность и диагностика |
| [Редактор подложки и декора](DECOR-EDITOR.md) | Пользователи, тестировщики и разработчики | Инструменты, единое выделение и трансформации, физические размеры, магнит, Undo/Redo, поведение картинки-подложки и совместимость старых полей |
| [Лестницы и переходы между этажами](STAIRS.md) | Пользователи, тестировщики и разработчики | Прямые и винтовые лестницы, размеры, направление подъёма, магнит, связь этажей, площадь и ограничения 2.5D |
| [GitHub Issues](https://github.com/Matysh/houseplan-card/issues) и [Project v2](https://github.com/users/Matysh/projects/1) | Владелец, разработчики и контрибьюторы | Единственный актуальный backlog: задачи, приоритеты, решения и статусы выполнения |
| [GitHub Issues](https://github.com/Matysh/houseplan-card/issues) | Владелец, разработчики и контрибьюторы | Единственный актуальный backlog: задачи, приоритеты и решения; статус — в метках issue (`PROCESS.md` §9) |
Старые тематические документы в этом каталоге остаются инженерными спецификациями и историей решений. При расхождении пользовательского описания с интерфейсом текущей версии приоритет имеет новое руководство, а при расхождении с фактическим поведением — код текущей версии.
+2 -2
View File
@@ -77,8 +77,8 @@ Track progress in `custom_components/houseplan/quality_scale.yaml` (done/exempt
## Phase 10 — Community & distribution
- [ ] hacs/default PR **#9004** through moderation (#8995 was bot-closed for a
non-template body; #9004 is queued with the label since 2026-07-22).
- [x] hacs/default PR **#9004** merged on 2026-08-25: House Plan is in the HACS
default catalog (#8995 was bot-closed earlier for a non-template body).
- [ ] Demo GIF/video for README (the single biggest driver of adoption for dashboard cards).
- [ ] Forum post in the Floorplan category + Reddit r/homeassistant showcase once
the demo assets exist.
+9 -6
View File
@@ -48,9 +48,9 @@ deliberate degradation is allowed under `TOUCH-SUPPORT.md`.
| J1 | "Show the whole home and what's happening right now" — live spatial overview: device states, room fills (light/temp/LQI), values, multi-floor tabs | **Closed** |
| J2 | "Something is wrong — show me *where*" — leak/smoke/gas pulse, open doors/windows, unlocked locks, red dot on devices HA added silently | **Closed** |
| J3 | "Let me act on the obvious right from the plan" — tap-to-toggle for safe domains, info cards, guarded lock action | **Closed** |
| J4 | "From zero to a working plan in one evening, no Inkscape/YAML" — image/PDF/draw, floors-import wizard, room polygons bound to areas, filtered auto-placement, editable icon rules | **Closed**; onboarding polish is *partial* (no registry-driven room suggestions) |
| J4 | "From zero to a working plan in one evening, no Inkscape/YAML" — image (SVG/PNG/JPG/WebP) or draw, floors-import wizard, room polygons bound to areas, filtered auto-placement, editable icon rules | **Closed**; onboarding polish is *partial* (no registry-driven room suggestions) |
| J5 | "Room climate at a glance" — per-room temperature/humidity, comfort-range fills, room-card metrics | **Closed** |
| J6 | "Keep the plan true as the home evolves" — new-device flag, two editors, drag/resize, merge/split, multi-client live sync, optimistic locking | **Closed** |
| J6 | "Keep the plan true as the home evolves" — new-device flag, three editors (plan, devices, background), drag/resize, merge/split, multi-client live sync, optimistic locking | **Closed** |
| J7 | "Is my Zigbee mesh healthy *here*?" — LQI badges, per-room average/fill and opt-in direct-neighbour links for one hovered device | **Closed** (spatial diagnostics; no persistent full-mesh graph) |
## Partially covered — improvement backlog stays inside these
@@ -62,11 +62,14 @@ deliberate degradation is allowed under `TOUCH-SUPPORT.md`.
formatting only.
- **Accessibility**: `prefers-reduced-motion` only; no keyboard navigation in
editors, no ARIA labelling of the plan.
- **Docs/screenshots**: README predates the two-editor redesign.
- **Docs**: the English user guide covers less than the Russian one
([#668](https://github.com/Matysh/houseplan-card/issues/668)).
## Known gaps that fit the mission (build only on owner's request)
- Person/presence shown in rooms (classic floorplan ask; pure J1).
- Person/presence shown in rooms (classic floorplan ask; pure J1). Started on the
owner's request with mmWave radar presence, [#485](https://github.com/Matysh/houseplan-card/issues/485)
(`docs/RADAR.md`); anything beyond it stays here.
### The lock invariant, stated precisely (review CR-1)
No lock or alarm panel is ever actuated **by a tap on the plan**: icons, lock
@@ -158,8 +161,8 @@ the file — and if a future version wants to reclaim that space, it asks.
> a plan image (or draw one), outline rooms and bind them to HA areas — your
> devices appear in place, automatically, with live states. Glance at the wall
> tablet: what's on, what's open, what's too cold, what's leaking, what's new.
> Tap to act — safely: locks never toggle by accident. Two built-in editors
> (plan and devices) mean no Inkscape, no YAML, no external tools — ever.
> Tap to act — safely: locks never toggle by accident. Three built-in editors
> (plan, devices and background) mean no Inkscape, no YAML, no external tools — ever.
**Tasks it closes:** whole-home live overview · spatial alerts (leak/smoke/open/
unlocked/new device) · safe quick actions · per-room climate · Zigbee mesh
+22 -26
View File
@@ -63,10 +63,11 @@ same commit as the behaviour.
## Where things live
- **Source of truth:** the git repo (GitHub `main`). In a sandbox session: clone from GitHub or
from `houseplan-card.git.bundle` (kept fresh in the user folder root *and* in `houseplan-card/`).
- **User folder** `houseplan/houseplan-card/` — a file mirror of the repo (synced after every
commit; the mount cannot delete files, so a few stale artifacts linger — git is authoritative).
- **Source of truth:** the git repo on GitHub — work lands on `dev`, stable releases on
`main`. In a sandbox session clone it from GitHub.
- **Owner's folder:** `houseplan-card-src/houseplan-card` is the author's tree and
`houseplan-card-src/hp-dev` the owner's worktree on `dev` (`AGENTS.md` › Working
trees). The former file mirror `houseplan/houseplan-card/` is no longer maintained.
- **Production config:** server-side on the HA instance, `.storage/houseplan.config` +
`.storage/houseplan.layout` (backups `.bak-v1100` exist on the box).
@@ -78,39 +79,34 @@ same commit as the behaviour.
The former local product plan is preserved only as a snapshot at
[`legacy/docs/PRODUCT-IMPROVEMENT-PLAN.ru.md`](../legacy/docs/PRODUCT-IMPROVEMENT-PLAN.ru.md)
and must not be updated or used as a backlog.
1. **hacs/default PR #9004** — accepted by the bot into the review queue ('New default
repository' label). Minor issues ⇒ the bot drafts the PR (fix and re-ready).
2. GitHub auth: fine-grained PAT (Contents R/W, issued 2026-07-23) in the sandbox
`~/.git-credentials`; pushes go over SSH with the `ha_jb` key. The old classic PAT
expired and is gone.
3. Privacy: legacy real-house plan sources (`assets/`) and screenshots were
1. Privacy: legacy real-house plan sources (`assets/`) and screenshots were
removed from the current tree. Public documentation images are generated
from synthetic fixtures by the `Docs screenshots` workflow, accepted with `npm run docs:accept -- --reviewed`, and indexed in
`docs/images/screenshots.json`. Old images persist in git history and release
archives; history rewrite is deliberately not done because it would break
release tags and HACS installs.
4. Stale files on the mount that cannot be deleted from the sandbox: `src/data/` leftovers,
`brand_preview.png`, old nested bundle copies — ignore, git is authoritative.
5. Roadmap: phases 7–10 are DONE (v1.12.0 quality scale, v1.13.0 universality,
2. Roadmap: phases 7–10 are DONE (v1.12.0 quality scale, v1.13.0 universality,
v1.13.1 distribution). Next candidates: measure backend coverage (>95% goal);
mypy strict.
6. The public-doc screenshot harness is versioned in `demo/docs/capture.mjs` and
3. The public-doc screenshot harness is versioned in `demo/docs/capture.mjs` and
reuses the production component plus deterministic golden fixtures.
## How to resume work in a fresh session (checklist)
1. Read this file, then CHANGELOG.md (top entries), DEVELOPMENT.md (environment gotchas).
2. Restore the repo: `git clone <user-folder>/houseplan-card.git.bundle hpcN` in `/tmp`
(files from *previous* sandbox sessions in `/tmp` belong to `nobody` and are unreadable —
always clone into a fresh directory; `npm ci` again).
3. Deployment needs the `ha_jb` SSH key — it lives in the user folder at
`houseplan/.secrets/ha_jb` (outside git) and often survives in the sandbox home
`~/.ssh/ha_jb`; copy with chmod 600. Only ask the user if both are gone.
4. Build only in `/tmp` (never on the mount), `npm run build` (starts with `tsc --noEmit`),
md5-verify after every deploy, restart HA via
`nohup ha core restart >/dev/null 2>&1 </dev/null &` (otherwise the SSH session hangs).
5. GitHub pushes: SSH remote with the `ha_jb` key; API releases with the fine-grained
PAT from `~/.git-credentials` (see the watchlist).
1. Read by role, as `AGENTS.md` › Read this first lists it: author — `docs/SCOPE.md` →
`AGENTS.md` → `docs/process/AUTHOR.md` → this file; reviewer — `docs/SCOPE.md` →
`AGENTS.md` → `docs/process/REVIEWER.md`; pipeline, gates or process — through
`PROCESS.md`.
2. Clone `https://github.com/Matysh/houseplan-card` and run `npm ci` — it installs the
hooks (`git config core.hooksPath` → `.githooks`). On the owner's Windows machine use
`scripts/windows-toolchain.ps1`; in WSL, an ext4 clone and
`bash scripts/wsl-setup.sh --verify`.
3. Start a task from its packet: `node scripts/task-packet.mjs --issue NN`.
4. Build only through `npm run build`; the task's local gate is `npm run gate:small`
(`AGENTS.md` › Gates).
5. Nothing is copied to the home instance by hand (`PROCESS.md` §12): it updates
through HACS by tag, and the dev stand takes the head of `dev` from the
`dev-build` branch.
## Product scope
+5 -3
View File
@@ -273,9 +273,11 @@ target the icon element itself.
**`houseplan-space-card` is a different card.** The read-only space card is
its own custom element with its own shadow root, so it needs its own card-mod
block. It carries the same `data-hp` attributes for the objects it draws
(rooms, room labels, device markers); it draws no openings and no decor
layer, so those simply are not there.
block. It carries the same `data-hp` attributes for the objects it draws:
rooms, room labels, device markers, openings (`data-hp="opening"` with
`data-id`/`data-kind`, class `.static-opening`) and decor images
(`data-hp="decor"`, class `.dimage`). Vector decor shapes and furniture are not
drawn there, so their hooks simply are not there.
**The kiosk header is visually absent.** The full header is hidden by CSS in
kiosk mode, but most of its existing children remain in the DOM. A selector
+1 -1
View File
@@ -199,7 +199,7 @@ registry-сценарий. Для limited/read-only нужен локальны
- Stranded migration repair / geometry repair — Стенд: не проверяется руками (WS-команда) — backend.
- Редакторы видят весь холст — Стенд: «Yard» (одна комната): в редакторе плана виден весь белый квадрат, во View — контент-фит.
- Save ждёт пропорции выбранного плана — Стенд: прикрепить «уже загруженный» план и мгновенно Save.
- Зум ниже фита (пол 0.4x) — Стенд: минусовать зум ниже 100%.
- Зум ниже фита (пол 1/3, `MIN_ZOOM`) — Стенд: минусовать зум ниже 100%.
- Migration crash / parallel upload quota — Стенд: не проверяется (kill HA между записями невозможен) — backend.
- Зум открывается на контенте — Стенд: «Yard» открывается комнатой на весь экран.
- Удаление используемого плана запрещено — Стенд: в списке «уже загруженные» у подложки First Floor (first-floor.svg) delete неактивен.
+4 -4
View File
@@ -1,6 +1,6 @@
# House Plan — полное руководство пользователя
Актуально для **v1.73.0**. Руководство составлено по исходному коду и
Актуально для **v1.78.0-beta.5**. Руководство составлено по исходному коду и
фактическому интерфейсу этой версии. [English version](USER-GUIDE.md).
House Plan добавляет отдельную страницу **House Plan** в боковое меню Home
@@ -525,6 +525,9 @@ desktop: для точного рисования, Resize, модификато
| Вариант | Когда использовать | Поведение |
|---|---|---|
| Изображение | Есть готовый чертёж или фото | SVG, PNG, JPG, WebP; пропорции изображения сохраняются, положение и масштаб можно менять позже |
| Уже загруженный файл | Один план используется повторно или файл уже лежит на сервере | Выбор из серверного списка; используемый пространством файл нельзя удалить |
| Без изображения | План рисуется непосредственно в House Plan | Бумага формируется по контурам комнат; границы и названия удобно включить сразу |
| Импорт этажей HA | В HA уже создан реестр этажей | Мастер создаёт пространства по очереди; любой этаж можно пропустить |
Очень большие растры (примерно от 32 мегапикселей) карточка распознаёт ещё до
загрузки и предлагает безопасную уменьшенную копию — с точными цифрами
@@ -532,9 +535,6 @@ desktop: для точного рисования, Resize, модификато
план не трогается ни при каком исходе. Изображения шире 16384 px по стороне
браузеры показать не могут — их придётся уменьшить на компьютере. SVG
загружается как есть и никогда не преобразуется в растр.
| Уже загруженный файл | Один план используется повторно или файл уже лежит на сервере | Выбор из серверного списка; используемый пространством файл нельзя удалить |
| Без изображения | План рисуется непосредственно в House Plan | Бумага формируется по контурам комнат; границы и названия удобно включить сразу |
| Импорт этажей HA | В HA уже создан реестр этажей | Мастер создаёт пространства по очереди; любой этаж можно пропустить |
Новое пространство с изображением открывается с выключенными границами и
названиями. При выборе варианта **«Без изображения»** оба переключателя сразу
+4 -3
View File
@@ -92,9 +92,10 @@ support. User documentation recommends desktop for creation and maintenance.
Allowed: pan/zoom (wheel, pinch, buttons, double-click/tap on free background
to Fit all), switching spaces, device tap
(info / more-info / toggle per settings), long-press → info card, opening tap →
door/lock info card (with an explicit Unlock/Lock button when a lock is bound —
the only way to operate a lock from the card; plan-icon taps never toggle locks),
(info / more-info / toggle per settings), long-press → info card, lock-badge tap
→ door/lock info card (openings themselves are inert in View; the card carries an
explicit Unlock/Lock button — the only way to operate a lock from the card;
plan-icon taps never toggle locks),
room-card link icon → HA area, clean room click/tap → room fit, room hover
highlight, hover tooltips (name, clean-floor area, temperature, signal).
@@ -6,6 +6,9 @@
- Normative spec: `docs/specs/089-isometric-view-stage1.md`, revision 3
- Activation superseded by #448: the renderer remains authoritative, but its
historical per-feature URL/storage lifetime is replaced by `hp_alpha`.
- Activation superseded by #649: 2.5D is a public View mode behind
`settings.volumetric_view`; `hp_alpha` no longer gates it (`docs/ISOMETRIC.md` ›
Activation). The activation text below is historical.
## Context
@@ -7,6 +7,9 @@
- Predecessor: `docs/adr/089-isometric-stage1-renderer.md`
- Activation superseded by #448: Stage 2 remains hidden, now behind the single
indefinite `hp_alpha` switch instead of the historical `iso` lifetime.
- Activation superseded by #649: 2.5D is a public View mode behind
`settings.volumetric_view`; `hp_alpha` no longer gates it (`docs/ISOMETRIC.md` ›
Activation). The activation text below is historical.
## Context
@@ -8,6 +8,9 @@
- Amended by: #471 (`docs/specs/471-isometric-overlay-white-plates.md`) removes
visible raised plates while retaining their geometry as an invisible safety
footprint.
- Activation superseded by #649: 2.5D is a public View mode behind
`settings.volumetric_view`; `hp_alpha` no longer gates it (`docs/ISOMETRIC.md` ›
Activation). The activation text below is historical.
## Context
+143
View File
@@ -0,0 +1,143 @@
# CODE-REVIEW-667-r1
Issue: #667 · Заход: r1 · Материал: `2fe20a095b1c565134cb9983eb0ed27c9b3d351c`
(единственный коммит `781902b3..HEAD`, ветка `issue/667-docs-drift`)
## Скоуп
Инфраструктурный трек, только документация: 23 файла, ни одной строки в
`src/**`, `custom_components/**`, `test/**`, `demo/**`. Задача — свести 15
расхождений документации с кодом/каноном, найденных при сплошном чтении
`docs/` на `dev @ 781902b`. Класс изменений — C (документация). Трейлеры
коммита: `Issue: #667`, `User-Visible: no` — верно: изменения не трогают
поведение продукта, только описание уже существующего (AGENTS.md, «User-Visible:
no для… документации, которая не меняет продукт»).
Job из `docs/SCOPE.md`: задача не строит фичу, а обслуживает точность входных
документов для J4/J6 (README и руководство описывают шаги, которых уже нет)
и для самого процесса (актуальность STATUS/CONTRIBUTING/AGENTS для
следующего автора/ревьюера).
## Как проверялось
Ревью — не первый раунд по объёму, а полный разбор всех 15 пунктов, потому
что предмет не код с AC, а фактическая точность документации: каждое
утверждение автора проверено чтением текущего дерева и, где применимо,
исполнением инструмента, а не доверием к самоотчёту.
По каждому из 15 пунктов из тела issue — сверка "было / стало / факт в
коде":
| № | Расхождение | Правка в диффе | Сверено с |
|---|---|---|---|
| 1 | Бюджет initial View назван числом (256000 Б) в прозе | `AGENTS.md:409`, `docs/DEVELOPMENT.md:344` теперь ссылаются на `INITIAL_VIEW_GZIP_BUDGET` без цифры | `scripts/bundle-budget.mjs:44` — `export const INITIAL_VIEW_GZIP_BUDGET = 301_066` (прочитано) |
| 2 | CONTRIBUTING: бандл коммитить вручную; Python ≥3.13; релиз — 4 файла + тег | Три абзаца переписаны: `bundle:clean`/`Release:`-трейлер, `.python-version`, `release-contract`/`release:prerelease`/`release.yml` | `.python-version` = `3.14` (прочитано); `.githooks/commit-msg` → `validate-commit-provenance.mjs` → `bundle-policy.mjs` (`BUNDLE_RELEASE_ONLY_ERROR`, коммит с путём бандла без `Release:` отклоняется) — исполнено чтением всей цепочки; `scripts/release-contract.mjs`, `scripts/wsl-setup.sh` существуют |
| 3 | testing-notes называют регистратором мутантов `mutation-gate.mjs` | `live-and-integrations.md`, `geometry.md` → `mutation-registry.mjs` | `ls scripts/mutation-registry.mjs` существует; `scripts/mutation-gate.mjs --changed` в `dialogs-and-forms.md:227` и в `ARCHITECTURE.md:2285-2287` оставлен намеренно — это раннер, не реестр (сверено разницей формулировок) |
| 4 | STATUS/ROADMAP держат HACS PR «в очереди» | Обе строки → «merged 2026-08-25» | `docs/STATUS.md` snapshot-таблица (сгенерированная) уже говорит «In the default catalog since 2026-08-25» — согласовано |
| 5 | STATUS «How to resume»/watchlist — старая песочница (git bundle, `ha_jb`, ручной scp) | Секции переписаны на роли/`task-packet`/`gate:small`/HACS-обновление | `scripts/task-packet.mjs` существует; `package.json` → `"gate:small": "node scripts/gate-small.mjs"`; `AGENTS.md:10` заголовок `## Read this first`, `docs/process/AUTHOR.md` существует |
| 6 | SCOPE: «two editors», J4 «image/PDF», presence в known gaps без ссылки на #485 | J4/J6 → три редактора, SVG/PNG/JPG/WebP; known gaps → ссылка на #485; Docs-пункт → ссылка на #668 | `docs/USER-GUIDE.ru.md:1622` заголовок `## 14. Редактор подложки` — третий редактор существует и документирован; `gh issue view 668` — открыт, «Английское руководство… отстаёт» |
| 7 | README/README.ru: «Контур комнаты» — инструмента нет | → «Стены», рисуется цепочка, замыкание открывает диалог | `src/i18n/ru.json:79` `"markup.add": "Стены"`; `src/houseplan-editor-runtime.ts:2474,6316` `_roomDialog = true` при замыкании контура — поведение подтверждено чтением |
| 8 | USER-GUIDE.ru штамп v1.73.0; таблица «Источник плана» разорвана абзацем | Штамп → v1.78.0-beta.5; абзац про растры перенесён после таблицы | `docs/USER-GUIDE.ru.md:523-537` — таблица теперь 4 строки подряд, абзац после неё (прочитано) |
| 9 | UX-MODES: «opening tap → door/lock info card» — противоречит инертности проёмов | → «lock-badge tap → …», проёмы инертны в View | `src/houseplan-editor-runtime.ts:6012` `_opClick`: `if (this.host._mode === 'plan') this._editOpening(o)` — вне Plan клик не открывает диалог, комментарий в коде подтверждает «openings are inert outside Plan mode» |
| 10 | STYLING-HOOKS: space-card «draws no openings and no decor layer» | → рисует `data-hp="opening"` и `data-hp="decor"`/`.dimage`, только векторный декор/мебель отсутствуют | `src/space-render.ts:891` (`data-hp="opening"`), `:647` (`class="dimage" data-hp="decor"`) — прочитано |
| 11 | DEVICE-PRESENTATION: битый якорь `#12-отображение-устройств` | → `#12-визуальные-состояния-устройств` | `docs/USER-GUIDE.ru.md:1328` заголовок `## 12. Визуальные состояния устройств` — якорь резолвится |
| 12 | Пол зума 0.4x в testing-notes | → «1/3 (`MIN_ZOOM`)» | `src/space-geometry.ts:237` `export const MIN_ZOOM = 1 / 3` |
| 13 | ADR 089/122/160 и ISOMETRIC.md называют 2.5D скрытым `hp_alpha`-экспериментом | Добавлена строка «Activation superseded by #649…» в ADR; в ISOMETRIC.md — исторические врезки | `src/types.ts:305` `volumetric_view?: boolean`; `src/logic.ts:1412` читает `settings.volumetric_view === true`; `docs/ISOMETRIC.md:10` заголовок `## Activation` — якорь резолвится |
| 14 | ARCHITECTURE.md раскладка содержит несуществующий `src/data/` | Строки `rules.ts`/`data/house.ts`/`data/backgrounds.ts` убраны, оставлен только `rules.ts` | `ls src/data` → No such file or directory |
| 15 | legacy/README.md называет `docs/superpowers/specs/` «действующими спецификациями» | → «дизайн-документы до процесса…, историческая справка; ТЗ живёт в теле issue (#517)» | Формулировка согласована с `docs/process/REVIEWER.md`/`PROCESS.md` §2.3 («ТЗ живёт в теле issue, `docs/specs/` — архив») |
Дополнительно проверено за рамками таблицы 15 пунктов (не находки, для
полноты картины):
- Оставшиеся упоминания `mutation-gate.mjs` вне трёх указанных в issue файлов
(`docs/ARCHITECTURE.md`, `docs/design/**`, `docs/specs/**`) — это либо
корректные вызовы раннера, либо архивные ТЗ/ADR, которые канон не требует
переписывать задним числом; не в скоупе issue.
- `docs/STATUS.md` › «Workflow» в CONTRIBUTING.md — ссылка на строку таблицы
«Standing state and decisions», а не на markdown-заголовок (в файле нет
`## Workflow`); стиль расходится с соседними `AGENTS.md › Gates` (это
реальные заголовки), но искомое по факту находится — не поднимаю до
находки, чисто стилистическая шероховатость.
## Прогнанные гейты
| Гейт | Результат | Почему так |
|---|---|---|
| Validate на `2fe20a09` | success (https://github.com/Matysh/houseplan-card/actions/runs/36262534130) | дешёвые гейты уже подтверждены на этом SHA, повторно не гонял |
| `node scripts/check-docs.mjs` | `Documentation checks passed (7 files, 12 external links)` — прогнал сам | diff — документация, дешёвый гейт |
| `node scripts/process-gate.mjs --range 781902b3..HEAD` | пройден, 1 warning: `legacy/README.md` вне классов A/B/C/D (`process-gate: диапазон 781902b3..HEAD, коммитов 1`) | сверка трейлеров/классов, дёшево; предупреждение — известное свойство классификатора (`legacy/**` не входит ни в один путь из таблицы классов AGENTS.md), не дефект этой задачи |
| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | «Исполняемого frontend-диффа нет (src/**/*.ts не тронут)… Тронуто файлов: 23» | по инструкции — обязательный вывод для решения по каждой строке; связей нет, `src/**` не тронут → смоки не выбираются |
| `npx tsc --noEmit`, `npm test`, `npm run build`, `bundle-policy --verify`, `golden:verify`, `pytest tests_backend`, `invariants`, performance | не прогонял | diff не трогает `src/**`, `custom_components/**/*.py`, геометрию, рендер, фикстуры; Validate на этом SHA уже зелёный и покрывает эти гейты собственным прогоном |
Проверка исполнением ключевых утверждений (не только чтением кода, но и
запуском): `.githooks/commit-msg` → `bundle-policy.mjs` — прочитан текст
правила и подтверждено, что путь в `dist/**`/`custom_components/houseplan/frontend/**`
без трейлера `Release:` отклоняется (`BUNDLE_RELEASE_ONLY_ERROR`); это не
исполнение самого хука на реальном коммите, а чтение логики, которую он
реализует — записываю как «проверено чтением, не исполнением».
## AC / защитные требования
Задача не имеет отдельного раздела ТЗ с AC в issue — она перечисляет 15
конкретных расхождений и просит их устранить; «доказательство» каждого
пункта — не автотест и не защитный гард, а факт: текст документа теперь
соответствует коду/канону. Таблица выше — это и есть доказательство по
каждому пункту (столбец «Сверено с»). Формат «AC · чем доказан · чем
краснеет» неприменим: ни один из 15 пунктов не является защитным
поведением (валидацией/гардом/лимитом) — это фактическая правка текста,
верифицируемая только чтением дерева, что и сделано.
## Находки
Нет. Все 15 пунктов устранены и проверены против фактического состояния
кода/конфигурации; побочных регрессий или новых расхождений в изменённых
файлах не найдено.
## Что проверено и корректно
- Все 15 строк таблицы выше — текст документа после правки совпадает с
реальным состоянием кода/скриптов/файловой структуры на `HEAD`.
- Трейлеры коммита (`Issue: #667`, `User-Visible: no`) и класс изменения
(C — документация) верны.
- `check-docs.mjs` и `process-gate.mjs --range` зелёные (один ожидаемый
warning вне скоупа задачи).
- `smoke-select.mjs` подтверждает: frontend-диффа нет, смоки не выбираются
по объективной причине, а не пропущены.
- EN-паритет руководства (п. 8 issue) сознательно вынесен в отдельный,
уже заведённый issue #668 — не сокрытие, а корректное разделение скоупа.
- ADR не переписаны ретроспективно, а дополнены строкой поверх — сохранена
история решений, что соответствует духу канона (не редактировать принятые
решения задним числом).
## Чего не проверял
- Полные `npx tsc --noEmit`, `npm test`, `npm run build`,
`bundle-policy --verify` (со сверкой копий), `golden:verify`,
`pytest tests_backend`, инварианты модели, performance — не запускал:
diff не трогает `src/**`/`custom_components/**/*.py`/геометрию/рендер/
фикстуры, и зелёный Validate на этом же SHA уже покрывает их.
- Не проверял оставшиеся ~40+ вхождений `mutation-gate.mjs` в архивных
`docs/specs/**` и `docs/design/**` — они вне списка issue и вне канона
«переписывать архив»; не мой предмет ревью.
- Не проверял английский `docs/USER-GUIDE.md` построчно — его отставание
явно признано и вынесено в #668, эта задача его не трогает.
- Не запускал `process-gate.mjs --issues` (нужен `gh`, автор тоже пометил
«не запускался» — это ограничение окружения, а не сокрытие; сам факт
указан в issue честно).
## Вердикт
Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 0 → в задаче
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/667-docs-drift`, коммит `2fe20a095b1c` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `63267430f28f9450cd99c81949bacf79a539b939`
```
git log --all --format='%H %T' | grep 63267430f28f
```
- Тело issue: `c9320c593f7f0b1e5791eba19dfeaac03640732797f1a886a2bce106d7066596`
- Вердикт конвейера: `green` · High 0
+2 -1
View File
@@ -1,9 +1,10 @@
# Индекс ревью
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1088, issue: 386. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1089, issue: 387. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы |
|---|---|---|---|---:|---:|---|---|
| #667 | [CODE-REVIEW-667-r1.md](CODE-REVIEW-667-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #666 | [CODE-REVIEW-666-r1.md](CODE-REVIEW-666-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #665 | [SPEC-REVIEW-665-r1.md](SPEC-REVIEW-665-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | заявленная правка docs/ISOMETRIC.md | `docs/ISOMETRIC.md` `docs/adr/160-isometric-stage3-overlays.md` `check-docs.mjs` `ISOMETRIC.md` |
| #665 | [CODE-REVIEW-665-r1.md](CODE-REVIEW-665-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | golden-влияние диффа занижено в отчёте автора вдвое-без-остатка: 0 заявлено, 8 подтверж…; , снято без возврата — расположение строки в docs/ISOMETRIC.md | `golden-report.json` `demo/golden/matrix.mjs` `demo/golden/harness.mjs` `AGENTS.md` `docs/ISOMETRIC.md` `src/iso-tiles.ts` `src/styles/iso-tiles.styles.ts` `src/styles/plan.styles.ts` |
+1 -1
View File
@@ -449,7 +449,7 @@
saved plan and hit Save before the thumbnail loads — the stored aspect is
the real one, never the previous file's [auto: smoke_audit_1490]
- [ ] Zoom goes below the fit (v1.50.0): minus past 100% floats the plan
centred, floor at 0.4x; entering an editor keeps the stage inside the
centred, floor at 1/3 (`MIN_ZOOM`, `src/space-geometry.ts`); entering an editor keeps the stage inside the
viewport [auto: smoke_zoom_out]
- [ ] Migration crash recovery (v1.50.0, HP-1490-01): kill HA between the two
store writes of the square migration — the next start finishes the layout
+3 -3
View File
@@ -28,7 +28,7 @@
reserved/colliding deterministic IDs receive stable `-2`, `-3` suffixes.
- [ ] The three structural writer families — interactive commit, Undo/Redo
restore and Optimize — are enumerated by the source guard and each has an
independent bypass mutant in `scripts/mutation-gate.mjs`. A rejected
independent bypass mutant in `scripts/mutation-registry.mjs`. A rejected
migration changes neither config, Undo history nor revision.
- [ ] Full/space imports cover v7→v7 (no upgrade), v7→v8 and v8→v8; copy/merge
remaps every ID and reference together. A byte-equivalent legacy-client
@@ -90,7 +90,7 @@
- [ ] `test/align-grid.test.mjs` proves Optimize leaves complete furniture/image
transforms byte-equivalent while an ordinary decor rectangle remains
grid-bound.
- [ ] The `writer-*` mutations in `scripts/mutation-gate.mjs` remove one finish
- [ ] The `writer-*` mutations in `scripts/mutation-registry.mjs` remove one finish
owner, pre-adoption safety, history normalization, direct/vacuum reference
rewrite, free-transform exclusion, terminal-click separation, seed merge
and seed reconciliation; each named witness must turn red.
@@ -254,7 +254,7 @@
неприменимых ключей, Cancel не меняет config. [auto: open-passage-contract, smoke_open_passage]
- [ ] Full/space import отвергает forged binding до preview, а старое битое
значение можно прочитать и очистить. [auto: test_validation, test_ha_import_export]
- [ ] Пять passage-мутантов из `scripts/mutation-gate.mjs` пойманы своими
- [ ] Пять passage-мутантов из `scripts/mutation-registry.mjs` пойманы своими
guards до передачи в review. [auto: mutation-gate]
## Independent-wall openings and structural axes (#132, #185)
+2 -2
View File
@@ -38,7 +38,7 @@
[auto: `demo/smoke_pdf_export.mjs`].
- [ ] Каждый поведенческий барьер выше защищён соответствующим мутантом, а
обновлённый PDF golden принят только после визуальной проверки Linux CI
[mutation: `scripts/mutation-gate.mjs`; golden: `demo/golden/`].
[mutation: `scripts/mutation-registry.mjs`; golden: `demo/golden/`].
## Многоэтажный робот: карты и пространства (#162)
@@ -72,7 +72,7 @@
`vacuum-run-forgets-its-route`, `vacuum-retargeted-route-keeps-its-old-trails`,
`vacuum-route-validation-accepts-a-dead-space` и
`space-delete-keeps-foreign-vacuum-routes`
[mutation: `scripts/mutation-gate.mjs`].
[mutation: `scripts/mutation-registry.mjs`].
- [ ] Продакшен-бандл показывает робота на этаже активной карты, а на этаже дока
не показывает; предупреждение у дока появляется на движущемся роботе с
несопоставленной картой; донастройка предложения с высоким residual
+1 -1
View File
@@ -10,7 +10,7 @@
| `docs/PRODUCT-2026-07-05.md` | Старая продуктовая оценка с устаревшей таблицей рынка |
| `docs/PRODUCT-IMPROVEMENT-PLAN.ru.md` | Последний снимок локального backlog; все актуальные пункты перенесены в GitHub Issues + Project v2 9 августа 2026 года |
| `docs/SUN-CONTRAST.md` | Отклонённая модель солнечного контраста; реализована только описанная в актуальном `docs/SUN.md` кромка |
| `docs/implementation-plans/` | Завершённые пошаговые планы реализации; действующие спецификации остаются в `docs/superpowers/specs/` |
| `docs/implementation-plans/` | Завершённые пошаговые планы реализации. `docs/superpowers/specs/` — дизайн-документы до процесса (08-05…08-10), историческая справка: действующее ТЗ живёт в теле issue (#517), `docs/specs/` — архив |
| `demo/dbg_click.mjs` | Одноразовая диагностика старой проблемы клика |
| `demo/repro_issue3.mjs` | Репродуктор уже закрытой ошибки |