Files
houseplan-card/legacy/specs/280-optimize-rehost-validation.md
Claudeandclaude[bot] df46fd1c3e docs(hygiene): ТЗ выпущенных задач без живых ссылок — в legacy/specs (#682)
Волна 5 эпика #674, перенос ТЗ (класс C). Из 240 файлов `docs/specs/` в
`legacy/specs/` уехали 219: на них не ссылается ни один живой файл (код,
тесты, скрипты, workflow, документы вне архива и ревью). Остались 21 ТЗ —
на которые ссылаются код, ADR, ISOMETRIC, SUN, RADAR, LIGHT (`docs/specs/067`),
DECOR-EDITOR, support-relay, и те, на которые ссылаются они сами; README
каталога объясняет, где искать остальное. Открытых issue с файлом ТЗ среди
перенесённых нет. Относительные ссылки перенесённых файлов переписаны
(`../X` → `../../docs/X`, соседние оставшиеся ТЗ → `../../docs/specs/…`) —
все 26 резолвятся. Попутно: битая ссылка в
`089-isometric-view-stage1.md:8` на удалённый `089-isometric-view.md` —
теперь команда `git show` по истории. Строка в `legacy/README.md`.

Issue: #682
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 22:10:46 +00:00

103 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Issue #280 — backend принимает доказанный Optimize rehost
- Дата: 2026-08-24
- Тип: regression bug · приоритет P1
- Issue: [#280](https://github.com/Matysh/houseplan-card/issues/280)
- Ветка: `issue/280-optimize-rehost-backend`
- Статус ТЗ: одобрено self-review по решению владельца
Связанные контракты: #132, #186, #199, #224 и #276;
`docs/CONFIG-COMPATIBILITY.md`, `docs/WALL-THICKNESS.md`, `docs/TESTING.md`.
## 1. Проблема
#276 намеренно удаляет exact coincident partition и материализует её hosted
opening как ordinary room-wall opening. Backend при любом surviving opening
безусловно запрещает `host != null → host == null`, поэтому preview beta.8
успешен, а единственный Optimize write отклоняется как `host removed`.
Frontend mock не является доказательством server acceptance. Исправление
должно сохранить общий запрет и дать исключение только специальному WS Optimize,
если backend самостоятельно доказывает тот же безопасный переход.
## 2. Пользовательский результат
Apply для exact reconciliation #276 атомарно сохраняет candidate. Дверь/окно/
ворота не двигаются, partition исчезает, reload видит обычный room-wall
opening, а одноразовый Undo возвращает прежний partition и explicit host.
Обычный config/set и crafted Optimize без полного доказательства остаются
fail-closed с `invalid_partition_opening_host`.
## 3. Backend-контракт доказательства
`validate_partition_opening_hosts()` получает keyword-only capability,
включаемую только `ws_plan_optimize`. Capability не является доверием клиенту:
каждый снятый host должен пройти все проверки.
Для одного surviving opening backend требует:
1. предыдущий host имеет `kind: partition`, а предыдущий partition существует;
2. partition с этим id отсутствует в candidate;
3. его полный отрезок является однозначной solid shared boundary ровно двух
разных candidate rooms: оба endpoints лежат на collinear room edges;
4. candidate physical wall envelope на всём отрезке не уже удалённого тела:
covering exact wall record имеет достаточный `cm`, либо действующий default
`15 cm` уже достаточен;
5. candidate `x/y` равны точке `a + t × (b-a)`, angle совпадает с осью modulo
180°, length полностью помещается в отрезок;
6. все поля, кроме `host` и материализуемых `x/y/angle`, byte-semantically
равны предыдущему opening;
7. новый slot не перекрывает другой candidate opening на той же физической
оси; every removed host в batch проходит проверку.
Coordinate tolerance — `1e-8` normalized units для девятизначной storage
канонизации. Он не используется для near/partial wall matching: collinearity и
coverage всё равно должны доказать полный исходный segment.
## 4. Scope
Входит:
- pure backend delta-proof и узкий Optimize-only call site;
- exact shared fixture, ordinary-write и crafted-candidate negative matrix;
- HA websocket success/atomic failure/Undo regression для Linux CI;
- cross-stack fixture: результат настоящего `optimizePlans()` равен candidate,
который принимает Python validator;
- backend/config compatibility docs и оба changelog.
Не входит: общий отказ от host guard, доверие frontend counters, nearest-wall
эвристика, изменение schema/model version или геометрии #276.
## 5. Acceptance criteria
1. Privacy-minimized #276 fixture проходит frontend optimizer и backend
Optimize-validation; второй Optimize — no-op.
2. Тот же host removal при capability=false отклоняется.
3. Отклоняются: partition остался; partial/non-shared/ambiguous wall; более
узкий envelope; сдвиг/поворот/длина/тип/id/связи; overlap; unsafe второй
opening в batch.
4. `ws_plan_optimize` передаёт capability, `config/set` — нет; validation
завершается до первого store write.
5. Linux HA integration доказывает save/reload/Undo и неизменность revisions/
backup при failure.
6. Pure backend, frontend unit, typecheck/build и targeted smoke зелёные.
## 6. Совместимость, security и performance
Schema и stored result уже поддерживаются старыми версиями: ordinary opening
и room wall. Новый capability недоступен из payload и не расширяет права WS.
Proof линейно обходит rooms/walls/openings только при явном Optimize и только
для реально снятых hosts; render и обычные state updates не затрагиваются.
## 7. Self-review ТЗ
- Исключение привязано к server command, но не доверяет его происхождению.
- Доказательство покрывает identity, geometry, envelope и conflicts, а не
только факт удаления partition.
- Позитивный cross-stack fixture закрывает точный разрыв тестов beta.8.
- Негативный ordinary config/set сохраняет прежнюю security/compat guarantee.
Вердикт: **approved**. Внешнее spec-review пропущено по прямому решению
владельца.