Skip to content

refactor(plugin-dashboard,types): retire the unread widget dataProvider key (objectui#7353) - #10522

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-7353-retire-widget-dataprovider
Sep 25, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-7353-retire-widget-dataprovider

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #7353

Clause-②: yes — the ruling removes a declared member from a published prop type (ObjectPivotTable is exported from @object-ui/plugin-dashboard) and from ObjectDataTableSchema on both faces.

This carries out ruling 5809008870 (ADR-0049 enforce-or-remove, remove arm):

  • The three dataProvider: widgetData writes are deleted.
  • The two typed declarations are replaced by retirement tombstones, which refuse the key and point at objectName.
  • No reader is added.

Round 2 applies contract review 5828182277 (FAIL at 35624634f). That review found that the bare deletion left an authored dataProvider absorbed silently. It also found that the changeset described an unreleased @object-ui/types member as if it were published.

What changed

Site Released 17.6.0 This PR
DashboardRenderer, table arm (object-data-table node) writes objectName and dataProvider writes objectName only
DashboardGridLayout, table arm (data-table node) writes objectName and dataProvider writes objectName only
DashboardGridLayout, pivot arm (pivot node) writes objectName and dataProvider writes objectName only
ObjectPivotTableProps['schema'] (prop type of the exported ObjectPivotTable) dataProvider?: { provider: string; object?: string } dataProvider?: never, a tombstone. There is no zod face: neither object-pivot nor PivotTableSchema has a mirror.
ObjectDataTableSchema, TS interface (@object-ui/types) not released (enters with objectui#6576, changeset still pending) dataProvider?: never, a tombstone
ObjectDataTableSchema, zod mirror (@object-ui/types/zod) not released dataProvider: retirementTombstone(...), which refuses the key by name. Its message says to write objectName.

I measured the released column with npm pack of @object-ui/types@17.6.0 and @object-ui/plugin-dashboard@17.6.0 (both are latest), using a word-bounded grep:

  • types 17.6.0: 0 files name dataProvider and 0 name ObjectDataTableSchema. The control, DashboardSchema, is found in 4 files. An unbounded grep also finds one CHANGELOG.md line, but that is the MetadataProvider substring trap.
  • plugin-dashboard 17.6.0: dist/ObjectDataTable.d.ts and dist/ObjectPivotTable.d.ts both declare dataProvider?, and dist/index.js carries 3 dataProvider: writes.

The changeset is .changeset/7353-retire-widget-dataprovider.md. It declares @object-ui/plugin-dashboard minor with a BREAKING body, and @object-ui/types minor, per AGENTS.md §9. It is written against released 17.6.0: the published narrowing is plugin-dashboard's, and no released @object-ui/types validator changes verdict.

Pre-edit re-grep (H1). I ran a word-bounded dataProvider grep over every tracked file at base 660d31185. It left out the const dataProvider = ...provider locals in calendar, gantt, map, tree and core's record-source test, which triage ruled unrelated, and the apps/console comment about them. It found:

  • the three writes and the three declarations at the sites the dispatch named;
  • one comment in ObjectPivotTable;
  • two fixtures in objectql-union-arms-7363.test.ts.

It found no reader, no doc and no README that uses the key. @objectstack/spec declares neither object-data-table nor dataProvider.

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 on console.error:

Render Elements dataprovider / data-provider attributes React unknown-prop warnings naming it
renderer, table 68 0 0
grid, table 31 0 0
grid, pivot 23 0 0
positive control: a div with the same object spread onto it 2 1 (dataprovider) 1

This change does not close any objectui#4357-class leak.

What the zod mirror does with an authored dataProvider (H3)

  • Bare deletion, measured at 35624634f (round 1). ObjectDataTableSchema extends the .passthrough() BaseSchema, so an authored dataProvider was 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.
  • Tombstone, at this head. A well-formed value and a malformed value are both refused by name, at path dataProvider, with code invalid_type. The message names objectName. The refusal also reaches authors through safeValidateSchema. An undeclared key is still accepted and kept (control). On the TS faces, authoring dataProvider is a compile error on both carriers.
  • Released terms. @object-ui/types@17.6.0 declares neither the schema nor the key, so no released validator's verdict moves. ObjectDataTableSchema ships for the first time with dataProvider already 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.color in packages/types/src/complex.ts. A ?: never tombstone is available only on a surviving carrier. On such a carrier it is used when either prong holds:

  1. it steers authors to a named live replacement key;
  2. docs taught the key as working.

Here:

  • Both carriers survive: ObjectDataTableSchema and ObjectPivotTableProps['schema'].
  • Prong 1 holds: objectName is the key both widgets read.
  • Prong 2 does not hold: no doc, README or CHANGELOG ever taught the key.

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/types half in this PR instead of a separate card. For the domain:spec lane:

  • ObjectDataTableSchema is still unreleased. Its dataProvider member changes from a typed optional object to a retirement tombstone, on the TS face and the zod face.
  • No other member moves.
  • Union-arms fixture triage. The "with its keys" fixture drops dataProvider, because the key is now refused. The rejection row that probed dataProvider.provider is 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 through searchable.

Pins

packages/plugin-dashboard/src/__tests__/widgetDataProviderRetired-7353.test.tsx

  • It records every node handed to SchemaRenderer and then renders it with the real renderer. It checks:
    • the DashboardRenderer object-data-table node, and the data-table node that widget renders next;
    • the DashboardGridLayout data-table node and pivot node.
  • Each node must have no dataProvider and must keep objectName (control).
  • The widget must still fetch through objectName (control).
  • Type level: ObjectPivotTableProps['schema']['dataProvider'] and ObjectDataTableProps['schema']['dataProvider'] must both be exactly undefined, which is how a ?: never tombstone reads. objectName must stay string | undefined (control).
  • @ts-expect-error on authoring dataProvider on both prop types, with an undeclared key compiling without a directive (control).
  • ObjectDataTableProps reads @object-ui/types through the built .d.ts.

packages/types/src/__tests__/object-data-table-dataprovider-retired-7353.test.ts

  • The TS face must read as undefined (tombstone), with objectName live (control).
  • @ts-expect-error on authoring both a well-formed and a malformed value, with an undeclared key compiling (control).
  • The zod face must refuse both a well-formed and a malformed value by name (path dataProvider, invalid_type, message names objectName), including through safeValidateSchema.
  • An undeclared key must still be accepted and kept, and a node without dataProvider must 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 was expected [...] 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/types and 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.

  • vitest: 3 failed, 16 passed. The failures were the zod well-formed, malformed and safeValidateSchema cases (expected true to be false).
  • types type-check: exit 2. TS2344 on the tombstone Equal line, plus TS2578 unused directive on both authoring lines.
  • plugin-dashboard type-check: exit 2. TS2344 on both Equal lines, plus TS2578 on both authoring lines.
  • The controls and the node pins stayed green.

Leg B: 660d31185 (original base). On disk there were 0 tombstones and 3 writes.

  • vitest: 6 failed, 13 passed. The failures were the three node pins, the zod well-formed case (accepted), the zod malformed case (refused at dataProvider.provider instead of at the key: expected [] to have a length of 1), and the safeValidateSchema case.
  • types type-check: exit 2. TS2344 on the Equal line, plus TS2578 on the well-formed authoring line. The malformed line was already an error under the typed member, so its directive held.
  • plugin-dashboard type-check: exit 2 with 4 errors, as in Leg A.
  • The controls stayed green.

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 HEAD was 0 bytes and git status was clean. @object-ui/types was rebuilt, and the dist tombstone hits were 1.

Gates (at head 511316a02)

  • Tests. 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), lock VERDICT command-exit 0.
  • Type-check. pnpm --filter @object-ui/types --filter @object-ui/plugin-dashboard run type-check: both full chains, including tsc -p tsconfig.test.json, lock VERDICT command-exit 0. This ran after building the plugin-dashboard dependency closure (12 build: Done).
  • Changeset gates, exit 0:
    • 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-fixed and check:pending-changeset-literals.
    • check:changeset-claims is report-only.
  • Citation and byte gates, exit 0: check:new-line-citations (VERDICT new-cross-file-line-citations: 0 new citation(s)) and check:control-bytes.
  • Mock and test-root gates, exit 0: check-vi-mock-specifiers, check-vi-mock-inherit, check-vi-mock-override-shape and check-test-path-roots.
  • Types-surface and doc gates, exit 0:
    • 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-coverage and check-lint-coverage.
    • check:component-surface-parity is report-only, with read-of-tombstoned-key 0.
  • Lint, measured over a proven narrowing. eslint --no-inline-config --format json over the 8 touched TS files gave 8 files, 0 errors and 63 warnings. The narrowing rests on three facts:
    1. eslint --print-config accepts all 8 files.
    2. The JSON output has 8 entries.
    3. eslint.config.js has no parserOptions.project or projectService, so linting is not type-aware and the diff cannot change a judgement on an untouched file.
  • NOT MEASURED locally. check:readme-exports, check:doc-examples and check-skill-examples need the whole package set built. check:sdui-registration-pins needs a console build. The diff touches no README, doc or registration, and CI runs them.
  • CI on 511316a02. 43 check-runs: 40 success and 3 skipped.

Acceptance notes

  • Clause-②. The line stays yes, which the contract review confirmed.
  • Out of scope, filed by the seat as objectui#10528 (class a, reproducible with the H2 probe). DashboardGridLayout's provider: 'object' table and pivot widgets never fetch. They become data-table / pivot nodes with data: [], and those renderers read no objectName. On the base, the probe measured find called 0 times and the fetched row text absent for both, while DashboardRenderer fetched and rendered the same widget. objectui#7353 does not address this.

The dev session for this PR is session_014mXUNuFomfj24w7s1pZzhN (seat domain:ui#2, mode:subagent).


Generated by Claude Code

…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>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 28 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5903-objectgantt-declared-keys.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

  • names src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

.changeset/6940-rowactions-boolean-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/7113-chart-data-model.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7200-object-form-section-style-keys-undeclared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7322-object-kanban-group-by-limit.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

.changeset/7352-drill-down-config-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7632-shared-record-source-config.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    That ladder is published contract on both faces — packages/types/src/objectql.ts and its zod mirror both ship .describe() strings naming getDataConfig's order (objectui#6939, maintainer ruling 2026-09-02), pinned by objectql-record-source-refinement-6939.test.ts — and it was hand-copied into five plugin components with no gate holding them together. A change to the ruled order had five edit sites and nothing that noticed a missed one; that is the AGENTS.md #0.1 drift class.

.changeset/7804-objectql-handler-key-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The four plain objectql.ts node faces declare the nine handler keys their registered renderers read (objectui#7804, the objectql.ts slice): ObjectFormSchema.onCancel / .onError / .onOpenChange / .onStepChange / .onSuccess, ObjectGallerySchema.onCardClick / .onRowClick, ObjectGridSchema.onNavigate and ObjectViewSchema.onNavigate.

.changeset/7804-tree-view-handler-slot.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    'runtime-slot' and not 'retired', measured at this key's own channel. 'retired' publishes "no renderer reads this key, so nothing could ever run it" — true of the two siblings already tombstoned on this arm (onSelectChange, onExpandChange) and flatly false here, since the read is live and INVOKED. ⚠️ No in-repo host builds a tree-view node carrying the key: the channel is wired end to end and only the supplier is absent, which is the same shape as ObjectFormSchema.onStepChange in this card's objectql.ts slice and is not evidence of a dead read. The TypeScript declaration is unchanged and still callable, so a programmatic host supplies it exactly as before.

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/7963-alert-dialog-footer-keys-retired.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Nothing else moves. These spellings are overloaded across the tree and every other owner is a live key on a different declaration — FormSchema.cancelLabel, objectql.ts's confirmLabel, plugin-designer's ConfirmDialog React props, plugin-grid's def.confirmLabel, and plugin-form's ModalForm / DrawerForm, which build a local cancelLabel from schema.cancelText. None is an AlertDialogSchema; none is touched, and a pin asserts it. No fixture, catalog schema, example app or doc fence authored any of the three on an alert-dialog node, so no shipped document is stranded.

.changeset/8478-describe-line-addresses.md

.changeset/8735-objectql-mirror-docblocks-not-defaulted.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8767-object-grid-refuses-string-sort.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Migration. Write the array: sort: [{ field: 'name', order: 'desc' }]. Both keys are required. SortConfig.order carries no ? in @object-ui/types (packages/types/src/objectql.ts) and no .optional() in its zod mirror, and the protocol's own reusable SortItemSchema requires order as well — measured: that schema refuses [{ field: 'name' }] with invalid_value at 0.order. Do not omit it: this block's array arm interpolates whatever is present, so an omitted order lowers to $orderby: 'name undefined' today. That is pre-existing behaviour on the arm this change does not touch, and it is filed as a successor card rather than widened into here.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.
  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/8992-user-actions-collapse-and-docblock.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.changeset/9092-inline-locale-declared-face.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    • AppComponentSchema.label (app.ts) - ObjectGridSchema.label and .description (objectql.ts) - PageNodeSchema.aria.ariaLabel (layout.ts)

.changeset/9309-object-gallery-filter-destination-typed.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

.changeset/9511-record-id-is-a-string.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

.changeset/9549-tree-filter-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9550-object-tree-root-barrel.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectQLComponentSchema declares the node types an ObjectQL block may be. Every one of its arms was a named export of this package's root barrel except ObjectTreeSchema, which was declared in objectql.ts, applied by the union, and re-exported by the ./zod barrel (objectui#7917) — while no TypeScript consumer could name it. There is no ./objectql subpath to reach around the barrel: the package's exports map is pinned by packages/types/src/__tests__/package-exports-manifest.test.ts, and the root barrel was the only route to this type.

.changeset/9606-object-kanban-card-title.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

.changeset/9628-kanban-column-collapsed-honoured.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with 09ab32bff (merge-base with origin/main): 8 file(s) changed outside .changeset/, read against 1424 pending declaration(s) that publish a body (2006 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3044.6 KB 3104.5 KB
Main entry chunk (gzip) 147.8 KB 350 KB
Entry file index-CM-Fj-oK.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 544.62KB 130.17KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.86KB 62.25KB
fields (index.js) 256.68KB 65.01KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.22KB 14.56KB
plugin-charts (index.js) 74.95KB 20.88KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.52KB 35.38KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.25KB 61.40KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 146.50KB 37.51KB
plugin-gantt (index.js) 168.43KB 41.50KB
plugin-grid (index.js) 215.49KB 58.91KB
plugin-kanban (index.js) 49.30KB 15.39KB
plugin-list (index.js) 114.55KB 28.29KB
plugin-map (index.js) 21.83KB 7.07KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.64KB 8.94KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 88.00KB 21.97KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 114.58KB 37.60KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 35624634f76204470fd592787fb748d904f3d62f

① Derived judgments

Head and base. git rev-parse refs/review/pr-10522 = 35624634f…; merge-base with refs/review/main = 660d31185, the base the PR body names. Two commits on the branch, 9 files, matching the REST file list.

Writes, declarations, readers. My own census, word-bounded git grep -nE "(^|[^A-Za-z0-9_])dataProvider([^A-Za-z0-9_]|$)" over the whole tracked tree:

  • Base 660d31185, scope packages/plugin-dashboard/src packages/types/src: 9 hits = 3 writes (DashboardGridLayout.tsx:386,:425, DashboardRenderer.tsx:790), 3 declarations (ObjectPivotTable.tsx:44, objectql.ts:4649, objectql.zod.ts:2594), 1 comment, 2 fixture rows. Identical to the dev's H1.
  • Head, same scope, excluding the two new pins: 3 hits, all comments in objectql-union-arms-7363.test.ts. Whole tree at head: 13 files, all of them the calendar/gantt/map/tree const dataProvider = dataConfig?.provider locals and their tests, one more same-shaped local in packages/core/src/utils/__tests__/record-source.behaviourNeutrality-7627.test.ts:75 (not listed in the PR body's H1 narration, harmless), a console comment, the changeset and the pins. Reader-shaped grep (\.dataProvider\b|dataProvider\?\.|destructure) outside tests: 0 hits. Controls lit: MetadataProvider 201 files, objectName in plugin-dashboard/src 50 files. No RUNTIME SLOT row names the key in zod-mirror-parity.test.ts (45 rows; the data-table ones are col.cell callbacks). All three writes and all three declarations are gone; no reader added.

H3 reading is correct, measured. BaseSchemaCore is .passthrough() (base.zod.ts:486); TS BaseSchema carries [key: string]: any (base.ts:592). Scratch harness with zod 4.6.5 (repo range ^4.4.3), mirroring BaseSchema.extend({...}) and applying .omit({ dataProvider: true }) as the diff does: BEFORE malformed {provider: 42} RED at dataProvider.provider:invalid_type; AFTER GREEN with dataProvider kept on the parsed value; undeclared-key control GREEN on both. The dev's pin asserts exactly this.

Is the widening a problem, and was a tombstone owed? This is the material finding. The repo's ADR-0049 retirement pattern is ?: never on the TS face plus retirementTombstone(...) on the zod face: retirementTombstone( in 54 files under packages/types/src, ?: never in 80, and every recent unread-key retirement on a BaseSchema carrier took that route (.changeset/10387-header-bar-unread-keys-retired.md, 6121-retire-report-data-source.md, 8178-…). The amended discriminator (objectui#7678, stated at complex.ts:171-193): a ?: never tombstone is available only on a surviving carrier and is used when either prong holds, (1) it steers authors to a named live replacement key, or (2) docs taught the key as working. Both carriers survive (ObjectDataTableSchema, ObjectPivotTableProps['schema']). Prong 1 holds by the letter: objectName is the key the widgets read, and the card, the ruling and the changeset all say so. Prong 2 does not (0 hits in CHANGELOGs, content/, READMEs; control objectName in plugin-dashboard CHANGELOG 3). The #8178 pin records why deletion is the wrong route on this carrier: "a DELETED optional member is absorbed silently at any value … Deletion would therefore have left exactly the silent no-op the retirement exists to end." That is the outcome my harness measures, and the harness also shows the tombstone shape refusing both well-formed and malformed values by name while leaving unknown keys alone.

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 (dashboard-title-retired-declaration.test.ts, #7623) is not on point: that one had an explicit dispatch line "do not invent a tombstone", the deletion "changes no parse verdict at all", and the spec's strict DashboardSchema already refuses the key. Here the parse verdict moves toward acceptance, and per the PR's own H1 the spec declares neither object-data-table nor dataProvider, so nothing upstream refuses it. Net: the declaration that invited authors is gone, but the card's "Why it matters" defect (an author writes it and nothing happens) is left in place, now with less checking than before, which runs against AGENTS.md #0.1 ("have it rejected at authoring/publish"). Flagged as a route omission the ruling seat must settle or the PR must close with the tombstone.

Fixture triage. Honest. The removed rejection row ['object-data-table','dataProvider.provider',…] pinned only the retired declaration; the arm is still probed by name through searchable; the "with its keys" fixture keeps objectName, searchable, pagination. Nothing else lost.

H2 plausibility. SchemaRenderer.tsx:1973 spreads ...componentProps as React props, so the key did reach the component as a prop. DataTableRenderer is ({ schema }: { schema: DataTableSchema }) (data-table.tsx:715) with 0 rest-forwards and 0 objectName/dataProvider reads; PivotTable destructures seven named props (PivotTable.tsx:169); ObjectDataTable hands its node on as schema (ObjectDataTable.tsx:1037-1054). No path forwards unknown props to a DOM element, so the probe's 0/0/0 reading is plausible from source.

② Semver level

minor on both packages is correct for the repo: AGENTS.md §9 版本号策略 line 271 says objectui's own breaking changes are marked minor with the breaking semantics in prose, check-changeset-no-major enforces it, and both packages sit in the 40-member fixed group of .changeset/config.json. CI "Changeset Bump Policy", "Changeset Declaration", "Changeset Fixed Group Check" all success.

The prose is not true sentence by sentence. "Both removals narrow a published declaration" is false for @object-ui/types: npm pack @object-ui/types@latest gives 17.6.0 (released 2026-08-20, commit 59f61cfb8), whose dist has 0 files naming dataProvider and 0 naming ObjectDataTableSchema (control DashboardSchema 4 files). ObjectDataTableSchema entered objectql.ts on 2026-09-02 (4ca30d044, #7355) and its changeset 6576-widget-schema-anchors.md is still pending. So on the types face this PR edits an unreleased member, and the "Validation, measured … used to be refused at dataProvider.provider and now passes" paragraph, read as a release note, tells consumers a released validator's accept set moved when no released @object-ui/types ever declared the key. The published narrowing is real only on @object-ui/plugin-dashboard@17.6.0: dist/ObjectPivotTable.d.ts:6 and dist/ObjectDataTable.d.ts:6 both declare dataProvider?, and dist/index.js carries the three writes (lines 1747, 2165, 2191). The index-signature sentence ("keeps compiling … now sees any") and the DOM sentence hold.

③ Boundary flags

  • Clause-② line. Arms in use at head: no 11, yes 7, yes (widening) 1, yes (narrowing) 1; not defined in objectui AGENTS.md or docs. yes is correct and sufficient: the plugin-dashboard published prop types narrow, while the types face is a pre-release edit and its zod accept set widens, so a single parenthetical arm would misdescribe the shape. Keep yes; not a blocker.
  • Class-a finding is real at source. DashboardGridLayout.tsx:381-391 and :419-427 emit data-table / pivot nodes with data: [] and objectName under the comment "pass through object config for async data loading"; DataTableRenderer has 0 objectName reads and PivotTable.tsx:36-38 says PivotTableSchema declares no objectName; DashboardRenderer.tsx:831 calls these "two live branches". Out of scope here; worth its own card.
  • CI on 35624634f: 42 check-runs: 27 success (incl. Build & E2E, Test (dist pins), all changeset gates, Line Citation Gate, README Export Check, Skill Example Check), 3 skipped (coverage, dependabot), 12 in_progress: Lint, Type Check, Spec Main Shape Gate, Build Docs, Test shards 1/8 through 8/8. Nothing failed. PR is a draft; mergeable_state unknown.
  • Should stop landing: (1) the tombstone omission above, until the ruling seat states outright deletion on this carrier in words or the PR adds ?: never on ObjectDataTableSchema and ObjectPivotTableProps['schema'] plus retirementTombstone('… write objectName') on the zod mirror with the pins flipped; (2) the changeset sentence "Both removals narrow a published declaration" and the validation paragraph must be corrected to say the types half edits an unreleased member and no released validator changes verdict.

Implemented-by: claude/issue-7353-retire-widget-dataprovider
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

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>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3044.7 KB 3104.5 KB
Main entry chunk (gzip) 147.8 KB 350 KB
Entry file index-DV-IU9uT.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 544.97KB 130.34KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.86KB 62.25KB
fields (index.js) 256.68KB 65.01KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.38KB 14.60KB
plugin-charts (index.js) 74.95KB 20.88KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.52KB 35.38KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.25KB 61.40KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 146.50KB 37.51KB
plugin-gantt (index.js) 169.37KB 41.83KB
plugin-grid (index.js) 215.49KB 58.91KB
plugin-kanban (index.js) 49.30KB 15.39KB
plugin-list (index.js) 114.55KB 28.29KB
plugin-map (index.js) 23.82KB 7.42KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.64KB 8.94KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 88.00KB 21.97KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 114.58KB 37.60KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 511316a02ac151a8ca90dabcaf1e4f180afeac7b

① Derived judgments

Head and base. git rev-parse refs/review/pr-10522 = 511316a02… (re-checked at the end of the run, unchanged); merge-base with refs/review/main = 660d31185; 3 commits; 9 files, identical to the REST file list (pulls/10522/files: 9). Round delta 35624634f..511316a02: 7 files, the two producer files untouched.

FAIL item 1, tombstone omission: discharged, each part measured.

  • TS faces: packages/types/src/objectql.ts:4667 dataProvider?: never and packages/plugin-dashboard/src/ObjectPivotTable.tsx:63 dataProvider?: never, both under a retirement JSDoc that names objectui#7353, ruling 5809008870, prong 1 of the discriminator and objectName, both @deprecated, the same shape as the KanbanColumn.color precedent at complex.ts:171-193.
  • Zod mirror: packages/types/src/zod/objectql.zod.ts:2598 dataProvider: retirementTombstone('REFUSED (objectui#7353, ADR-0049) — … Write objectName …'), the helper imported at line 45 and called in the same form as the 12 other calls in that file (git grep -l "retirementTombstone(" -- packages/types/src = 54 files). The message contains objectName.
  • No zod face for the pivot, verified: git grep -nEi "PivotTable|object-pivot|'pivot'" -- packages/types/src/zod = 1 hit, a comment at data-display.zod.ts:801 stating PivotTableSchema "has no mirror of its own"; lit control ObjectDataTableSchema = BaseSchema.extend at objectql.zod.ts:2595. Tree-wide, no file that names object-pivot imports a zod module (0).
  • Writes and readers: (^|[^A-Za-z0-9_])dataProvider\s*: over packages/plugin-dashboard/src excluding tests = 0 at head, 3 at base 660d31185 (DashboardGridLayout.tsx:386,:425, DashboardRenderer.tsx:790). Reader-shaped grep (.dataProvider, dataProvider?., destructure) over packages/*/src excluding tests = 0; lit control, the same shape for objectName in plugin-dashboard = 6 files (ObjectDataTable 16 hits, ObjectPivotTable 13). Whole-tree word-bounded census at head = 16 files: outside the changeset and the two pins, only the calendar/gantt/map/tree/core-test const dataProvider = …provider locals, one console comment, two union-arms comments and the three tombstone lines.
  • Harness (scratch git archive of head's packages/types/src, esbuild bundle, zod 4.6.5, spec 17.4.0): well-formed {provider:'object',object:'contact'} refused, 1 issue at path dataProvider, code invalid_type, message names objectName; malformed {provider:42} refused identically at the key, not at dataProvider.provider; undeclared zzUndeclared7353: {provider:42} accepted and kept; plain node accepted; safeValidateSchema reports path dataProvider; lit control searchable:'yes' refused at searchable; dataProvider: undefined accepted.

Pins. object-data-table-dataprovider-retired-7353.test.ts: Equal pin that the TS member reads as undefined plus an objectName twin reading string | undefined; @ts-expect-error on a well-formed and a malformed literal with an undeclared-key literal carrying no directive; zod it.each for both values asserting one issue at the key, invalid_type, message contains objectName; the safeValidateSchema door; two controls. widgetDataProviderRetired-7353.test.tsx: the same Equal and @ts-expect-error pins on ObjectPivotTableProps['schema'] and ObjectDataTableProps['schema'] with objectName twins and undeclared controls. These assert exactly what round 1 asked. They are real enforcement: both packages' type-check scripts chain tsc -p tsconfig.test.json (types package.json:69, plugin-dashboard :19), plugin-dashboard's paths: {} reads the built .d.ts, and the root tsconfig sets no exactOptionalPropertyTypes, so ?: never reads as undefined and a deletion would read as any. Round-1 node pins intact: git diff 35624634f refs/review/pr-10522 on the plugin-dashboard pin touches only the header comment and lines 170 onward; the three node cases (renderer table, grid table, grid pivot, with objectName and find controls) are byte-identical.

The 7200 sentence and the ruling. .changeset/7200-object-form-section-style-keys-undeclared.md and its pin object-form-section-style-keys-undeclared.test.ts:31-43 state their own scope: "The house pattern for a retired key on a zod-mirrored, NON-strict surface is a tombstone", and deletion won there for two reasons that both fail here: (a) ObjectFormSection has no zod mirror and "carries no index signature and extends nothing, so an annotated object literal is subject to excess-property checking", i.e. deletion already refuses at the authoring site; (b) that ruling's rationale was specifically "do not declare". Here ObjectDataTableSchema has a parse door (mirror at objectql.zod.ts:2595) and both carriers extend BaseSchema (objectql.ts:4645, data-display.ts:2314) whose [key: string]: any and .passthrough() absorb a deleted member, so on the pivot carrier the tombstone is the only refusal that exists. No repo text makes a tombstone contradict "delete … every declaration"; the standing discriminator in complex.ts licenses it on a surviving carrier under prong 1, and precedent remove-arm changesets (8178-ai-schemas-retire-zero-read-members.md:52-58, 6121-retire-report-data-source.md:16-21, 10387-header-bar-unread-keys-retired.md:16) took the same route. My reading: the ruling's substance (three writes gone, no authorable declaration survives, no reader) is met and the key remains in the .d.ts only as a named refusal. The ruling seat does not need to be asked: round 1 offered this route as the alternative to asking, and the seat's rework instruction adopted it. Residual, not blocking: if the ruling seat wanted a literally bare .d.ts it would have to say so against the discriminator.

② Semver level

minor on both packages with BREAKING prose only on @object-ui/plugin-dashboard is correct under AGENTS.md §9 版本号策略 ("objectui 自身的破坏性变更也标 minor(在正文里写清 breaking 语义即可)", enforced by check-changeset-no-major). CI: Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report all success.

FAIL item 2 discharged; the rewritten .changeset/7353-retire-widget-dataprovider.md read against the tarballs (npm pack, both latest = 17.6.0):

  • "Released 17.6.0 declares neither ObjectDataTableSchema nor dataProvider": types tarball, word-bounded dataProvider = 0 files, ObjectDataTableSchema = 0, control DashboardSchema = 4; the one unbounded hit is CHANGELOG.md:556 MetadataProvider. "new after 17.6.0 (objectui#6576)": .changeset/6576-widget-schema-anchors.md still pending at head. "no released validator's verdict" moves: true, and the mirror is exported at index.zod.ts:324 so "in @object-ui/types/zod" is true.
  • plugin-dashboard "In 17.6.0, the schema prop types of ObjectPivotTable and ObjectDataTable both declare dataProvider?: { provider: string; object?: string }": dist/ObjectPivotTable.d.ts:6 and dist/ObjectDataTable.d.ts:6, exactly that shape; ObjectPivotTable exported at dist/index.d.ts:14. "no longer writes … three": dist/index.js writes at 1747, 2165, 2191, 0 at head. "no zod schema" for the pivot: verified above. "Both of these types extend BaseSchema": both do. The refusal-any-value and passthrough sentences match the harness. The DOM paragraph restates the dev's uncommitted probe and is not independently measurable here; round 1's source reading makes it plausible.
  • One imprecision, non-blocking: "Both dashboard surfaces build a node for the table and pivot widgets" reads as each building both, but DashboardRenderer's pivot arm returns LEGACY_RETIRED_WIDGET_SCHEMA (DashboardRenderer.tsx:819-835); only the grid builds a pivot node. The next bullet names each producer's nodes correctly, so the CHANGELOG reader is not misled about the narrowing.

③ Boundary flags

  • CI on 511316a02: 43 check-runs, 40 success (Lint, Type Check, Test, Test shards 1/8 to 8/8, Test (dist pins), Build & E2E, Spec Main Shape Gate, Line Citation Gate, README Export Check, Skill Example Check, Doc Snippet Type Check, all four changeset gates, Governed Surface Queue Guard, Bundle Analysis), 3 skipped (coverage shard, coverage, dependabot). Nothing failed. mergeable_state clean.
  • PR body vs diff: the file table, the npm counts (0/0, control 4, 2 d.ts files, 3 writes), the H1 census, the pin descriptions, the gate list and the "43: 40 success, 3 skipped" line all reproduce. The reverse-verification counts (Leg A 3 failed of 19, Leg B 6 failed of 19, TS2344 on Equal lines, TS2578 on directive lines) are consistent with the pin shapes and were not re-run. "@objectstack/spec declares neither": spec 17.4.0 dist, object-data-table 0 files, word-bounded dataProvider 0, control kanban 46. The out-of-scope pointer objectui#10528 exists (open, filed 2026-09-25T06:42Z by the fleet bot). Clause-② stays yes, as round 1 concluded. The body says "two typed declarations" become tombstones while its table lists three faces; the mirror is the third, harmless.
  • Landing: the PR is still draft: true; it must be marked ready before the squash-merge. That is process state, not a defect in the change. Nothing in ①–③ should stop the PR from landing.

Implemented-by: claude/issue-7353-retire-widget-dataprovider
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 25, 2026 07:46
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 2ceb43a Sep 25, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-7353-retire-widget-dataprovider branch September 25, 2026 07:58
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
… 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding(plugin-dashboard): dataProvider is declared on two widget schema types and written by two producers, and no renderer reads it

2 participants