CODE-REVIEW-295-r1, both Medium findings:
M1 — _preflightDiagnostics hashed this._serverCfg, the saved config a space
export would reproduce anyway. The hash now comes from the candidate the
preflight actually judged: the report path passes r.config / d.config and the
copy button reads the dialog's own candidate. The smoke no longer masks the
difference — its dialog carries a candidate whose geometry differs from the
saved config, and swapping the two must change the reported hash.
M2 — the inline clipboard fallback survived dialog close and reopen, so a
later refusal could hand the previous refusal's JSON to a bug report. The
field now dies with its dialog: reset on open (_previewAlignDialog) and on
every close path (escape, mode reset, successful apply, hp-close, cancel).
Both regressions are pinned by execution: reverting either fix turns the
extended smoke red (fingerprintTracksCandidate / fallbackClearedOnClose),
and two new gate mutants keep it that way.
Issue: #295
User-Visible: no
Диалог «Оптимизировать» при отказе перечисляет причину по каждому
пространству (7 значений OptimizeGeometryFailureReason получили RU/EN
строки), даёт «Скопировать диагностику» — JSON-блок с origin: runtime,
версией карточки, отпечатками и классами исключений (граница приватности
checkOptimizeGeometry; privacy-тесты дополнены позитивной проверкой) — и
пишет одну структурированную запись в dev-лог (дедупликация по fingerprint).
При недоступном clipboard блок раскрывается прямо в диалоге.
Совет «обновите House Plan» больше не безусловный: websocket
houseplan/config/get теперь возвращает integration_version (бэкенд-тест),
и подсказка показывается только при реальном расхождении с версией карточки;
старый бэкенд без поля — подсказки нет.
Три новых мутанта (потеря причины в диалоге, блок без reason, отключённый
dev-лог) — краснота каждого проверена исполнением; смок
smoke_preflight_diagnostics на dev падает.
Issue: #295
User-Visible: yes