Measured by the #4425 phase-1 DOM-leak sweep gate (packages/app-shell/src/__tests__/widget-dom-leak-sweep.test.tsx). Recorded in that gate's ledger, not fixed there — phase 1 is measurement only.
The defect
view:dashboard resolves to DashboardRenderer, whose widget-grid container ends in a bare spread (packages/plugin-dashboard/src/DashboardRenderer.tsx:962). Reached through SchemaRenderer — which every dashboard page is — the node's own keys and its props contents land on that container as attributes.
This is the same package PR #4428 fixed for MetricWidget / MetricCard and a different element: #4357 measured and closed the two KPI card components, and the container the cards sit in was not in that card's scope.
Measured, through the real SDUI path
One render under SchemaRendererProvider, node carrying the canary set:
class="grid auto-rows-min grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
style="gap: 1rem;" id="canary-node" name="canary_node" bind="data.revenue"
events="[object Object]" arialabel="Canary label" ariadescribedby="canary-desc"
zzcanary="CANARY-STR" zzcanaryobj="[object Object]" zzcanarynum="42"
zzcanarycamel="CANARY-CAMEL" reference_to="contacts" props="[object Object]"
colorvariant="success" zzcanaryprop="CANARY-PROP" aria-label="Canary label"
aria-describedby="canary-desc" data-obj-id="canary-node" data-obj-type="view:dashboard"
The 13 leaked attribute names:
ariadescribedby arialabel bind colorvariant events
name props reference_to zzcanary zzcanaryobj
zzcanarynum zzcanarycamel zzcanaryprop
datasource is not among them — DashboardRenderer consumes the adapter, so it never reaches the spread. schema is not either. Everything else does.
As with #4431, arialabel / ariadescribedby duplicate the correctly-resolved aria-label / aria-describedby the renderer emits, under a spelling assistive technology ignores.
Not in scope of the gate that found it
The sweep ledgers this target with this issue as its owner. The assertion is exact set equality, so fixing the leak turns the gate red until the ledger row is deleted in the same change.
Fix shape
Deliberately left to #4425 phase 2, which decides the SDUI widget prop contract generally. Note this package already carries a deny-list for the same class — packages/plugin-dashboard/src/schemaHostProps.ts — so the cheap move is to reuse it here. That would strip the seven named keys and leave the open tail (zzcanary, reference_to, an authored props: { colorVariant }) still on the DOM, which is exactly the limit the sweep measured on metric and metric-card. Worth weighing against the whitelist before reaching for it.
Generated by Claude Code
Measured by the #4425 phase-1 DOM-leak sweep gate (
packages/app-shell/src/__tests__/widget-dom-leak-sweep.test.tsx). Recorded in that gate's ledger, not fixed there — phase 1 is measurement only.The defect
view:dashboardresolves toDashboardRenderer, whose widget-grid container ends in a bare spread (packages/plugin-dashboard/src/DashboardRenderer.tsx:962). Reached throughSchemaRenderer— which every dashboard page is — the node's own keys and itspropscontents land on that container as attributes.This is the same package PR #4428 fixed for
MetricWidget/MetricCardand a different element: #4357 measured and closed the two KPI card components, and the container the cards sit in was not in that card's scope.Measured, through the real SDUI path
One render under
SchemaRendererProvider, node carrying the canary set:The 13 leaked attribute names:
datasourceis not among them —DashboardRendererconsumes the adapter, so it never reaches the spread.schemais not either. Everything else does.As with #4431,
arialabel/ariadescribedbyduplicate the correctly-resolvedaria-label/aria-describedbythe renderer emits, under a spelling assistive technology ignores.Not in scope of the gate that found it
The sweep ledgers this target with this issue as its owner. The assertion is exact set equality, so fixing the leak turns the gate red until the ledger row is deleted in the same change.
Fix shape
Deliberately left to #4425 phase 2, which decides the SDUI widget prop contract generally. Note this package already carries a deny-list for the same class —
packages/plugin-dashboard/src/schemaHostProps.ts— so the cheap move is to reuse it here. That would strip the seven named keys and leave the open tail (zzcanary,reference_to, an authoredprops: { colorVariant }) still on the DOM, which is exactly the limit the sweep measured onmetricandmetric-card. Worth weighing against the whitelist before reaching for it.Generated by Claude Code