The production LANGUAGE_RUNTIME was a handwritten twin of the tested
LanguageRuntime class (germanDictionary/Pending/Failed): equivalent on the
day it was written, invisible to every i18n-runtime test afterwards. The
registry now exports one page-scoped `new LanguageRuntime(LANGUAGE_REGISTRY,
…)` instance — the whole existing suite starts proving the object production
actually runs, and a contract unit (instanceof + source free of the old
field names) keeps the duplicate from returning.
The class gains an optional `loadFailed(code)` hook — fired once when a
dictionary load settles into English fallback — and the registry fans it out
through `subscribeLanguageLoadFailures`. Only the View card subscribes (it
alone owns toast infrastructure): a failed language pack now shows the new
`toast.locale_load_failed` message (en/ru/de) instead of a console-only
warning; space card and both GUI editors keep the console warning as before.
Proofs: contract unit, hook unit, subscription unit; smoke_german_locale
extended — the both-attempts-failed scenario now asserts the visible toast;
two new registry mutants (handwritten-twin returns, toast dropped).
Issue: #354
User-Visible: yes
Network failure of the editor runtime is no longer terminal: the loader
re-arms to idle and the next explicit press starts a fresh cycle, while a
fingerprint mismatch on either attempt stays terminal. The toast now says
what actually helps — retry advice for the network, refresh advice for a
foreign build — via one shared lazyLoadFailureMessage helper (new i18n key
editor.retry_advice in en/ru/de).
The field smoke caught a second, deeper bug on the way: Chromium records a
FAILED module in the page module map permanently, so retrying the same URL
(even the cache-busted one) never touched the network again. Every retry
now carries a per-cycle nonce and becomes a genuinely new module request.
A proxy-cached stale entry no longer kills the card silently: the entry
facade is rewritten at build time from a static re-export into a top-level
`try{await import(...)}catch{...}` — importers keep the happy-path
guarantee (await import(entry) still resolves only after
customElements.define), and the catch defines a fallback element with a
localized "reload the page" panel. Content-hashed chunks are served with
`public, max-age=31536000, immutable`, and verifyBundleTree now fails on
orphan chunks that the manifest does not name.
Proofs: loader units for re-arm/terminality/toast wording + an AST check
that both loaders forward the terminality flag; smoke_entry_stale (en/ru)
against a tree without the main chunk; smoke_lazy_editor_chunk extended —
second press after network failure now really opens the editor; pytest for
the immutable header; orphan-tree unit; five new registry mutants.
TESTING.md budget line updated to the #352 ceiling alongside.
Issue: #353
User-Visible: yes
isDegenerateApexCorner measured the inner-face convergence as
max(h1,h2)/tan(theta/2) — for a 10-degree apex between a 15 cm and a 30 cm
wall that overstates the distance (171.5 cm against the true 128.3/128.9 on
160 cm edges), the corner failed the "inside both edges" test and rendered
as the #329 trident again. Worse, the verdict depended on which neighbouring
edge carried the thicker wall.
The check now intersects the two actual face lines: the meeting point lands
at (hOther + hOwn*cos(theta))/sin(theta) along each edge, degenerate only
when inside both. With equal halves this reduces algebraically to the old
h/tan(theta/2), so equal-thickness verdicts are unchanged by construction —
pinned by the untouched section-4 units and the full golden matrix (136
scenes verified). New units cover both traversal orders of the mixed apex,
the one-point outset tip, the 30-degree ordinary pair and the zero-thickness
guard.
The write path is untouched: P1 forbids new sub-15-degree corners since
issue 329, this is purely how a legacy document renders.
Issue: #339
User-Visible: yes
Accept the complete canonical Linux capture from run 33159459520 after visual
review of View, touch and Device editor surfaces.
Issue: #345
User-Visible: no
The rebase resolved docs/images/screenshots.json to the dev side while the
PNG files stayed from this branch's capture — CI correctly refused the
mismatched pair. One local capture regenerates both halves from the same
run, so hashes and the source fingerprint agree again.
Issue: #330
User-Visible: no
П3 measures the WALL, not the catalogue atom: a short filler segment that
compensates a thickness step (owner's fixture, 5 cm = (30-20)/2) is a legal
continuation of a long same-thickness wall, so the rule walks the maximal
collinear run through the shared nodes before judging the length.
Resize stops at the last allowed position and names the broken rule instead
of the generic "geometry cannot be saved"; the Thickness dialog refuses
through its own toast. Both channels are pinned by demo/smoke_junction_limits
plus three mutants (angle threshold, write barrier, degenerate apex bevel).
Issue: #329
User-Visible: yes
Владелец, осмотрев первые эталоны сета, отменил дневное решение о сохранении
фаски: `junction-y-60-equal50` показывал вырез, `junction-acute30-mixed` —
торчащие углы. По визуальному сравнению трёх вариантов принято: узлы
смыкаются полным mitre, как обычное пересечение стен на чертеже.
Итоговое правило веера (одно на все случаи):
- mitre принимается, когда он В СЕКТОРЕ пары (вперёд по лучам для обычной
пары, назад — для рефлексной: наружный угол между крайними лучами, где и
жил вырез Y-60), в пределах классического `MITRE_LIMIT` и не дальше конца
толстого саппорта (#271);
- рефлекс без валидного mitre замыкается плоской хордой между гранями;
- обычная пара без mitre — локальный бевел: ход по граням ограничен толстым
саппортом, лимитом и двойной толщиной пары, чтобы хорда осталась деталью
угла. Гигантские бевел-«бабочки» и mitre вне сектора — две реальные ошибки
промежуточных версий, обе пойманы на сценах сета до пуша.
Слой `bevelMultiWallBody` сохранён только как АДРЕСНЫЙ латеральный трим для
узлов с вырожденно-коротким толстым саппортом (#271); все прочие узлы — чисто
аддитивные, следы трима на них исчезли. `bevelMultiWallPaper` из бумаги
удалён. Обе записи CHANGELOG приведены к финальному контракту.
Тесты: юниты §302 усилены; площадь фикстуры #197 +0.6 юнита²; мутанты
переякорены, краснота каждого проверена исполнением.
Issue: #302
User-Visible: yes
Вторая половина переработки узлов поверх ядра из прошлого коммита:
- `junctionContractHoles` — объективный инвариант «тело ⊇ полосы ∪ веера в
фасадной границе» как экспортная чистая функция; самопроверка на заведомо
дырявой фикстуре входит в юниты. Первая формулировка детектора из ТЗ
(«окружено кладкой с ≥5 из 8 сторон») уточнена в §8.4 по факту измерения:
она ложно флагует легитимный пол комнаты в острых внутренних углах.
- `junctionNodeBound` — «гладкая» фасадная граница (конверт с обычными углами)
экспортирована: ею клиппуются куски узла и ею же пользуются тесты.
- юниты #302: веера/рефлекс/короткий толстый саппорт/детектор/репро
end-to-end; хелпер тестов старого контракта переведён на strip-safe
семантику по саппортам и фасадной границе.
- смок `smoke_junction_holes`: контрактные пробы считаются в node из той же
фикстуры и проверяются в браузере по реальному `d`-пути карточки.
- сет из 16 golden-сцен стыков крупным планом (звёзды лучей: T/X/Y/острые/
почти коллинеарные/виртуальные/колонна/черновик) + сцена-репро владельца;
билдер сцен и `zoomCenter` в harness. Контракт сцены
`multiwall-junction-bevel-view-dark` инвертирован по решению владельца:
проба в перекрытии полос обязана быть ЗАПОЛНЕНА (strip-safe), а не пустой.
- семь мутантов §14, включая слепоту детектора и невозврат саппортов.
- фикстура #197: площадь кладки выросла на 0.2 юнита² — слайвер вееров вдоль
хорд фаски; константа обновлена с комментарием.
Эталоны новых сцен идут отдельным коммитом с положенными трейлерами.
Issue: #302
User-Visible: yes
Canonical Linux capture from workflow run 32854424829 at exact branch SHA a2b4d32b2d was reviewed as a complete ten-frame set.
Issue: #304
User-Visible: no
Canonical Linux capture from workflow run 32772784765 was visually inspected after integrating #296, #298, and #300. It refreshes the exact combined source fingerprint and all ten accepted frames.
Issue: #300
User-Visible: no
Accepted the complete Linux artifact after visual review. Only the dark and light isometric geometry views change intentionally; 106 passing scenarios keep their prior bytes.
Issue: #260
User-Visible: no
Release: v1.67.0-beta.10
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/32725286757
Accept the complete ten-frame Linux artifact captured from candidate 8d2a050. All five changed frames were reviewed against the committed set; they preserve the intended UI while recording the tapered #272 geometry and beta.6 source fingerprint. Run: https://github.com/Matysh/houseplan-card/actions/runs/32667107212
Issue: #272
User-Visible: no
Accept the complete ten-frame Linux artifact from the exact #272 performance gate-fix source. The content matches the reviewed UI while replacing the non-canonical Windows captures that had entered dev with #274.
Issue: #272
User-Visible: no
Accepted the complete 97-scenario Linux artifact after visual review. The intentional golden changes are limited to the EN/Dark and RU/Light Optimize orphan-cleanup dialogs; all 95 passing raster candidates were restored to their prior bytes and hashes. The canonical docs artifact used the same Chromium and refreshed its source fingerprint; eight frames were identical, while two differed by only 2 and 17 sub-threshold pixels.
Issue: #252
User-Visible: no
Release: v1.67.0-beta.4
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/32623704126
`scripts/check-docs.mjs` держит скриншоты в соответствии с исходниками через
отпечаток `src/**`. Отпечаток был просрочен ещё до этой задачи — проверено
исполнением на чистом dev, — так что перезахват закрывает чужой долг заодно с
изменением, которое отпечаток всё равно бы сдвинуло. Содержательно кадры те
же: меняется только шум рендера.
Issue: #229
User-Visible: no