Repository navigation
Commit cc4e476
fix(types,plugin-dashboard): retire drillDown on the bare pivot node; object-pivot is where a pivot drills (objectui#10932) (#10972)
Fixes #10932
Clause-②: no — a retirement narrows the accept set; it widens nothing
and adds no public surface.
`drillDown` on the bare `pivot` node validated and did nothing. This
retires it on both published faces, with a tombstone that names
`object-pivot` as the remedy. That is option (b) of the card, as graded
in triage comment `5868092364`. `object-pivot`'s own `drillDown`
(`ObjectPivotDrillDownConfig`) is untouched and still drills.
Implemented by the `domain:spec` dispatched dev, session
`https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm`, on the PM
claim `5868869683`. Base `95a7c8d38`.
## Premise gate (measured before any edit)
The grade's premise was: no shipped or example document authors
`drillDown` on a `pivot` node (as opposed to `object-pivot`), and a
static-data drill has no meaning. **It holds.**
- **objectui**, tree at base `95a7c8d38` (clean worktree; enumeration
`git ls-files`, reads from the same checkout). A structural classifier
looks up the `type` of the object that encloses every `drillDown` key,
and of the parent widget when that object is an `options` bag. It also
lists every `type: 'pivot'` / `'object-pivot'` object. It scanned 9,125
files (json/ts/tsx/js/md/mdx/yaml) and found 88 `drillDown` key sites.
- Enclosing type `pivot`: 2 sites, both test fixtures.
`drillRefusal-10789.test.tsx` renders `ObjectPivotTable`, so it is an
`object-pivot` drill. `registered-type-arms-10859-b2.test.ts` is the
objectui#10859 accept pin, which this PR updates. These are the
matcher's positive control.
- Non-test `type: 'pivot'` objects: the `DashboardGridLayout`
static-data branch, `plugin-dashboard/SKILL.md`, a CHANGELOG entry, a
code comment, and the declaration itself. None carries `drillDown`.
- `examples/**` (504 files, 473 of them in `examples/schema-catalog`)
has zero `pivot` or `drillDown` mentions. The control is that the same
query finds `"type"` there.
- `apps/**`, `content/docs/**`, every package README and `skills/**`
hold no `pivot` node document at all. The only hits are type-name tables
and prose.
- **objectstack**, at `origin/main` `dbddf02c1`, fetched into a named
ref. Enumeration and reads both come from that ref (`git grep` / `git
show`). The local checkout was 15 commits behind, so it was not read.
- 7 pivot-typed objects: 6 `pivot` and 1 `object-pivot` (in
`sdui.manifest.json`). None carries `drillDown`.
- The one shipped pivot widget, `pivot_tasks` in the app-showcase
`chart-gallery` dashboard, is dataset-bound. It renders through
`DatasetWidget`, not the `pivot` node.
- 9 `drillDown` key sites, none on a pivot. All are spec pins: `bar`,
`summary`, and the dashboard-widget refusal ("Drill-through on a
dashboard is AUTOMATIC").
- **`DashboardGridLayout`'s static-data pivot** emits `{ type: 'pivot',
...options, data }`. It never writes a `drillDown` of its own; only its
table branch defaults one. A pivot widget's `options.drillDown` would
pass through, and none is authored anywhere above.
- **Static-data drill meaning.** The only drill implementation is
`ObjectPivotTable`'s `DrillDownDrawer`, and its `renderDrillDrawer`
returns nothing without `schema.objectName`. A `pivot` node declares no
object, so a drill has nothing to list.
- **Runtime.** `onDrillDown` has exactly one producer,
`ObjectPivotTable`. The `pivot` registration is bare `PivotTable`, and
console's lazy stub loads that same registration. The inertness was also
read at runtime, through the real `SchemaRenderer` and registry (the new
plugin-dashboard probe): a `pivot` node carrying `drillDown: { enabled:
true }` renders the cross-tab with zero `role=button` elements.
## What changed
- `@object-ui/types`
- `PivotTableSchema.drillDown` is a `?: never` tombstone. Its docblock
follows the `DataTableSchema.toolbar` convention and points at
`object-pivot` / `ObjectPivotDrillDownConfig`.
- The zod `pivot` arm's `drillDown` is
`retirementTombstone(PIVOT_DRILL_DOWN_RETIRED)`. The one string feeds
both the parse-time message and `.describe()`, and it names
`object-pivot`.
- `PIVOT_NEITHER_CHANNEL`, the `body` / `children` refusal, no longer
lists `drillDown` among what a `pivot` renders.
- Three docblocks that described the old accept are updated:
`DrillDownConfigSchema`, the zod `PivotTableSchema`, and
`ObjectPivotDrillDownConfig`.
- `@object-ui/plugin-dashboard`
- `PivotTable` reads nothing off `schema` for its drill. The host's
`onDrillDown` is now the only switch.
- `ObjectPivotTable` types its `schema` as `PivotTableSchema` minus
`drillDown` (key remapping, not `Omit`: `BaseSchema`'s index signature
makes `Omit` drop every declared member), intersected with its own
`drillDown?: ObjectPivotDrillDownConfig`. It strips that key before
handing the node to `PivotTable`.
- `.changeset/10932-pivot-drilldown-retired.md`: `@object-ui/types` and
`@object-ui/plugin-dashboard`, both `minor`, with the break stated. The
changeset names the three pending entries whose sentences this
supersedes (see Acceptance notes).
### Decision the dispatch asked for: the component's drill switch
`PivotTable` had no `drillDown` React prop. It read `schema.drillDown`
and gated it with `isDrillEnabled`. With the node key tombstoned, it had
to stop reading it, and there were two routes:
- **(i) Move the config to a new `drillDown` React prop. Not taken.**
`SchemaRenderer` spreads a node's keys as React props, so a prop of that
name would hand an authored `drillDown` on a `pivot` node straight back
to the component. That reopens the channel the tombstone closes.
- **(ii) Make the host's handler the only switch. Taken.** The only
thing `PivotTable` took from the config was the on/off bit, and its one
drilling host already decides that before it passes `onDrillDown`.
Behaviour of `object-pivot` is unchanged.
For a React caller the published behaviour changes: a handler now turns
the drill on by itself, and a `schema.drillDown` no longer gates it (the
type refuses that key anyway). The changeset states this.
### Claimed file surface: exceeded, on purpose
The claim listed `packages/types/src/data-display.ts`,
`packages/types/src/zod/data-display.zod.ts`, pins under
`packages/types/src/__tests__/` and one changeset. This PR also edits
`packages/plugin-dashboard/src/PivotTable.tsx`,
`packages/plugin-dashboard/src/ObjectPivotTable.tsx` and two
plugin-dashboard tests.
That is forced by the ruled TS tombstone: reverse verification 5 below
shows `ObjectPivotTable` stops compiling without the change. The
dispatch's mechanism assumption 3 also asked for this decision.
## Tests
All runs are from head `fd2befe42`.
- `pnpm --filter @object-ui/types type-check` (all three legs): exit 0.
- `pnpm exec vitest run packages/types/`: 269 files, 5,963 tests passed.
- `pnpm --filter @object-ui/plugin-dashboard type-check` (both legs):
exit 0. `tsc -p tsconfig.test.json --listFiles` includes
`PivotTable.drill.test.tsx`, `pivotNode.drillDownRetired-10932.test.tsx`
and `ObjectPivotTable.drillDownRefusal-10685.test.tsx`.
- `pnpm exec vitest run packages/plugin-dashboard/`: 149 files; 1,346
passed, 6 skipped.
- `apps/console/src/__tests__/registry-inputs-spec-parity.test.ts` +
`packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts`:
2 files, 213 passed.
- Build: `pnpm --workspace-concurrency=2 --filter
'@object-ui/plugin-dashboard^...' build`, exit 0. It includes
`@object-ui/types`, whose build runs `check-dist-completeness`. The
rebuilt `dist/data-display.d.ts` carries `drillDown?: never`.
### New and updated pins
- `packages/types/src/__tests__/pivot-drilldown-retired-10932.test.ts`
(new)
- Refusal: `code` `invalid_type`, `expected` `never`, `path`
`['drillDown']`, on the arm, `safeValidateSchema` and
`StrictAnyComponentSchema`.
- Message: names `` `object-pivot` ``, equals `.describe()`, and is not
zod's generic text.
- The key stays declared: a tombstone, not a deletion.
- Control: the same node without `drillDown` parses on all three.
- TS: a `@ts-expect-error` line, plus `Equal` rows (`drillDown` reads
`undefined`; `title` stays `string | undefined`).
- `registered-type-arms-10859-b2.test.ts`: the "fully populated" fixture
drops `drillDown`. The member-level pin now asserts the whole-key
refusal at `['drillDown']`.
- `PivotTable.drill.test.tsx`: the node's `drillDown` can neither turn
the drill on (no handler) nor turn it off (`enabled: false` with a
handler). The fixtures no longer author the retired key.
- `pivotNode.drillDownRetired-10932.test.tsx` (new): the
`SchemaRenderer` + real-registry probe above, with a lit control (the
same query finds the affordance when a host passes `onDrillDown`).
- Not a zod control: `object-pivot` with `drillDown` has no zod arm, so
a `safeParse` of it is refused at `type` either way. The `object-pivot`
accept controls are the existing `live` case in
`ObjectPivotTable.drillDownRefusal-10685.test.tsx` (TS, green) and the
CONTROL case in `drillRefusal-10789.test.tsx` (the drawer opens, green).
### Reverse verifications
Each was run from committed state through `ablation-replace.mjs`, which
checks the anchor hit and restores on a trap. Every restore was proven:
the blob equals HEAD and `git diff HEAD` is empty.
1. Zod arm back to `DrillDownConfigSchema.optional()`. Five tests go
red: 4 in the new pin and the rewritten objectui#10859 path pin. Exit 1.
2. TS member back to `drillDown?: DrillDownConfig`. `tsc -p
tsconfig.test.json` in `packages/types` reports 4 errors: the pin's
`Equal` row, an unused `@ts-expect-error`, the objectui#10859
`MismatchedKeys` row, and the `zod-mirror-parity` ledger. Exit 2.
3. `PivotTable`'s switch re-reads the node key (`... &&
Boolean(schema.drillDown?.enabled)`). 11 tests go red: 6 in
`PivotTable.drill.test.tsx` and 5 in `drillRefusal-10789.test.tsx`,
since `ObjectPivotTable` no longer hands the key down. Exit 1.
4. Non-vacuity of the SchemaRenderer probe, which is green on base by
design because it records the premise: with the switch forced to `true`,
the probe goes red. Exit 1.
5. Cross-package, which also proves the rebuilt `.d.ts` is read:
`ObjectPivotTable`'s schema intersected with the full `PivotTableSchema`
again gives 4 `TS2339` errors on `drillDown?.target / columns / maxRows
/ report` (property of `never`). Exit 2.
### Gates
These were hand-derived from objectui's `package.json` and
`.github/workflows/`, since objectui has no `dispatch-gates`.
- Exit 0 at head: `check-control-bytes`,
`check-new-cross-file-line-citations` (0 new citations),
`check-spec-symbol-derivation`, `check-changeset-presence`,
`check-changeset-no-major`, `check-changeset-overwrite` (no pre-existing
changeset modified), `check-changeset-fixed`, `check-changeset-claims`,
`check-pending-changeset-literals`, `check-handler-key-read-sites`,
`check-component-surface-parity`, `check-test-path-roots`,
`check-unreferenced-sources`.
- Governed-surface guard `--test` on the 10 paths: NOT GOVERNED.
- A control-byte grep of the changed files found no hits.
- Lint, narrowed, measured per file rather than run repo-wide. The
repo-wide `pnpm lint` belongs to CI. The evidence has three parts:
1. The population is the 9 changed TS files, linted under the root
`eslint.config.js`. No package has its own config.
2. `--format json` reports 9 files, 0 errors.
3. The config enables no type-aware linting (no `parserOptions.project`
/ `projectService`), and no rule in `eslint-rules/` reads another file,
so this diff cannot move a verdict on an untouched file.
- Warning counts are identical base vs head for each of the 7
pre-existing files. The 2 new test files have 0 warnings.
- NOT MEASURED: `check-sdui-registration-pins`. Its prerequisite is a
console bundle (exit 2, prerequisite not met), and no registration
changed.
- NOT MEASURED: e2e, and the full `pnpm test` / `pnpm lint`. Those runs
belong to CI.
## Acceptance notes
- **Release text.** Three pending changesets say something this change
makes false for the release. They are **not** edited here:
`check-changeset-overwrite` guards pre-existing entries, and the repo's
precedent is a separate dated-note PR. This PR's own changeset names all
three.
- `.changeset/10859-pivot-object-block-zod-arms.md`: "`drillDown` is the
shared `DrillDownConfigSchema`".
- The dated note in `.changeset/7352-drill-down-config-mirror.md`: "its
`drillDown` is this entry's `DrillDownConfigSchema`, so the opening
paragraph's two referencing declarations are three for the release".
- The dated note in `.changeset/10685-drilldown-per-block.md`: "a
validator does read the members of a `pivot` node's `drillDown`, and
accepts `mode` there".
- **Stale prose, not touched.** The `dataProvider` tombstone docblock in
`ObjectPivotTable.tsx` and the header of
`widgetDataProviderRetired-7353.test.tsx` still say `PivotTableSchema`
has no zod mirror. That has been false since objectui#10859, and it
concerns a different member.
- `main` moved 3 commits past the base (`328abeb55`), and none touches
these files. PR #10956 (objectui#10928), the serial neighbour, was
already in the base.
---
_Generated by [Claude
Code](https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent fe56394 commit cc4e476
10 files changed
Lines changed: 382 additions & 47 deletions
File tree
- .changeset
- packages
- plugin-dashboard/src
- __tests__
- types/src
- __tests__
- zod
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
41 | 56 | | |
42 | | - | |
| 57 | + | |
43 | 58 | | |
44 | 59 | | |
45 | 60 | | |
| |||
96 | 111 | | |
97 | 112 | | |
98 | 113 | | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
104 | 120 | | |
105 | 121 | | |
106 | 122 | | |
| |||
354 | 370 | | |
355 | 371 | | |
356 | 372 | | |
357 | | - | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
358 | 377 | | |
359 | | - | |
| 378 | + | |
360 | 379 | | |
361 | 380 | | |
362 | 381 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
44 | | - | |
45 | | - | |
46 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
47 | 55 | | |
48 | 56 | | |
49 | 57 | | |
| |||
179 | 187 | | |
180 | 188 | | |
181 | 189 | | |
182 | | - | |
183 | 190 | | |
184 | 191 | | |
185 | 192 | | |
186 | | - | |
| 193 | + | |
| 194 | + | |
187 | 195 | | |
188 | 196 | | |
189 | 197 | | |
| |||
Lines changed: 20 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
36 | | - | |
37 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
38 | 42 | | |
39 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
40 | 50 | | |
41 | 51 | | |
42 | 52 | | |
43 | 53 | | |
44 | 54 | | |
45 | 55 | | |
46 | | - | |
| 56 | + | |
47 | 57 | | |
48 | 58 | | |
49 | 59 | | |
| |||
62 | 72 | | |
63 | 73 | | |
64 | 74 | | |
65 | | - | |
| 75 | + | |
66 | 76 | | |
67 | 77 | | |
68 | 78 | | |
| |||
74 | 84 | | |
75 | 85 | | |
76 | 86 | | |
77 | | - | |
| 87 | + | |
78 | 88 | | |
79 | 89 | | |
80 | 90 | | |
| |||
86 | 96 | | |
87 | 97 | | |
88 | 98 | | |
89 | | - | |
| 99 | + | |
90 | 100 | | |
91 | 101 | | |
92 | 102 | | |
| |||
100 | 110 | | |
101 | 111 | | |
102 | 112 | | |
103 | | - | |
| 113 | + | |
104 | 114 | | |
105 | 115 | | |
106 | 116 | | |
| |||
Lines changed: 64 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
Lines changed: 4 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | | - | |
29 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| |||
0 commit comments