Commit Graph
659 Commits
Author SHA1 Message Date
Sergey Matyunin 0d91c1e18e fix: make plan visuals grid-scale invariant
Issue: #239
User-Visible: yes
2026-08-22 13:45:26 +03:00
claude[bot] a4e8dd7ba7 docs: review document for #239
Issue: #239
User-Visible: no
2026-08-22 10:03:10 +00:00
Sergey Matyunin e8b3c861b2 docs(spec): add proof matrix for grid scale
Issue: #239
User-Visible: no
2026-08-22 12:59:18 +03:00
claude[bot] da597da274 docs: review document for #239
Issue: #239
User-Visible: no
2026-08-22 09:58:21 +00:00
Sergey Matyunin 4c065f5ec4 docs(spec): define grid-scale visual invariance
Issue: #239
User-Visible: no
2026-08-22 12:49:46 +03:00
claude[bot] 1af0cc1711 docs: review document for #238
Validate / docs (push) Failing after 26s
Validate / provenance (push) Successful in 1m18s
Validate / process-gate (push) Failing after 1m9s
Validate / changes (push) Successful in 1m0s
Validate / reuse (push) Successful in 43s
Validate / hacs (push) Failing after 21s
Validate / hassfest (push) Failing after 18s
Validate / frontend (push) Successful in 7m27s
Validate / backend (push) Failing after 10m17s
Validate / golden (push) Failing after 12m29s
Validate / performance_smoke (push) Failing after 13m26s
Validate / smoke (push) Failing after 40m7s
Issue: #238
User-Visible: no
2026-08-22 09:40:27 +00:00
Sergey Matyunin 18cd0c8b01 docs: refresh rebased screenshot provenance
Issue: #238
User-Visible: no
2026-08-22 12:25:40 +03:00
claude[bot]andSergey Matyunin ace6e62f89 docs: review document for #238
Issue: #238
User-Visible: no
2026-08-22 12:25:05 +03:00
claude[bot]andSergey Matyunin 7c6e631560 docs: review document for #238
Issue: #238
User-Visible: no
2026-08-22 12:25:05 +03:00
Sergey Matyunin cb19b7d52e feat: measure opening preview to inner faces
Issue: #238
User-Visible: yes
2026-08-22 12:24:49 +03:00
claude[bot]andSergey Matyunin 06c7934667 docs: review document for #238
Issue: #238
User-Visible: no
2026-08-22 12:24:49 +03:00
Sergey Matyunin 5582e9a35d docs(spec): define opening inner-distance guides
Issue: #238
User-Visible: no
2026-08-22 12:24:49 +03:00
Matysh 9e71334cb4 docs: refresh documentation screenshots and require check-docs
Issue: #237
User-Visible: no
2026-08-22 11:42:55 +03:00
claude[bot] 6bd197ffd7 docs: review document for #228
Issue: #228
User-Visible: no
2026-08-22 08:14:31 +00:00
claude[bot]andSergey Matyunin 55d5a560ad docs: review document for #228
Issue: #228
User-Visible: no
2026-08-22 10:56:38 +03:00
Sergey Matyunin 691cea074b fix: close plan repair review findings
Issue: #228
User-Visible: yes
2026-08-22 10:56:38 +03:00
claude[bot]andSergey Matyunin 8fc3ec783b docs: review document for #228
Issue: #228
User-Visible: no
2026-08-22 10:56:23 +03:00
Sergey Matyunin 2f968996b1 fix: make plan drawing fail closed
Issue: #228
User-Visible: yes
2026-08-22 10:56:22 +03:00
claude[bot]andSergey Matyunin 9a131cca25 docs: review document for #228
Issue: #228
User-Visible: no
2026-08-22 10:55:08 +03:00
Sergey Matyunin e44b3c97b0 docs: specify plan drawing repairs
Issue: #228
User-Visible: no
2026-08-22 10:55:08 +03:00
claude[bot] 66ffd6fdda docs: review document for #233
Validate / docs (push) Failing after 23s
Validate / provenance (push) Successful in 1m15s
Validate / process-gate (push) Failing after 1m14s
Validate / changes (push) Successful in 1m0s
Validate / hacs (push) Skipped
Validate / hassfest (push) Skipped
Validate / reuse (push) Successful in 47s
Validate / backend (push) Skipped
Validate / frontend (push) Successful in 8m16s
Validate / golden (push) Failing after 13m4s
Validate / performance_smoke (push) Failing after 13m7s
Validate / smoke (push) Failing after 34m13s
Issue: #233
User-Visible: no
2026-08-22 07:22:40 +00:00
claude[bot] bff47f522b docs: review document for #233
Issue: #233
User-Visible: no
2026-08-22 06:57:57 +00:00
Matysh abfaae3e38 feat: measure resize labels between wall faces
Issue: #233
User-Visible: yes
2026-08-22 09:45:15 +03:00
claude[bot] 969847a4c4 docs: review document for #233
Issue: #233
User-Visible: no
2026-08-22 00:26:11 +00:00
Matysh bc8c368db9 docs(spec): keep a passage full length, read thickness atomically
Spec review r1 returned two blocking findings and both were right.

A measured side that is itself a passage would have been shortened by its
neighbouring walls, while insetContour — the very function the area label
already uses — treats that joint as a flat cap and shortens nothing. Length
and area would have diverged again, at a different boundary, which is the
defect this task exists to remove. The zero rule now comes first and returns
the full centreline length for an open side.

The thickness source was wrong as a matter of fact, not of taste: an
existing test shows thicknessCmAt returns 0 for a whole-edge query against a
partially set thickness, so a split-thickness edge would have silently
stopped shortening. Half-depths now come from roomWallProfile, the atomic
profile that innerContourForRoom already uses for the area, so one edge is
resolved by one mechanism.

Two acceptance criteria and two mutation guards added for the closed
findings.

Issue: #233
User-Visible: no
2026-08-22 03:20:06 +03:00
claude[bot] 0312104527 docs: review document for #233
Issue: #233
User-Visible: no
2026-08-22 00:13:35 +00:00
Matysh 77fa698a27 docs(spec): register the #233 spec in the index
Issue: #233
User-Visible: no
2026-08-22 03:00:05 +03:00
Matysh 7b0747888c docs(spec): measure resize labels between wall faces
Issue: #233
User-Visible: no
2026-08-22 02:58:37 +03:00
claude[bot] 0df5db8b1c docs: review document for #234
Validate / docs (push) Failing after 20s
Validate / reuse (push) Successful in 55s
Validate / changes (push) Successful in 1m13s
Validate / provenance (push) Failing after 1m21s
Validate / process-gate (push) Failing after 1m22s
Validate / hacs (push) Failing after 15s
Validate / hassfest (push) Failing after 11s
Validate / frontend (push) Successful in 3m23s
Validate / backend (push) Failing after 4m25s
Validate / golden (push) Failing after 9m54s
Validate / performance_smoke (push) Failing after 11m9s
Validate / smoke (push) Failing after 20m20s
Issue: #234
User-Visible: no
2026-08-21 16:56:20 +00:00
Sergey Matyunin c8e9597228 fix: resolve chain segment thickness in one place
Issue: #234
User-Visible: yes
2026-08-21 19:42:42 +03:00
claude[bot]andSergey Matyunin 67505f8343 docs: review document for #234
Issue: #234
User-Visible: no
2026-08-21 19:41:37 +03:00
MatyshandSergey Matyunin b2024c6626 docs(spec): state that i18n is untouched, name the zero case
The spec review found the i18n section missing outright — the analysis
comment claimed it was untouched, the document itself said nothing, and a
DoR section cannot be inferred from a comment. It now says so explicitly,
and adds that the absence of i18n files from the diff is part of the
contract rather than an accident.

The waived Low is closed too: the old wallChainSegments treated a recorded
zero as valid while the new contract requires strictly positive values, so
zero is now named in the AC1 examples instead of being derivable from the
prose.

Issue: #234
User-Visible: no
2026-08-21 19:41:37 +03:00
claude[bot]andSergey Matyunin b7a9cc4edf docs: review document for #234
Issue: #234
User-Visible: no
2026-08-21 19:41:37 +03:00
MatyshandSergey Matyunin f4098fcf09 docs(spec): register the #234 spec in the index
Issue: #234
User-Visible: no
2026-08-21 19:41:37 +03:00
MatyshandSergey Matyunin 05b2c74442 docs(spec): define one thickness resolver for a wall chain
Issue: #234
User-Visible: no
2026-08-21 19:41:37 +03:00
claude[bot] 1e2eba95b1 docs: review document for #230
Issue: #230
User-Visible: no
2026-08-21 14:07:33 +00:00
claude[bot] 579d6e5f4e docs: review document for #230
Issue: #230
User-Visible: no
2026-08-21 12:33:54 +00:00
CodexandCodex edf1cca8e3 feat: hatch density is a distance, not a count of units (#230)
Одна и та же стена 15 см выглядела на планах с разным `cell_cm` по-разному:
шаг паттерна был константой в юнитах, а толщина стены переводится в юниты через
`cell_cm`, — значит число полос было пропорционально `1/cell_cm`. Разброс между
крайними масштабами достигал 25 раз, а при `cell_cm ≥ 10` в стену не попадало
и одной полосы: штриховка вырождалась в случайные штрихи или исчезала.

Шаг стал физической величиной: `wallHatchStepUnits(cellCm)` возвращает
`8 × (5 / cell_cm)` — это 9.6 см плана при любом масштабе сетки и ровно
исторические 8 юнитов при эталонном `cell_cm: 5`, так что старые планы не
двигаются. Толщина штриха следует за шагом, поэтому соотношение «штрих к
просвету» тоже перестало зависеть от масштаба.

Формула из описания issue (`cell_cm / 5`) не годилась: она увеличивает шаг там,
где стена и без того тонкая в юнитах, и разброс не исчезает, а растёт — 39
полос против 0.06 на краях диапазона. Множитель обратный; на эту ошибку
поставлен отдельный мутант `hatch-step-inverted`.

Зумовая компенсация `1/zoom` убрана по решению владельца (§4.2 ТЗ): стена,
которая меняет штриховку при зуме, — это тот же дефект, только по другой оси.
От каши на дальнем конце зума защищает второй порог `wallHatchNeedsSolid`
рядом с существующим `wallBodyNeedsSolid`; шаг клампится в [0.5, 80] юнитов,
чтобы патологический `cell_cm` не выродил паттерн.

Статический рендерер (`space-render.ts`) нёс собственную константу 8 и вообще
не знал про зум — то есть уже сегодня расходился с картой при любом зуме,
кроме единицы. Теперь оба читают шаг из одной функции; смок проверяет, что они
согласны между собой, а не только каждый сам с собой.

Два golden-эталона переснято осознанно (`golden:accept -- --reviewed`):
`large-house-zoom-040-dark` (шаг был 20 юнитов, стал 8) и
`large-house-zoom-250-dark` (был 3.2, стал 8). Расхождение осмотрено: меняется
только плотность штриховки тел стен, колонн и перегородок, геометрия и цвета
идентичны. Остальные 80 сцен не тронуты — `accept` переснимает весь набор, и
пять сцен, разошедшихся на шуме рендера, возвращены к прежним байтам вместе с
их хэшами в индексе.

Issue: #230
User-Visible: yes
2026-08-21 15:12:08 +03:00
claude[bot] 115a7d4ccd docs: review document for #230
Issue: #230
User-Visible: no
2026-08-21 11:54:24 +00:00
CodexandCodex 44a35fde0f docs: two golden scenes DO move, and the static renderer needs its own AC (#230 r1)
Issue: #230
User-Visible: no
2026-08-21 14:47:49 +03:00
claude[bot] 6872dc420d docs: review document for #230
Issue: #230
User-Visible: no
2026-08-21 11:46:42 +00:00
Codex 2396044bae docs: spec for #230 — hatch density normalised to plan centimetres
Issue: #230
User-Visible: no
2026-08-21 14:35:29 +03:00
claude[bot] 619516806f docs: review document for #229
Validate / docs (push) Failing after 24s
Validate / changes (push) Successful in 1m10s
Validate / process-gate (push) Failing after 1m14s
Validate / provenance (push) Successful in 1m16s
Validate / reuse (push) Successful in 52s
Validate / hassfest (push) Failing after 33s
Validate / hacs (push) Failing after 47s
Validate / frontend (push) Successful in 7m12s
Validate / backend (push) Failing after 16m13s
Validate / golden (push) Failing after 11m40s
Validate / performance_smoke (push) Failing after 14m46s
Validate / smoke (push) Failing after 32m43s
Issue: #229
User-Visible: no
2026-08-21 10:31:02 +00:00
CodexandCodex fab0c38ca9 refactor: one function owns the junction geometry of a space (#229 r2 M1)
Дефект High-1 был одинаковым в двух местах — и в живом рисовании, и в
«Оптимизировать планы», — потому что каждый вызывающий собирал геометрию
примыканий сам. Ревью r2 справедливо заметило, что и защита получилась
однобокой: юнит и мутант сторожили только оптимизатор, а путь карты — тот, где
дефект и был виден пользователю, — не сторожил никто. Заплатка в виде второго
мутанта-близнеца оставила бы причину на месте: два списка координат, которые
обязаны совпадать, но ничем не связаны.

Поэтому геометрия переехала в `spaceMergeGeometry(space, { excludeDraftId })`:
один источник комнат, колонн и концов черновиков, одни координаты, одно место,
где можно ошибиться. Оба вызывающих теперь строчка вызова.

Покрытие идёт за причиной, а не за симптомом: три юнита в
`test/wall-merge.test.mjs` проверяют масштаб полигонов (включая комнаты в форме
x/y/w/h и комнату без геометрии), исключение активного черновика и сам T-стык к
середине стороны комнаты. Мутанты `partition-merge-rescales-rooms` и
`chain-merge-sees-own-draft` перенацелены на общий модуль и теперь краснеют для
обоих путей сразу: 2 и 1 падение, проверено применением патча.

Сценарий с комнатой в смоке пробовал — не взлетел: рисование в комнату
поднимает `_offerWallFaces`, и цепочка не завершается штатно. Ломать смок под
тест не стал, юниты общего модуля покрывают оба пути честнее.

Issue: #229
User-Visible: no
2026-08-21 13:25:16 +03:00
claude[bot] fe2fcef735 docs: review document for #229
Issue: #229
User-Visible: no
2026-08-21 10:20:16 +00:00
CodexandCodex ed13b4a5ca fix: a room side and a live draft, seen in the right coordinates (#229 r1 H1,H2)
**High-1.** Комнаты хранятся в тех же координатах, что и перегородки:
`roomPoly` отдаёт сырой полигон конфига. Обе обвязки делили его на `NORM_W`
ещё раз, комната уезжала в область ~0.0001, и `junctionAt` не находил ни
одного совпадения. Узел на T-стыке к середине стены комнаты — тот самый
случай, ради которого ТЗ прошло два раунда ревью, — молча исчезал.
Воспроизведено вызовом `optimizePlans`: `partitionsMerged === 1` там, где
ожидается 0.

**High-2.** Завершаемая цепочка к моменту слияния ещё лежит в `room_drafts`:
каждый клик персистит её через `_persistActiveDraftSegment`, а удаляется
черновик строкой ниже вызова слияния. Собственные концы цепочки считались
чужим примыканием, и стык с существующей стеной не срастался. Активный
черновик теперь исключается — ровно так же, как это делает
`plan-snap-overlay` (`activeDraftId`).

Дыры в тестах, которые это пропустили, закрыты по существу, а не заплаткой:

- `demo/smoke_wall_chain_merge.mjs` рисует продолжение реальными кликами через
  `_markupClick`, а не присваиванием `_path`, — то есть исполняет тот путь, на
  котором дефект и жил. Клики задаются в координатах плана и переводятся через
  живой view box, иначе смок целится мимо только что нарисованной стены.
- `test/plan-optimizer.test.mjs` получил комнату с примыканием к середине
  стороны: юниты модуля этого не ловили, потому что передают полигон уже в
  согласованном масштабе, минуя обвязку.
- Мутанты `partition-merge-rescales-rooms` и `chain-merge-sees-own-draft`
  сторожат оба места: проверены применением патча, 1 и 2 падения.

Issue: #229
User-Visible: no
2026-08-21 13:04:20 +03:00
claude[bot] 10d5b5a288 docs: review document for #229
Issue: #229
User-Visible: no
2026-08-21 09:57:36 +00:00
Codex 50a00e41a1 docs: refresh documentation screenshots (#229)
`scripts/check-docs.mjs` держит скриншоты в соответствии с исходниками через
отпечаток `src/**`. Отпечаток был просрочен ещё до этой задачи — проверено
исполнением на чистом dev, — так что перезахват закрывает чужой долг заодно с
изменением, которое отпечаток всё равно бы сдвинуло. Содержательно кадры те
же: меняется только шум рендера.

Issue: #229
User-Visible: no
2026-08-21 12:40:41 +03:00
Codex e6be43b90f feat: a straight wall is one record, not a row of seams (#229)
Рисование прямой стены в несколько кликов оставляло по записи на каждый
отрезок. Швы невидимы, пока их не тронешь: выделение хватает кусок,
перетаскивание ломает стену пополам, толщина задаётся пофрагментно. У стен
комнат этого давно нет — `normalizeWallIntervals` схлопывает каждый сплошной
участок одной толщины. Независимые перегородки жили по другому правилу.

Новый чистый модуль `src/wall-merge.ts` даёт им то же правило:

- `mergeCollinearPartitions` сращивает соседей одинаковой толщины и
  направления до неподвижной точки, но только там, где узел никому не нужен.
  Узел остаётся, если в него приходит третья перегородка, стена комнаты
  (стороной, а не только вершиной), колонна или конец сохранённого черновика.
- Направление выжившей записи канонизируется лексикографически: иначе одна и
  та же физическая стена выходила то a→b, то b→a в зависимости от порядка
  входа, и каждый host.t вдоль неё переворачивался вместе с ней.
- `applyOpeningMoves` переносит проёмы на выжившую запись: и авторитетный
  `host`, и legacy-проекцию `x/y/angle`, которую рисует старый читатель
  конфига (docs/CONFIG-COMPATIBILITY.md, #132). Проекция здесь не кэш —
  канонизация направления разворачивает угол на 180°.

Рисование сращивает только свою цепочку и то, чего она коснулась (§8.6 ТЗ):
молча править чужие швы в стороне оно не вправе — для этого есть
«Оптимизировать планы» с предпросмотром, отчётом и отменой. Оптимизация
проходит по всему пространству без seed-ограничения и отдельной строкой
сообщает, сколько записей исчезло.

Issue: #229
User-Visible: yes
2026-08-21 12:40:34 +03:00
claude[bot] 483c29cc39 docs: review document for #229
Issue: #229
User-Visible: no
2026-08-21 09:01:53 +00:00