Parent record for the leak ledger that landed with #5574 (PR #5629). Filed unassigned and ungraded by the domain:ui execution seat (#5560) so the work is tracked rather than stranded inside a test file. Sizing and sequencing are triage's to decide — see "What this card is not" below.
What exists now
packages/app-shell/src/__tests__/widget-dom-leak-sweep.test.tsx sweeps 158 registry types across the five namespaces owned by packages/components/src/renderers/** (ui:, element:, page:, action:, protocol-placeholder:), all 86 renderer source files. Before #5629 it saw none of them.
119 of 158 targets leak DOM attributes. All 119 are enumerated in LEAK_LEDGER in that file — that map is authoritative for the exact per-target attribute sets; the summary below is a reading of it, not a substitute.
Why this is safe to burn down incrementally
The per-target assertion is exact set equality in both directions, so the ledger expires itself on contact:
- a ledgered renderer that leaks one more attribute fails the gate;
- a renderer that stops leaking also fails it, until its row is deleted in the same change.
A follow-up therefore cannot half-land, and the rows cannot quietly become a permanent allowlist. Nothing is skipped, it.skip-ed or quarantined — all 158 targets render and are scanned on every run.
Three meta-cases keep that honest: no renderer may appear in two groups; every readiness override must carry a recorded reason and every reason an override (two-way, so the override list cannot become a parking space); and the four renderers #5574 originally named must stay ledgered while ui:grid must stay out.
The grouping, as a starting point for decomposition
The ledger groups by measured mechanism rather than by file, which is why mechanism looks like the natural card boundary — each group has one argument and one test story, where a file-sized card would have neither.
| group | targets | note |
|---|
BARE_SPREAD | 95 | 14 attributes including name |
BARE_SPREAD_MINUS_NAME | 18 | 13 attributes — the host definesname, so HTML makes that one legitimate |
BARE_SPREAD_ON_SVG | 2 | ui:icon, ui:spinner — 14 attributes with camelCase preserved, because SVG attribute names are case-sensitive |
action:group | 1 | BARE_SPREAD plus actions |
action:menu | 1 | MINUS_NAME plus actions |
ui:form | 1 | 12 attributes; FormRenderer consumes dataSource and form defines name |
ui:sidebar-trigger | 1 | 14 attributes including schema itself — the node SchemaRenderer injects on every render |
Read LEAK_LEDGER for the authoritative grouping and the exact attribute sets; the counts above are transcribed from the landing report and the mechanisms, not the individual rows, are what this table is for.
Two things a burn-down needs to know before starting
A renderer that renders nothing reads clean. The first sweep pass reported 46 clean targets. Sixteen were phantom — 12 rendered zero elements (closed overlays, action:* with no actions, ui:icon returning null) and 4 threw useSidebar into an attribute-clean error boundary. Once made to render real markup, 7 of the 16 leaked. A DOM-attribute gate cannot distinguish "safe" from "absent" without a rendering-something precondition, so any fix that makes a renderer bail early will read as a success it did not earn.
ui:grid is clean and must stay out of the ledger.#4787 / PR #5573 fixed it, and it is now pinned from both sides rather than by hand. It is the worked example of what a burned-down row looks like.
What this card is not
It is not a decomposition decision and carries no priority. packages/components is the most-shared package in the repo, several agents land into its merge queue concurrently, and how to slice 119 fixes across it is a planning call this seat declined to make on its own authority. Grading, splitting into per-mechanism cards, or closing this in favour of a different decomposition are all triage's.
Refs #5574, PR #5629, #4787 / PR #5573. Related but distinct, on the same renderer family: #5630 (three element: renderers swept only in their empty-state branch) and #5631 (ui:icon consults the SDUI identity key name).
Parent record for the leak ledger that landed with #5574 (PR #5629). Filed unassigned and ungraded by the
domain:uiexecution seat (#5560) so the work is tracked rather than stranded inside a test file. Sizing and sequencing are triage's to decide — see "What this card is not" below.What exists now
packages/app-shell/src/__tests__/widget-dom-leak-sweep.test.tsxsweeps 158 registry types across the five namespaces owned bypackages/components/src/renderers/**(ui:,element:,page:,action:,protocol-placeholder:), all 86 renderer source files. Before #5629 it saw none of them.119 of 158 targets leak DOM attributes. All 119 are enumerated in
LEAK_LEDGERin that file — that map is authoritative for the exact per-target attribute sets; the summary below is a reading of it, not a substitute.Why this is safe to burn down incrementally
The per-target assertion is exact set equality in both directions, so the ledger expires itself on contact:
A follow-up therefore cannot half-land, and the rows cannot quietly become a permanent allowlist. Nothing is skipped,
it.skip-ed or quarantined — all 158 targets render and are scanned on every run.Three meta-cases keep that honest: no renderer may appear in two groups; every readiness override must carry a recorded reason and every reason an override (two-way, so the override list cannot become a parking space); and the four renderers #5574 originally named must stay ledgered while
ui:gridmust stay out.The grouping, as a starting point for decomposition
The ledger groups by measured mechanism rather than by file, which is why mechanism looks like the natural card boundary — each group has one argument and one test story, where a file-sized card would have neither.
BARE_SPREADnameBARE_SPREAD_MINUS_NAMEname, so HTML makes that one legitimateBARE_SPREAD_ON_SVGui:icon,ui:spinner— 14 attributes with camelCase preserved, because SVG attribute names are case-sensitiveaction:groupBARE_SPREADplusactionsaction:menuMINUS_NAMEplusactionsui:formFormRendererconsumesdataSourceandformdefinesnameui:sidebar-triggerschemaitself — the nodeSchemaRendererinjects on every renderRead
LEAK_LEDGERfor the authoritative grouping and the exact attribute sets; the counts above are transcribed from the landing report and the mechanisms, not the individual rows, are what this table is for.Two things a burn-down needs to know before starting
A renderer that renders nothing reads clean. The first sweep pass reported 46 clean targets. Sixteen were phantom — 12 rendered zero elements (closed overlays,
action:*with no actions,ui:iconreturningnull) and 4 threwuseSidebarinto an attribute-clean error boundary. Once made to render real markup, 7 of the 16 leaked. A DOM-attribute gate cannot distinguish "safe" from "absent" without a rendering-something precondition, so any fix that makes a renderer bail early will read as a success it did not earn.ui:gridis clean and must stay out of the ledger.#4787 / PR #5573 fixed it, and it is now pinned from both sides rather than by hand. It is the worked example of what a burned-down row looks like.What this card is not
It is not a decomposition decision and carries no priority.
packages/componentsis the most-shared package in the repo, several agents land into its merge queue concurrently, and how to slice 119 fixes across it is a planning call this seat declined to make on its own authority. Grading, splitting into per-mechanism cards, or closing this in favour of a different decomposition are all triage's.Refs #5574, PR #5629, #4787 / PR #5573. Related but distinct, on the same renderer family: #5630 (three
element:renderers swept only in their empty-state branch) and #5631 (ui:iconconsults the SDUI identity keyname).