Repository navigation
refactor(plugin-dashboard,types): retire the unread widget dataProvider key (objectui#7353) - #10522
Conversation
…der` key Remove the three `dataProvider: widgetData` writes (DashboardRenderer's object-data-table node, DashboardGridLayout's data-table and pivot nodes) and every declaration: `ObjectDataTableSchema.dataProvider` on the TS interface and its zod mirror, and the `schema.dataProvider` member of `ObjectPivotTableProps`. No reader is added; the widgets keep reading the `objectName` written beside it. Pins: the producer nodes carry no `dataProvider` (red on the base), the declared-key probes on both faces, and the measured zod reading after the removal (passthrough keeps an authored value unchecked). Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN Co-authored-by: Claude <noreply@anthropic.com>
…ableSchema too The declared-key probe now also reads `ObjectDataTableProps['schema']`, which this package resolves through `@object-ui/types`' built `.d.ts`, so the consumer side of the types removal is compiled, not assumed. Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN Co-authored-by: Claude <noreply@anthropic.com>
|
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: ① Derived judgmentsHead and base. Writes, declarations, readers. My own census, word-bounded
H3 reading is correct, measured. Is the widening a problem, and was a tombstone owed? This is the material finding. The repo's ADR-0049 retirement pattern is The ruling (5809008870) says "Delete the three writes and every declaration in one change. ⛔ No reader is added to keep the key alive." It never mentions a tombstone; its ⛔ is about readers. The wording omits a tombstone, it does not exclude one. The PR body's justification, "a named refusal is a declaration", is the dev's inference, not the ruling's text. The model pin the PR cites ( Fixture triage. Honest. The removed rejection row H2 plausibility. ② Semver level
The prose is not true sentence by sentence. "Both removals narrow a published declaration" is false for ③ Boundary flags
Implemented-by: VERDICT: FAIL Generated by Claude Code |
…iving carriers Contract review on the previous head found the bare deletion left an authored `dataProvider` absorbed silently: both carriers extend `BaseSchema` (index signature on the TS face, `.passthrough()` on the zod face). Per the repo's retirement discriminator (objectui#5941, #7526, amended by objectui#7678), a surviving carrier takes a `?: never` tombstone when it steers authors to a live replacement key, here `objectName`. - `ObjectDataTableSchema.dataProvider?: never` and a `retirementTombstone` on its zod mirror, whose message says to write `objectName`. - `ObjectPivotTableProps['schema'].dataProvider?: never`; that node has no zod face, so the TS refusal is its only one. - Pins flipped: well-formed and malformed values refused by name, an undeclared key still accepted, `@ts-expect-error` on both TS faces. - Changeset rewritten against released 17.6.0: the published narrowing is plugin-dashboard's; the types half edits an unreleased schema. The three writes stay deleted; no reader is added. Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN Co-authored-by: Claude <noreply@anthropic.com>
✅ 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: ① Derived judgmentsHead and base. FAIL item 1, tombstone omission: discharged, each part measured.
Pins. The 7200 sentence and the ruling. ② Semver level
FAIL item 2 discharged; the rewritten
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
… storage key (objectui#8522) (objectstack-ai#10549) Fixes objectstack-ai#8522 Clause-②: yes — a published export (`useColumnWidths` and its two types) is removed. Executes ruling `5810224713` (remove: reading 2 of the card, superseded and left behind). Dispatched by the `domain:ui` seat 2 PM; implemented by its `os-dev` in session `https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN`. ## What changed - `packages/plugin-kanban/src/useColumnWidths.ts` deleted: the hook, `UseColumnWidthsOptions`, `UseColumnWidthsReturn`, and its storage key `objectui:kanban-column-widths`. - `packages/plugin-kanban/src/index.tsx`: the three entry exports removed (the `useColumnWidths` value export and the two-type `export type` line). - `@object-ui/types` docblocks, comment-only hunks: - `complex.ts`, the bare-`kanban` retirement docblock: the "NOT retired" sentence no longer names the hook as a consumer. `KanbanCard` / `KanbanColumn` / `CardTemplate` keep the renderer and `CardTemplates` as consumers, and `ColumnWidthConfig` is recorded as having lost its one `plugin-kanban` reader to this card, which did not rule on the type. - `objectql.ts`, the `ObjectKanbanSchema` lane "member set is the READ set" paragraph: the hook is dropped from the list of read sites. The hook destructured `columns` as `_columns` and read no lane member, so the counted member set does not move. - `kanban-plugin-dialect-authoritative-7664.test.ts`: the pin-1 comment stops naming the hook. No assertion changed. - New pin `packages/plugin-kanban/src/__tests__/useColumnWidthsRetired-8522.test.ts`, following the `plugin-form` `entrySurface-6059` barrel-pin pattern (`import * as entry` + `Object.keys(entry)`) and the `spec-symbol-4650` compile-time `import('..').X` + `@ts-expect-error` pattern. - `.changeset/8522-retire-use-column-widths.md`: `'@object-ui/plugin-kanban': minor`, with a BREAKING body in migration terms. There is no `@object-ui/types` entry: `check-changeset-presence` asks for presence only, and the types hunks are comment-only. Its last migration bullet names objectui#7742. - `.changeset/7742-kanban-arm-batch70.md`, a pending changeset that this change falsifies, is reconciled here in prose only: - The sentences naming the `useColumnWidths` widths channel, and saying the prop and the hook consume the types, are scoped to "at this change". - A dated note (2026-09-25) records that the hook is retired (objectui#8522), that `ColumnWidthConfig` has no `plugin-kanban` reader, and that `CardTemplate` is still consumed by the `CardTemplates` component's `templates` prop. - The frontmatter is byte-identical: md5 of the frontmatter block is `b62313df8fb2af929fbe2c21c5ae3873` before and after. No tests were deleted. No test existed only to test the hook: the tracked tree had zero test importers of it. ## Premise, measured on `origin/main` `d461b0de8` - Readers. `git grep` over `packages apps examples content skills` found `useColumnWidths` 7 hits in 5 files, `UseColumnWidths` 4 hits in 2 files, and `kanban-column-widths` 1 hit in 1 file. Every hit was the hook's own file, the entry, the two docblocks, or the 7664 comment. On the same instrument, the control `useCrossSwimlaneMove` fired with 5 hits in 3 files. Zero readers holds. - Published surface. H3 answers yes. `@object-ui/plugin-kanban@17.6.0` from the npm registry exports the hook in its `dist/index.js` export list as `Ue as useColumnWidths`, and `dist/index.d.ts` re-exports it and both types. The storage-key literal is present in `dist/index.js` and `dist/index.umd.cjs`. That is why the changeset is written as a migration. - A tree-wide grep found one more carrier outside the file surface: the pending changeset `.changeset/7742-kanban-arm-batch70.md`. It names "a `useColumnWidths` hook option for widths" and says "the prop and the hook still consume the types". Both go false when this merges, and both would publish into the same release, so this PR reconciles it (see above). - A re-grep of every pending `.changeset/*.md` for `useColumnWidths`, `UseColumnWidths` and `kanban-column-widths` hits only 7742 and this PR's own changeset. - The control `CardTemplate` hits 3 files on the same instrument. - The two `7664-*` changesets that name `ColumnWidthConfig` claim only that it is declared and re-exported, which remains true. ## Verification The code legs below ran on `e62e390f4`. The only later commit, `8be30d7fc`, edits changeset prose only; the changeset gates were re-run on it. - Build, under the verify lock: `pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-kanban...' build` printed `VERDICT command-exit 0`. The rebuilt `plugin-kanban/dist` has `useColumnWidths` 0 and `kanban-column-widths` 0 in `index.js`, `index.d.ts` and `index.umd.cjs`, and no `useColumnWidths.d.ts`. The control `useCrossSwimlaneMove` is 2 / 2 / 1. - `pnpm --filter @object-ui/plugin-kanban type-check` (`tsc --noEmit && tsc -p tsconfig.test.json`) exits 0. `tsc -p tsconfig.test.json --listFilesOnly` lists the new pin, so the compile-time half is compiled. - `pnpm --filter @object-ui/types type-check` (including `tsconfig.examples.json` and `tsconfig.test.json`) exits 0. - `pnpm exec vitest run --maxWorkers=2 packages/plugin-kanban/` reports `Test Files 61 passed (61)` and `Tests 412 passed (412)`. That is 61 tracked test files: 60 on base plus the new pin. - `pnpm exec vitest run --maxWorkers=2 packages/types/` reports `Test Files 233 passed (233)` and `Tests 5184 passed (5184)`. - Red on base. The base `index.tsx` and `useColumnWidths.ts` were written back onto disk. The landing was checked on disk: the entry had `useColumnWidths` twice and the hook file was present with its key. Under a `trap` restore: - vitest: `Tests 1 failed | 1 passed (2)`, with `AssertionError: expected [ 'KANBAN_UNCOLUMNED_ID', …(10) ] to not include 'useColumnWidths'`. The failure is the runtime pin; the type-only test is erased at runtime. - `tsc -p tsconfig.test.json` exits 2 with `error TS2578: Unused '@ts-expect-error' directive.` twice, once on each retired type query. - After restore, the `index.tsx` blob matches HEAD `7e09f2d92`, the hook file is absent, and `git diff HEAD` and `git status --porcelain` are both empty. - Changeset and prose gates, on `8be30d7fc`: - `node scripts/check-changeset-presence.mjs` printed `✅ 6 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)`. - `node scripts/check-changeset-overwrite.mjs` exited 0 (report-only). It printed `1 changeset(s) added, 1 modified, 0 deleted`. For 7742 it printed `declared at base: @object-ui/types: minor, @object-ui/plugin-kanban: minor` and `declares now: @object-ui/types: minor, @object-ui/plugin-kanban: minor`. - `node scripts/check-changeset-claims.mjs` exited 0 (report-only), reading `Corpus: 2 changeset(s) this change adds or modifies` with no self-contradiction. It listed 27 pending changesets that name `complex.ts` or `objectql.ts`; none of them names the hook. - `node scripts/check-pending-changeset-literals.mjs` printed `✅ No test source names a pending changeset`. - `node scripts/check-changeset-no-major.mjs` printed `✅ No changeset declares a major bump`. - `node scripts/check-new-cross-file-line-citations.mjs` printed `VERDICT new-cross-file-line-citations: 0 new citation(s)`. - `node scripts/check-control-bytes.mjs` passed. - Source gates, on `e62e390f4`. These exited 0: `check:unreferenced-sources`, `check:self-import`, `check:side-effects-array`, `check:handler-key-reads`, `check:entry-guard`, `check:phantom-deps`, `check:unused-deps`, `check:test-path-roots`, `check:vi-mock-specifiers`, `check:spec-symbols` and `check:esm-specifiers`. - `check:readme-exports` passed after the build. No README names any of the three removed exports. - ESLint on the 5 touched text files (`--no-inline-config --format json`): 0 errors. The 66 warnings are pre-existing `no-explicit-any` / `react-refresh` warnings in untouched lines, and there are none in the new pin. - NOT MEASURED: - `check:sdui-registration-pins`: it needs an `apps/console` build and exits 2 without one. No registration changed here. - `check:published-dist`: its turbo build of the whole workspace, `apps/console` included, was killed by my 300s timeout (exit 124). It was run outside the verify lock by mistake. That is declared to CI. ## Overlap The one `types/src/objectql.ts` hunk here is the one-line docblock edit in the `ObjectKanbanSchema` lane paragraph. objectui#10533 and objectstack-ai#10522, which also edited that file while this PR was being written, have since merged, and this hunk still applies on `main`. At landing, the open PRs that edit `objectql.ts` are objectui#10550, objectstack-ai#10546 and objectstack-ai#8941, and all three are hunk-disjoint from this edit. ## Acceptance notes - After this change, `ColumnWidthConfig` (in `@object-ui/types`, re-exported by `plugin-kanban`, and mirrored by `ColumnWidthConfigSchema`) has no reader in `plugin-kanban`. The ruling named the hook, its exports and its key, not the type, so the type stays. Recorded here only: there is no reproducible defect, and nobody is known to own it next. - The 7664 pin-1 comment still says `KanbanColumn` / `KanbanCard` are consumed by `CardTemplates`. The `CardTemplates` component consumes `CardTemplate`, not those two. That wording predates this change and is kept, because the dispatch limits this file to removing the hook's name. --- _Generated by [Claude Code](https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #7353
Clause-②: yes — the ruling removes a declared member from a published prop type (
ObjectPivotTableis exported from@object-ui/plugin-dashboard) and fromObjectDataTableSchemaon both faces.This carries out ruling 5809008870 (ADR-0049 enforce-or-remove, remove arm):
dataProvider: widgetDatawrites are deleted.objectName.Round 2 applies contract review 5828182277 (FAIL at
35624634f). That review found that the bare deletion left an authoreddataProviderabsorbed silently. It also found that the changeset described an unreleased@object-ui/typesmember as if it were published.What changed
DashboardRenderer, table arm (object-data-tablenode)objectNameanddataProviderobjectNameonlyDashboardGridLayout, table arm (data-tablenode)objectNameanddataProviderobjectNameonlyDashboardGridLayout, pivot arm (pivotnode)objectNameanddataProviderobjectNameonlyObjectPivotTableProps['schema'](prop type of the exportedObjectPivotTable)dataProvider?: { provider: string; object?: string }dataProvider?: never, a tombstone. There is no zod face: neitherobject-pivotnorPivotTableSchemahas a mirror.ObjectDataTableSchema, TS interface (@object-ui/types)dataProvider?: never, a tombstoneObjectDataTableSchema, zod mirror (@object-ui/types/zod)dataProvider: retirementTombstone(...), which refuses the key by name. Its message says to writeobjectName.I measured the released column with
npm packof@object-ui/types@17.6.0and@object-ui/plugin-dashboard@17.6.0(both arelatest), using a word-bounded grep:dataProviderand 0 nameObjectDataTableSchema. The control,DashboardSchema, is found in 4 files. An unbounded grep also finds oneCHANGELOG.mdline, but that is theMetadataProvidersubstring trap.dist/ObjectDataTable.d.tsanddist/ObjectPivotTable.d.tsboth declaredataProvider?, anddist/index.jscarries 3dataProvider:writes.The changeset is
.changeset/7353-retire-widget-dataprovider.md. It declares@object-ui/plugin-dashboardminor with a BREAKING body, and@object-ui/typesminor, per AGENTS.md §9. It is written against released 17.6.0: the published narrowing is plugin-dashboard's, and no released@object-ui/typesvalidator changes verdict.Pre-edit re-grep (H1). I ran a word-bounded
dataProvidergrep over every tracked file at base660d31185. It left out theconst dataProvider = ...providerlocals in calendar, gantt, map, tree and core'srecord-sourcetest, which triage ruled unrelated, and theapps/consolecomment about them. It found:ObjectPivotTable;objectql-union-arms-7363.test.ts.It found no reader, no doc and no README that uses the key.
@objectstack/specdeclares neitherobject-data-tablenordataProvider.objectui#4357 question (H2): the key never reached a DOM attribute
A one-off probe, not committed, rendered all three producer paths for real on base
660d31185. It listed every attribute on every element and spied onconsole.error:dataprovider/data-providerattributesdataprovider)This change does not close any objectui#4357-class leak.
What the zod mirror does with an authored
dataProvider(H3)35624634f(round 1).ObjectDataTableSchemaextends the.passthrough()BaseSchema, so an authoreddataProviderwas kept on the parsed value and checked by nothing, whether well-formed or malformed. The TS face has[key: string]: any, so authoring the key still compiled. That was the same silent no-op the card exists to end.dataProvider, with codeinvalid_type. The message namesobjectName. The refusal also reaches authors throughsafeValidateSchema. An undeclared key is still accepted and kept (control). On the TS faces, authoringdataProvideris a compile error on both carriers.@object-ui/types@17.6.0declares neither the schema nor the key, so no released validator's verdict moves.ObjectDataTableSchemaships for the first time withdataProvideralready refused.Why a tombstone rather than a deletion. I used the repo's retirement discriminator: objectui#5941 and #7526, as amended by objectui#7678, stated on
KanbanColumn.colorinpackages/types/src/complex.ts. A?: nevertombstone is available only on a surviving carrier. On such a carrier it is used when either prong holds:Here:
ObjectDataTableSchemaandObjectPivotTableProps['schema'].objectNameis the key both widgets read.A tombstone refuses a key and reads nothing, so the ruling's "no reader is added" still holds.
Hand-off to the spec lane (
packages/types)Triage note 5548497098 and the ruling put the
packages/typeshalf in this PR instead of a separate card. For thedomain:speclane:ObjectDataTableSchemais still unreleased. ItsdataProvidermember changes from a typed optional object to a retirement tombstone, on the TS face and the zod face.dataProvider, because the key is now refused. The rejection row that probeddataProvider.provideris removed, not respelled, because it pinned the retired typed declaration. The by-name refusal of the key now lives in the retirement pin below. The arm is still probed by name throughsearchable.Pins
packages/plugin-dashboard/src/__tests__/widgetDataProviderRetired-7353.test.tsxSchemaRendererand then renders it with the real renderer. It checks:DashboardRendererobject-data-tablenode, and thedata-tablenode that widget renders next;DashboardGridLayoutdata-tablenode andpivotnode.dataProviderand must keepobjectName(control).objectName(control).ObjectPivotTableProps['schema']['dataProvider']andObjectDataTableProps['schema']['dataProvider']must both be exactlyundefined, which is how a?: nevertombstone reads.objectNamemust staystring | undefined(control).@ts-expect-erroron authoringdataProvideron both prop types, with an undeclared key compiling without a directive (control).ObjectDataTablePropsreads@object-ui/typesthrough the built.d.ts.packages/types/src/__tests__/object-data-table-dataprovider-retired-7353.test.tsundefined(tombstone), withobjectNamelive (control).@ts-expect-erroron authoring both a well-formed and a malformed value, with an undeclared key compiling (control).dataProvider,invalid_type, message namesobjectName), including throughsafeValidateSchema.dataProvidermust validate (controls).Red on the earlier trees, green on the head
Node pins on base
660d31185(round 1). 3 failed and 1 passed. Each failure wasexpected [...] to not include 'dataProvider'.Reverse verification at
511316a02. A trap-guarded script put the five source files back from each earlier tree and kept the pins. Each leg rebuilt@object-ui/typesand ran the three pin files and both type-checks.Leg A:
35624634f(bare deletion). On disk there were 0 tombstones and 0 writes, and the dist had 0 tombstones.safeValidateSchemacases (expected true to be false).TS2344on the tombstoneEqualline, plusTS2578unused directive on both authoring lines.TS2344on bothEquallines, plusTS2578on both authoring lines.Leg B:
660d31185(original base). On disk there were 0 tombstones and 3 writes.dataProvider.providerinstead of at the key:expected [] to have a length of 1), and thesafeValidateSchemacase.TS2344on theEqualline, plusTS2578on the well-formed authoring line. The malformed line was already an error under the typed member, so its directive held.Restore, after each leg and at exit.
git checkout HEAD --on absolute paths. All five files were hash-equal to their HEAD blobs,git diff HEADwas 0 bytes andgit statuswas clean.@object-ui/typeswas rebuilt, and the dist tombstone hits were 1.Gates (at head
511316a02)pnpm exec vitest run --maxWorkers=2 packages/plugin-dashboard/ packages/types/ packages/plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts packages/react/src/hooks/__tests__/navigationOverlayConsumers.onRowClickArity-9357.test.ts:Test Files 363 passed (363),Tests 6442 passed (6442), lockVERDICT command-exit 0.pnpm --filter @object-ui/types --filter @object-ui/plugin-dashboard run type-check: both full chains, includingtsc -p tsconfig.test.json, lockVERDICT command-exit 0. This ran after building the plugin-dashboard dependency closure (12build: Done).check-changeset-presence: "8 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)".check-changeset-no-major,check-changeset-overwrite,check-changeset-fixedandcheck:pending-changeset-literals.check:changeset-claimsis report-only.check:new-line-citations(VERDICT new-cross-file-line-citations: 0 new citation(s)) andcheck:control-bytes.check-vi-mock-specifiers,check-vi-mock-inherit,check-vi-mock-override-shapeandcheck-test-path-roots.check:spec-symbols,check:designer-field-key-parity,check:handler-key-reads,check:element-data-source-declaration,check:unreferenced-sources,check:doc-types,check:doc-example-readers,check:prompt-keys,check:action-forward-parity,check:metadata-write-doors,check-type-check-coverageandcheck-lint-coverage.check:component-surface-parityis report-only, withread-of-tombstoned-key 0.eslint --no-inline-config --format jsonover the 8 touched TS files gave 8 files, 0 errors and 63 warnings. The narrowing rests on three facts:eslint --print-configaccepts all 8 files.eslint.config.jshas noparserOptions.projectorprojectService, so linting is not type-aware and the diff cannot change a judgement on an untouched file.check:readme-exports,check:doc-examplesandcheck-skill-examplesneed the whole package set built.check:sdui-registration-pinsneeds a console build. The diff touches no README, doc or registration, and CI runs them.511316a02. 43 check-runs: 40 success and 3 skipped.Acceptance notes
yes, which the contract review confirmed.DashboardGridLayout'sprovider: 'object'table and pivot widgets never fetch. They becomedata-table/pivotnodes withdata: [], and those renderers read noobjectName. On the base, the probe measuredfindcalled 0 times and the fetched row text absent for both, whileDashboardRendererfetched and rendered the same widget. objectui#7353 does not address this.The dev session for this PR is
session_014mXUNuFomfj24w7s1pZzhN(seatdomain:ui#2,mode:subagent).Generated by Claude Code