From d8949cfffc067918b32149297a72790e629cc0b8 Mon Sep 17 00:00:00 2001 From: Matysh Date: Sun, 4 Oct 2026 07:17:00 +0300 Subject: [PATCH] test(light): preserve empty render contract and guard late static imports Follow the render-local barrier wrapper without weakening empty-space or confirmation assertions. Register the cold-import connection guard mutation. Issue: #789 User-Visible: no --- docs/testing-notes/mutation-browser-guards.md | 5 +++-- scripts/mutation-registry.mjs | 11 +++++++++++ test/optional-space-model-contract.test.mjs | 6 +++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/testing-notes/mutation-browser-guards.md b/docs/testing-notes/mutation-browser-guards.md index e32cef7a..f228a329 100644 --- a/docs/testing-notes/mutation-browser-guards.md +++ b/docs/testing-notes/mutation-browser-guards.md @@ -17,8 +17,8 @@ to prove that the Node witness actually kills it. | Paint, cascade and layer composition | 37 | The invariant depends on computed CSS, SVG paint, clipping, stacking or pixels produced by Chromium. | | Pointer geometry and trusted interaction | 47 | The invariant depends on hit testing, pointer capture, touch/keyboard dispatch or live DOM geometry. | | Responsive DOM layout | 38 | The invariant depends on measured element boxes, responsive breakpoints, native/HA dialog shells or focusable target size. | -| Custom-element and HA browser lifecycle | 103 | The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition. | -| **Total** | **233 / 200** | Above the guideline `mutation-gate --check` warns rather than fails (#699); each guard above it is held by its own reason in this inventory and its `because`. | +| Custom-element and HA browser lifecycle | 104 | The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition. | +| **Total** | **234 / 200** | Above the guideline `mutation-gate --check` warns rather than fails (#699); each guard above it is held by its own reason in this inventory and its `because`. | ## Measured effect @@ -253,6 +253,7 @@ The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy - `french-locale-wrong-dictionary` - `glow-barrier-render-pass-wiring-skipped` - `glow-static-led-release-skipped` +- `glow-static-ready-after-disconnect` - `household-enter-stops-acting` - `household-marker-drops-keyboard-reach` - `hp-dialog-escape-does-not-close` diff --git a/scripts/mutation-registry.mjs b/scripts/mutation-registry.mjs index 33fc4ec8..d7b55776 100644 --- a/scripts/mutation-registry.mjs +++ b/scripts/mutation-registry.mjs @@ -14267,6 +14267,17 @@ const MUTANT_DEFINITIONS = [ replace: ' // mutant: render the new source fully visible before its entry frame', }], }, + { + id: 'glow-static-ready-after-disconnect', + guard: 'node demo/smoke_led_strip_glow.mjs', + because: '#789 AC4: a real lazy runtime or field import completing after the static custom element ' + + 'disconnects must not request a late update; the browser smoke holds its network response across removal', + patches: [{ + file: 'src/space-render.ts', + find: ' const ledConnected = o.glowRuntime?.host.isConnected ?? (() => false);', + replace: ' const ledConnected = () => true;', + }], + }, { id: 'glow-static-led-release-skipped', guard: 'node demo/smoke_led_strip_glow.mjs', diff --git a/test/optional-space-model-contract.test.mjs b/test/optional-space-model-contract.test.mjs index a459deee..dc424f4a 100644 --- a/test/optional-space-model-contract.test.mjs +++ b/test/optional-space-model-contract.test.mjs @@ -76,7 +76,11 @@ test('empty render keeps create/import affordances without spatial layers', () = // Обёртка: настоящий `nothing` пробрасывается как есть. `noChange` вложен в // стабильный shell: так тело остаётся, а соседний confirm можно убрать. - const wrapper = methodBody('render'); + // #789: внешний render ограничивает кэш барьеров одним проходом; контракт + // пустого тела и подтверждения остаётся во внутренней обёртке. + assert.match(methodBody('render'), + /return this\._lightBarrierPass\.run\(\(\) => this\._renderLightPass\(\)\);/); + const wrapper = methodBody('_renderLightPass'); assert.match(wrapper, /const body = this\._renderBody\(\);/); assert.match(wrapper, /if \(body === nothing\) return body;/); assert.match(wrapper, /return this\._renderRoot\(body\);/);