|
36 | 36 | * | plugin-charts | 5 | 0 | 0 | |
37 | 37 | * | plugin-calendar | 3 | 0 | 0 | |
38 | 38 | * | plugin-chatbot | 3 | 0 | 0 | |
39 | | - * | plugin-dashboard | 7 | 2 | 7 / 9 | |
| 39 | + * | plugin-dashboard | 7 | 0 | 0 | |
40 | 40 | * | components | 150 | 82 | 12 .. 15 | |
41 | 41 | * |
42 | | - * **84 of 168 targets leak.** The `components` row is objectui#5574 and is |
43 | | - * covered in its own section below; the two `plugin-dashboard` rows are the |
44 | | - * older tail. Both are in {@link LEAK_LEDGER}: |
45 | | - * `plugin-dashboard:metric` and `plugin-dashboard:metric-card`, the open tail |
46 | | - * objectui#4425 owns directly. Two migration steps have closed their rows since |
47 | | - * the phase-1 measurement: |
| 42 | + * **82 of 168 targets leak.** All of them are the `components` row, which is |
| 43 | + * objectui#5574 and is covered in its own section below. The four packages |
| 44 | + * objectui#4425 named now read zero. Three migration steps have closed their |
| 45 | + * rows since the phase-1 measurement: |
48 | 46 | * |
49 | 47 | * - `plugin-chatbot:chatbot` / `chatbot-enhanced` — 14 attributes each, |
50 | 48 | * objectui#4431 / PR #4485, which also lifted `toDomProps` to |
51 | 49 | * `@object-ui/core` so later cards consume one executor. |
52 | 50 | * - `plugin-dashboard:dashboard` (spelled `view:dashboard` until |
53 | 51 | * objectui#9533) — `DashboardRenderer`'s widget-grid container, 13 |
54 | | - * attributes, objectui#4432 / this file's most recent edit. |
| 52 | + * attributes, objectui#4432. |
| 53 | + * - `plugin-dashboard:metric` / `metric-card` — the KPI cards' open tail, 7 |
| 54 | + * and 9 attributes, objectui#4425 itself: the last two rows inside these |
| 55 | + * four packages. See "what is left of it" below. |
55 | 56 | * |
56 | | - * The three packages now reading 0 are NOT clean for the same reason, and the |
| 57 | + * The four packages now reading 0 are NOT clean for the same reason, and the |
57 | 58 | * difference is worth keeping straight: `plugin-charts` never spreads the node |
58 | 59 | * onto its container at all; `plugin-calendar`'s components take a declared prop |
59 | 60 | * list and drop what they do not name, so the node's keys never reach an |
60 | | - * element; `plugin-chatbot` and `DashboardRenderer`'s grid reach zero by |
61 | | - * FILTERING — they still spread, through `toDomProps`. |
| 61 | + * element; `plugin-chatbot`, `DashboardRenderer`'s grid and the two KPI cards |
| 62 | + * reach zero by FILTERING — they still spread, through `toDomProps`. The KPI |
| 63 | + * cards filter on the renderer's door only: rendered directly as React |
| 64 | + * components they keep their declared `HTMLAttributes` pass-through |
| 65 | + * (objectui#4426), and this gate, which renders every target through |
| 66 | + * `SchemaRenderer`, never sees that door. |
62 | 67 | * |
63 | 68 | * `calendar-view` was originally swept with the `events` canary WITHHELD, because |
64 | 69 | * authoring it crashed the component outright (objectui#4433) — a worse failure |
|
81 | 86 | * - a **deny-list** (`plugin-dashboard/src/schemaHostProps.ts`, #4357/PR |
82 | 87 | * #4428): destructure seven measured non-DOM props out, spread the rest. |
83 | 88 | * |
84 | | - * The deny-list is correct for the seven props it enumerates — this sweep |
85 | | - * confirms all seven are gone from `metric` and `metric-card`. What it cannot |
86 | | - * close is the **open tail**, exactly as `toDomProps`' docblock predicted: an |
87 | | - * authored key the component does not declare still reaches the DOM. That is not |
88 | | - * a hypothetical here; it is ledger rows {@link LEAK_LEDGER} `metric` and |
89 | | - * `metric-card`, where `zzcanary` / `reference_to` / an authored |
90 | | - * `props: { colorVariant }` all land as attributes while every one of the seven |
91 | | - * named keys is correctly stripped. A deny-list bounded by enumeration cannot be |
| 89 | + * The deny-list was correct for the seven props it enumerates — this sweep |
| 90 | + * confirmed all seven gone from `metric` and `metric-card`. What it could not |
| 91 | + * close was the **open tail**, exactly as `toDomProps`' docblock predicted: an |
| 92 | + * authored key the component does not declare still reached the DOM. That was |
| 93 | + * not a hypothetical here; it was two {@link LEAK_LEDGER} rows, `metric` (7 |
| 94 | + * attributes) and `metric-card` (9), where `zzcanary` / `reference_to` / `name` |
| 95 | + * / an authored `props: { colorVariant }` — and, on `metric-card`, an authored |
| 96 | + * `label` — all landed as attributes while every one of the seven named keys |
| 97 | + * was correctly stripped. A deny-list bounded by enumeration cannot be |
92 | 98 | * finished; a whitelist bounded by declaration can. That contrast IS the |
93 | 99 | * measurement phase 2 waited for, and the ruling went to the whitelist on it. |
94 | 100 | * |
95 | | - * So the divergence is no longer a standing state of the repo — it is a |
96 | | - * migration in progress, and the two rows still below are the last of it inside |
97 | | - * these four packages. `plugin-dashboard` is now MIXED by design: its |
98 | | - * `DashboardRenderer` grid container filters through `toDomProps` (#4432) while |
99 | | - * the two KPI components still run the deny-list, and the two surviving rows are |
100 | | - * precisely that difference, measured. |
| 101 | + * The divergence is now gone from these four packages. objectui#4425 moved the |
| 102 | + * two KPI components' renderer door onto `toDomProps` and deleted both rows in |
| 103 | + * the same change — the two-way expiry below, which turned this gate red on |
| 104 | + * exactly those two targets (each measured `[]` against its row) until they |
| 105 | + * went. The deny-list stays in `schemaHostProps.ts` as the direct React door's |
| 106 | + * filter, which this gate does not render. |
101 | 107 | * |
102 | 108 | * ## objectui#5574 — the family this sweep could not see, and what it found |
103 | 109 | * |
@@ -440,7 +446,8 @@ const AUTHORED_EXTRAS = { |
440 | 446 |
|
441 | 447 | /** |
442 | 448 | * Authored `props: { … }`. `colorVariant` is objectui#4425's own measured |
443 | | - * example — `metric-card` has no such prop, so it lands as `colorvariant`. |
| 449 | + * example — `metric-card` has no such prop, so it landed as `colorvariant` |
| 450 | + * until that card moved onto `toDomProps`. |
444 | 451 | */ |
445 | 452 | const AUTHORED_PROPS = { |
446 | 453 | colorVariant: 'success', |
@@ -885,6 +892,10 @@ const TARGETS: Readonly<Record<string, readonly Target[]>> = { |
885 | 892 | ], |
886 | 893 | 'plugin-dashboard': [ |
887 | 894 | { type: 'plugin-dashboard:metric', schemaExtras: { label: 'Revenue', value: 42 }, ready: '.rounded-lg.border' }, |
| 895 | + // `label` is deliberately NOT this card's heading (`MetricCardProps` spells |
| 896 | + // it `title`): authored here it is one more open-tail key, and it once |
| 897 | + // leaked as `label="Revenue"` (objectui#4425). Kept so the gate keeps |
| 898 | + // proving it stops at the component. |
888 | 899 | { type: 'plugin-dashboard:metric-card', schemaExtras: { label: 'Revenue', value: 42 }, ready: '.rounded-lg.border' }, |
889 | 900 | { type: 'plugin-dashboard:object-metric', schemaExtras: { objectName: 'accounts' }, ready: '.rounded-lg.border' }, |
890 | 901 | { type: 'plugin-dashboard:pivot', ready: '[data-testid="pivot-empty-state"]' }, |
@@ -1201,40 +1212,12 @@ const COMPONENTS_LEAK_GROUPS: readonly LedgerGroup[] = [ |
1201 | 1212 | ]; |
1202 | 1213 |
|
1203 | 1214 | const LEAK_LEDGER: Readonly<Record<string, LedgerEntry>> = { |
1204 | | - /* ── plugin-dashboard: the OPEN TAIL a deny-list cannot close ───────────── */ |
1205 | | - // |
1206 | | - // Read these two rows against what is NOT in them. Every one of the seven keys |
1207 | | - // `schemaHostProps.ts` enumerates (#4357 / PR #4428) is absent — `schema`, |
1208 | | - // `bind`, `events`, `props`, `ariaLabel`, `ariaDescribedBy`, `dataSource` are |
1209 | | - // all correctly stripped, on both components, including the adapter. The |
1210 | | - // deny-list does exactly what it claims. |
1211 | | - // |
1212 | | - // What remains is the half it cannot reach: keys the component does not |
1213 | | - // declare and the list never names. That is `toDomProps`' argument, measured |
1214 | | - // rather than predicted, and it is the reading objectui#4425 phase 2 is for. |
1215 | | - 'plugin-dashboard:metric': { |
1216 | | - attributes: [ |
1217 | | - 'name', 'reference_to', 'zzcanary', 'zzcanarycamel', 'zzcanarynum', |
1218 | | - 'zzcanaryobj', 'zzcanaryprop', |
1219 | | - ], |
1220 | | - reason: |
1221 | | - 'the seven deny-listed props are gone; the open tail of authored keys ' + |
1222 | | - '`MetricWidget` does not declare still reaches the Card.', |
1223 | | - issue: 'objectui#4425', |
1224 | | - }, |
1225 | | - 'plugin-dashboard:metric-card': { |
1226 | | - attributes: [ |
1227 | | - 'colorvariant', 'label', 'name', 'reference_to', 'zzcanary', |
1228 | | - 'zzcanarycamel', 'zzcanarynum', 'zzcanaryobj', 'zzcanaryprop', |
1229 | | - ], |
1230 | | - reason: |
1231 | | - 'the same open tail as `metric`, plus two keys that are the tail in ' + |
1232 | | - 'miniature: `colorvariant` is objectui#4425\'s own measured example, and ' + |
1233 | | - '`label` leaks because `MetricCardProps` spells its heading `title` — so ' + |
1234 | | - 'authoring the key its sibling `MetricWidget` takes puts the heading on ' + |
1235 | | - 'the DOM as an attribute instead of rendering it.', |
1236 | | - issue: 'objectui#4425', |
1237 | | - }, |
| 1215 | + // ⛔ No `plugin-dashboard` rows. The last two — `metric` and `metric-card`, |
| 1216 | + // the open tail `schemaHostProps.ts`' deny-list could not close — were |
| 1217 | + // deleted by objectui#4425 when both KPI components moved their renderer door |
| 1218 | + // onto `toDomProps`. Both targets are still swept above with the full canary |
| 1219 | + // set, so a regression there is a NEW leak on an unledgered target and fails |
| 1220 | + // on the empty-report branch below, naming every attribute. |
1238 | 1221 |
|
1239 | 1222 | /* ── packages/components: 82 of 150 targets, in four measured shapes ───── */ |
1240 | 1223 | ...Object.fromEntries( |
@@ -1817,8 +1800,8 @@ const DOCBLOCK_COUNTS = { |
1817 | 1800 | commonestShapeAttributes: 14, |
1818 | 1801 | /** Every target this sweep renders, all five packages. */ |
1819 | 1802 | allTargets: 168, |
1820 | | - /** Every ledgered row, `plugin-dashboard`'s open tail included. */ |
1821 | | - allLedgered: 84, |
| 1803 | + /** Every ledgered row, all five packages. */ |
| 1804 | + allLedgered: 82, |
1822 | 1805 | } as const; |
1823 | 1806 |
|
1824 | 1807 | type CountName = keyof typeof DOCBLOCK_COUNTS; |
|
0 commit comments