fix: a cold View survives a telemetry-bearing vacuum (#358)

Systematic audit after #357 ("can there be more bugs with this root
cause?"): _vacMapId was the one remaining hard stub reachable from the
eager View path. It runs inside willUpdate for every vacuum whose
integration reports live telemetry (Tasshack, XCME, Valetudo), so on a
cold tab the #337 stub threw there and the exception took the whole Lit
update cycle with it — the card froze on its very first frame. The demo
mower has no position attributes, telemetry resolved to null, and every
existing smoke (warm and cold) sailed past the branch.

The card now owns the implementation (both dependencies — _vacEntity and
vacMapIdWithFallback — were already eager); the editor runtime delegates
back to the host. The HP-1541-01 invariant (selected_map: 0 is a real map
id, nullish not truthy) moves verbatim and is pinned by the new smoke.

Hardened alongside (audit Lows): _decorShapeDown gets the same
cold-tab guard its twin _decorShapeDbl received in #337 — decor shapes
render in View and CSS pointer-events alone must not be what prevents a
throw; the _vacCalConfirm dialog renders behind the same _editorRuntime
gate as every other editor dialog instead of relying on the implicit
"only the runtime ever sets it".

smoke_cold_view_vacuum: cold tab, vacuum with vacuum_position and
selected_map: 0 — the card commits three successive telemetry frames
(willUpdate alive, not merely the first paint), map id resolves to '0',
no editor chunk requested, a decor pointerdown is a quiet no-op. A
registry mutant restores the delegation and is killed by that smoke.

Issue: #358
User-Visible: yes
This commit is contained in:
Codex
2026-08-28 21:49:50 +03:00
parent 5a662d829d
commit bb3c1fd12f
25 changed files with 522 additions and 364 deletions
+14
View File
@@ -680,6 +680,20 @@ const MUTANT_DEFINITIONS = [
replace: ' this._languageFailureUnsub = undefined;',
}],
},
{
id: 'cold-view-vacuum-mapid-delegated',
guard: 'node demo/smoke_cold_view_vacuum.mjs',
because: 'map-id resolution runs inside willUpdate for every vacuum with telemetry — the '
+ '#337 stub threw there on a cold tab and froze the whole Lit update cycle (#358); the '
+ 'demo mower has no position attributes, so only this telemetry-bearing cold smoke sees it',
patches: [{
file: 'src/houseplan-card.ts',
find: ' const ve = this._vacEntity(d);\n'
+ ' const sel = ve ? planHass?.states?.[ve]?.attributes?.selected_map : null;\n'
+ ' return vacMapIdWithFallback(tele.mapId, sel);',
replace: " return this._editorRuntimeOrThrow()._vacMapId(d, tele, planHass);",
}],
},
{
id: 'cold-view-toggle-delegated-to-runtime',
guard: 'node demo/smoke_cold_view_toggle.mjs',
+8
View File
@@ -44,6 +44,14 @@ export const SMOKE_LINKS = [
+ 'requests and four root render gates: neutral cold frame, atomic German commit, page-cache '
+ 'reuse and the bounded retry-to-English path cannot be proven from pure registry tests (#348)',
},
{
symbols: ['vacMapIdWithFallback', 'vacMapIdFromAttrs', 'readVacTelemetry'],
smokes: ['smoke_cold_view_vacuum.mjs'],
because: 'the telemetry-bearing cold scenario proves the vacuum render path (willUpdate '
+ 'snapshot, map-id fallback with selected_map: 0, live position frames) survives without '
+ 'the lazy editor runtime — the demo mower has no position attributes, so every other '
+ 'smoke skips this branch (#358)',
},
{
symbols: [
'resolveToggleIntent', 'toggleOperation', 'projectedTapAction',