fix(types,plugin-dashboard): retire drillDown on the bare pivot node; object-pivot is where a pivot drills (objectui#10932) - #10972
Conversation
…(objectui#10932) `drillDown` on a `pivot` node validated and did nothing: `PivotTable` drilled only for a host that passed `onDrillDown`, and the `pivot` registration passes none. Retire it on both faces, naming `object-pivot`: - `PivotTableSchema.drillDown` is a `?: never` tombstone. - The zod `pivot` arm refuses it via `retirementTombstone()`. - `PivotTable` reads nothing off the node for its drill: the host's `onDrillDown` is the only switch. - `ObjectPivotTable` keeps its own `drillDown` (`ObjectPivotDrillDownConfig`), intersected with the pivot schema minus the tombstone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
…oth faces (objectui#10932) - types: the zod arm refuses `drillDown` at its path (`invalid_type`, message naming `object-pivot`, one string on both channels), on the arm, the rendering face and the strict face; a `@ts-expect-error` and an `Equal` row pin the `?: never` tombstone. Controls: the node without it parses on all three. - The objectui#10859 pins that asserted the old accept now assert the refusal. - plugin-dashboard: the node's `drillDown` can neither turn `PivotTable`'s drill on nor off (the host handler is the switch), and a `pivot` node rendered through `SchemaRenderer` draws no drill affordance. - Changeset: `@object-ui/types` and `@object-ui/plugin-dashboard` minor, breaking behaviour stated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
…l three superseded entries (objectui#10932) - The SchemaRenderer probe types its fixtures instead of casting to `any`: the document carries the retired key, the host-handler control renders the plain pivot. - The changeset names every pending entry whose sentence about the `pivot` arm's `drillDown` this change supersedes (objectui#10859, and the dated notes on the objectui#7352 and objectui#10685 entries). Those entries are not edited here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Inputs: card objectui#10932 (body, triage ① Derived judgmentsAccept-set changes, the bare
Public-surface changes:
Pins: adequate. The types pin covers the arm, ② Semver level
③ Boundary flags
Deviations (os-dev-report
Gates: 43 check-runs on the head, 40 Implemented-by: VERDICT: PASS Generated by Claude Code |
…drillDown that PR #10972 made false (objectui#10974) PR objectui#10972 (objectui#10932) retired `drillDown` on the bare `pivot` node on both faces in this same release: `PivotTableSchema.drillDown` is a `?: never` tombstone and the zod `pivot` arm declares it as a `retirementTombstone()`. Three pending entries still read it as the shared `DrillDownConfigSchema`, so each gets a dated 2026-09-29 supersession note, appended at the end of the file: - 10859-pivot-object-block-zod-arms.md - 7352-drill-down-config-mirror.md (its 2026-09-28 note) - 10685-drilldown-per-block.md (its 2026-09-28 note) Append only: frontmatter byte-identical, no existing line edited or deleted, per the maintainer's 2026-09-29 ruling recorded on the card. Claude-Session: https://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm Co-authored-by: Claude <noreply@anthropic.com>
Fixes #10932
Clause-②: no — a retirement narrows the accept set; it widens nothing and adds no public surface.
drillDownon the barepivotnode validated and did nothing. This retires it on both published faces, with a tombstone that namesobject-pivotas the remedy. That is option (b) of the card, as graded in triage comment5868092364.object-pivot's owndrillDown(ObjectPivotDrillDownConfig) is untouched and still drills.Implemented by the
domain:specdispatched dev, sessionhttps://claude.ai/code/session_012UwY3ahMixEFkfTUxMVkYm, on the PM claim5868869683. Base95a7c8d38.Premise gate (measured before any edit)
The grade's premise was: no shipped or example document authors
drillDownon apivotnode (as opposed toobject-pivot), and a static-data drill has no meaning. It holds.95a7c8d38(clean worktree; enumerationgit ls-files, reads from the same checkout). A structural classifier looks up thetypeof the object that encloses everydrillDownkey, and of the parent widget when that object is anoptionsbag. It also lists everytype: 'pivot'/'object-pivot'object. It scanned 9,125 files (json/ts/tsx/js/md/mdx/yaml) and found 88drillDownkey sites.pivot: 2 sites, both test fixtures.drillRefusal-10789.test.tsxrendersObjectPivotTable, so it is anobject-pivotdrill.registered-type-arms-10859-b2.test.tsis the objectui#10859 accept pin, which this PR updates. These are the matcher's positive control.type: 'pivot'objects: theDashboardGridLayoutstatic-data branch,plugin-dashboard/SKILL.md, a CHANGELOG entry, a code comment, and the declaration itself. None carriesdrillDown.examples/**(504 files, 473 of them inexamples/schema-catalog) has zeropivotordrillDownmentions. The control is that the same query finds"type"there.apps/**,content/docs/**, every package README andskills/**hold nopivotnode document at all. The only hits are type-name tables and prose.origin/maindbddf02c1, 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.pivotand 1object-pivot(insdui.manifest.json). None carriesdrillDown.pivot_tasksin the app-showcasechart-gallerydashboard, is dataset-bound. It renders throughDatasetWidget, not thepivotnode.drillDownkey 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 adrillDownof its own; only its table branch defaults one. A pivot widget'soptions.drillDownwould pass through, and none is authored anywhere above.ObjectPivotTable'sDrillDownDrawer, and itsrenderDrillDrawerreturns nothing withoutschema.objectName. Apivotnode declares no object, so a drill has nothing to list.onDrillDownhas exactly one producer,ObjectPivotTable. Thepivotregistration is barePivotTable, and console's lazy stub loads that same registration. The inertness was also read at runtime, through the realSchemaRendererand registry (the new plugin-dashboard probe): apivotnode carryingdrillDown: { enabled: true }renders the cross-tab with zerorole=buttonelements.What changed
@object-ui/typesPivotTableSchema.drillDownis a?: nevertombstone. Its docblock follows theDataTableSchema.toolbarconvention and points atobject-pivot/ObjectPivotDrillDownConfig.pivotarm'sdrillDownisretirementTombstone(PIVOT_DRILL_DOWN_RETIRED). The one string feeds both the parse-time message and.describe(), and it namesobject-pivot.PIVOT_NEITHER_CHANNEL, thebody/childrenrefusal, no longer listsdrillDownamong what apivotrenders.DrillDownConfigSchema, the zodPivotTableSchema, andObjectPivotDrillDownConfig.@object-ui/plugin-dashboardPivotTablereads nothing offschemafor its drill. The host'sonDrillDownis now the only switch.ObjectPivotTabletypes itsschemaasPivotTableSchemaminusdrillDown(key remapping, notOmit:BaseSchema's index signature makesOmitdrop every declared member), intersected with its owndrillDown?: ObjectPivotDrillDownConfig. It strips that key before handing the node toPivotTable..changeset/10932-pivot-drilldown-retired.md:@object-ui/typesand@object-ui/plugin-dashboard, bothminor, 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
PivotTablehad nodrillDownReact prop. It readschema.drillDownand gated it withisDrillEnabled. With the node key tombstoned, it had to stop reading it, and there were two routes:drillDownReact prop. Not taken.SchemaRendererspreads a node's keys as React props, so a prop of that name would hand an authoreddrillDownon apivotnode straight back to the component. That reopens the channel the tombstone closes.PivotTabletook from the config was the on/off bit, and its one drilling host already decides that before it passesonDrillDown. Behaviour ofobject-pivotis unchanged.For a React caller the published behaviour changes: a handler now turns the drill on by itself, and a
schema.drillDownno 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 underpackages/types/src/__tests__/and one changeset. This PR also editspackages/plugin-dashboard/src/PivotTable.tsx,packages/plugin-dashboard/src/ObjectPivotTable.tsxand two plugin-dashboard tests.That is forced by the ruled TS tombstone: reverse verification 5 below shows
ObjectPivotTablestops 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 --listFilesincludesPivotTable.drill.test.tsx,pivotNode.drillDownRetired-10932.test.tsxandObjectPivotTable.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.pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-dashboard^...' build, exit 0. It includes@object-ui/types, whose build runscheck-dist-completeness. The rebuiltdist/data-display.d.tscarriesdrillDown?: never.New and updated pins
packages/types/src/__tests__/pivot-drilldown-retired-10932.test.ts(new)codeinvalid_type,expectednever,path['drillDown'], on the arm,safeValidateSchemaandStrictAnyComponentSchema.`object-pivot`, equals.describe(), and is not zod's generic text.drillDownparses on all three.@ts-expect-errorline, plusEqualrows (drillDownreadsundefined;titlestaysstring | undefined).registered-type-arms-10859-b2.test.ts: the "fully populated" fixture dropsdrillDown. The member-level pin now asserts the whole-key refusal at['drillDown'].PivotTable.drill.test.tsx: the node'sdrillDowncan neither turn the drill on (no handler) nor turn it off (enabled: falsewith a handler). The fixtures no longer author the retired key.pivotNode.drillDownRetired-10932.test.tsx(new): theSchemaRenderer+ real-registry probe above, with a lit control (the same query finds the affordance when a host passesonDrillDown).object-pivotwithdrillDownhas no zod arm, so asafeParseof it is refused attypeeither way. Theobject-pivotaccept controls are the existinglivecase inObjectPivotTable.drillDownRefusal-10685.test.tsx(TS, green) and the CONTROL case indrillRefusal-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 andgit diff HEADis empty.DrillDownConfigSchema.optional(). Five tests go red: 4 in the new pin and the rewritten objectui#10859 path pin. Exit 1.drillDown?: DrillDownConfig.tsc -p tsconfig.test.jsoninpackages/typesreports 4 errors: the pin'sEqualrow, an unused@ts-expect-error, the objectui#10859MismatchedKeysrow, and thezod-mirror-parityledger. Exit 2.PivotTable's switch re-reads the node key (... && Boolean(schema.drillDown?.enabled)). 11 tests go red: 6 inPivotTable.drill.test.tsxand 5 indrillRefusal-10789.test.tsx, sinceObjectPivotTableno longer hands the key down. Exit 1.true, the probe goes red. Exit 1..d.tsis read:ObjectPivotTable's schema intersected with the fullPivotTableSchemaagain gives 4TS2339errors ondrillDown?.target / columns / maxRows / report(property ofnever). Exit 2.Gates
These were hand-derived from objectui's
package.jsonand.github/workflows/, since objectui has nodispatch-gates.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.--teston the 10 paths: NOT GOVERNED.pnpm lintbelongs to CI. The evidence has three parts:eslint.config.js. No package has its own config.--format jsonreports 9 files, 0 errors.parserOptions.project/projectService), and no rule ineslint-rules/reads another file, so this diff cannot move a verdict on an untouched file.check-sdui-registration-pins. Its prerequisite is a console bundle (exit 2, prerequisite not met), and no registration changed.pnpm test/pnpm lint. Those runs belong to CI.Acceptance notes
check-changeset-overwriteguards 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: "drillDownis the sharedDrillDownConfigSchema"..changeset/7352-drill-down-config-mirror.md: "itsdrillDownis this entry'sDrillDownConfigSchema, so the opening paragraph's two referencing declarations are three for the release"..changeset/10685-drilldown-per-block.md: "a validator does read the members of apivotnode'sdrillDown, and acceptsmodethere".dataProvidertombstone docblock inObjectPivotTable.tsxand the header ofwidgetDataProviderRetired-7353.test.tsxstill sayPivotTableSchemahas no zod mirror. That has been false since objectui#10859, and it concerns a different member.mainmoved 3 commits past the base (328abeb55), and none touches these files. PR fix(types): content-channel refusals name the parser tier's not-a-container warning (objectui#10928) #10956 (objectui#10928), the serial neighbour, was already in the base.Generated by Claude Code