Uh oh!
There was an error while loading. Please reload this page.
fix(types): anchor ObjectGalleryProps / ObjectDataTableProps schema to exported schema types that extend BaseSchema (#6576, #6914) - #7355
Merged
Conversation
… to exported schema types that extend BaseSchema (objectui#6576, #6914) Two widget prop types declared their `schema` as a hand-rolled inline object literal with no `BaseSchema` in its ancestry — the only two `Object*Props` in the repo whose `schema` anchored to no named type. Maintainer ruling 2026-08-31 (option A): mint `ObjectGallerySchema` and `ObjectDataTableSchema` in `@object-ui/types`, each `extends BaseSchema`, and anchor both. - `ObjectGalleryProps.schema` (published) WIDENS to every `BaseSchema` member (`visibleWhen` was a compile error on the literal) and NARROWS in one place: `type` is required and pinned to `'object-gallery'`. `data` stays typed — an interface member overrides, it does not intersect. - `ObjectDataTableProps.schema` (not exported) loses the literal's own `[key: string]: any` and declares the two keys the widget read behind casts, `drillDown: DrillDownConfig` and `onRowClick` (objectui#6914); the casts go. A wrong-typed base member and a wrong-shaped `drillDown` are refused now. - Zod mirrors of both under `@object-ui/types/zod`, registered in the parity ledger: `onRowClick` is a `handlerKeyRefusal` runtime-slot arm (the first on an objectql mirror; `KnownDrift` + the 6124 census updated), `drillDown` is seeded in `UnmirroredDeclared` — `DrillDownConfig` has no zod mirror and minting one is outside this ruling. - The objectui#6574 `bind` ratchet entries for both files are removed and the ratchet's prose rewritten: the defect was #6576's, not #5155 / #6269's. - Red-first pins: `widget-schema-anchors-6576.test.ts` (types), and one compile-time pin beside each widget. Two gallery test literals gain the now required `type` key. Unchanged and stated: an unknown key still compiles on both, because `BaseSchema`'s index signature is inherited (objectui#5155, open). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
… `bind` member (objectui#6576) `base-bind-declared.test.ts` scans every TRACKED file for a schema-side `bind?:` re-declaration. The new pin's "this assertion can fail" control was written as the pre-#6576 literal shape — `{ objectName?: string; bind?: string }` — which read as exactly such a re-declaration the moment the file was committed (green while untracked, red on the first post-commit run). The control keeps its job with `className` in that slot; nothing else moves. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Contributor
✅ 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
|
os-litant
marked this pull request as ready for review
September 2, 2026 13:22
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#6576
Fixes#6914
Clause-②: yes — contract review required before release
Maintainer ruling 2026-08-31 (director seat, batch #10, option A, verbatim 「同意」), executed as written: two new exported schema types in
@object-ui/types, eachextends BaseSchema, and the two widget prop types that declared theirschemaas a hand-rolled inline literal are anchored to them. #6914 (the two keys the data-table reads and declared nowhere) is closed in the same stroke, per the erratum:drillDownandonRowClick.Session for this implementation:
https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho(kept in prose because a PR body edit strips the footer form).What changed
packages/types/src/objectql.ts—ObjectGallerySchema(type: 'object-gallery') andObjectDataTableSchema(type: 'object-data-table'), besideObjectKanbanSchema/ObjectChartSchema. Members are the measured read sets of each widget;bindandclassNameare inherited, not restated.ObjectDataTableSchemadeclaresdrillDownasDrillDownConfig(the type it carries onChartSchema/PivotTableSchema) andonRowClickas a function of one row (the type onDataTableSchema). Exported fromindex.ts.packages/types/src/zod/objectql.zod.ts— mirrors of both, exported fromindex.zod.ts.onRowClickis ahandlerKeyRefusalruntime-slot arm (the PR fix(types): the 58on*handler keys declaredz.function()refuse BY NAME (objectui#6124) #7339 shape) — the first handler arm on anobjectqlmirror.drillDownis NOT mirrored:DrillDownConfighas no zod mirror in this package and minting one is a third new export outside the ruling; it is ledgered (see Deviations) and filed as finding(types):DrillDownConfighas no zod mirror —drillDownis declared onChartSchemaandObjectDataTableSchemaand validated on neither #7352.zod-mirror-parity.test.ts— both pairs registered (MIRRORS/Declared),KnownDriftgainsObjectDataTableSchema: onRowClick,UnmirroredDeclaredgains the seedObjectDataTableSchema: drillDown,SPEC_DERIVED_PAIRSgains the gallery pair (it references three spec schemas). Header counts re-read, not restated: 160 pairs (was 158),KnownDrift37 entries / 53 keys (was 36 / 52),UnmirroredDeclared17 entries / 98 keys (was 16 / 97), clean population 142 (was 141),LedgerMismatchpopulation 123 (was 122).RuntimeOnlyDeclaredunchanged at 7 / 24.handler-keys-json-refusal-6124.test.ts— the census covers nine mirror files (objectql joins),RUNTIME_SLOTis 37 (was 36), 59 sites ledgered (was 58), andObjectDataTableSchema.onRowClickkeeps its function type on the TS face.packages/plugin-list/src/ObjectGallery.tsx—ObjectGalleryProps.schema: ObjectGallerySchema(the bare-named-type shapeObjectMapPropsuses for a dedicated schema type); the inline literal, its localbind/className, and two now-unused type imports are gone.packages/plugin-dashboard/src/ObjectDataTable.tsx—ObjectDataTableProps.schema: ObjectDataTableSchema; the literal with its own string index signature is gone, and the two finding(plugin-dashboard): ObjectDataTableProps.schema reads drillDown and onRowClick and declares neither — both absorbed by its [key: string]: any #6914 casts with it (schema.drillDownno longer cast toDrillDownConfig;onRowClickno longer read through a cast toany).base-bind-declared.test.ts— the two fix(types): declarebindon BaseSchema and its zod mirror #6574ALLOWEDratchet entries for these files are removed and the prose rewritten deliberately: the defect was finding(types): two widget prop types declare theirschemaas a hand-rolled inline object with noBaseSchemain its ancestry #6576's, not finding(types): BaseSchema's[key: string]: anyleaves every component schema open, so a "declare the surface" fix can never reject a misspelled TOP-LEVEL key #5155 / finding(types): ObjectViewSchema'stableandformslots declare ZERO properties — the same Omit-under-index-signature collapse as #6151, in property position #6269's (those entries said the opposite); the scan is now what keeps a localbindcopy from returning.ObjectPivotTableis the precedent named.origin/main, GREEN here):packages/types/src/__tests__/widget-schema-anchors-6576.test.ts(type-level pins on the two new types, source-level pins on both widget files, and a read census against each mirror with the one ledgered exception);plugin-list/src/__tests__/ObjectGallery.schemaAnchor-6576.test.tsandplugin-dashboard/src/__tests__/ObjectDataTable.schemaAnchor-6576.test.ts(compile-time: the prop'sschemaequals the schema type, extendsBaseSchema, and each direction of the accept-set move is a literal that must or must not compile).type: 'object-gallery'(ObjectGallery.cells.test.tsx,ObjectGallery.coverValue.test.tsx)..changeset/6576-widget-schema-anchors.md—@object-ui/types: minor,@object-ui/plugin-list: minor,@object-ui/plugin-dashboard: patch.No runtime behaviour changes; both widgets render exactly as before (792 plugin-list and 805 plugin-dashboard tests unchanged and green).
Contract-review pack — accept-set before / after
Real
tsc --noEmitagainst the real prop types, one labelled statement per line, diagnostics mapped by line number (origin/mainat2956d7af8, then this head). Each row is the exact literal assigned to the prop'sschematype. Theorigin/maincolumn repeats the prior report's probe and re-measures it on the same instrument.ObjectGalleryProps.schema— PUBLISHED (plugin-list/src/index.tsxexports the type){ objectName, visibleWhen }(notype)visibleWhendoes not existtypeis missing{ type: 'object-gallery', objectName, visibleWhen }typedoes not exist{ type: 'object-gallery', objectName }typedoes not existtypekey can be spelled{ objectName }(minimal)typeis missingtypeis required (the prior report's G6){ type: 'gallery', objectName }typedoes not exist"gallery"not assignable to"object-gallery"{ [type,] objectName, data: 'not-an-array' }datawould collapse toanyunder aBaseSchemaINTERSECTION;extendsoverrides the member instead, so the widening does not happen{ type, objectName, data: [{ id: 1 }] }typetype){ objectName, visible: 42 }(notype)visibledoes not exist{ type, objectName, visible: 42 }typetypepresent{ type, objectName, bind: 42 }bind?: string)bind?: string){ type, objectName, visibleWhn: 'typo' }type(the unknown key would also have been refused)Net for the published type: WIDENS to every
BaseSchemamember (21 members gained;visibleWhen,visible,id,hidden,disabled,testId,ariaLabel,label,style, … are writable and type-checked), NARROWS in one place (typerequired and pinned to'object-gallery').data,bind,filter,gallery,navigation,grouping,imageField,titleFieldkeep their exact types.ObjectDataTableProps.schema— NOT exported fromplugin-dashboard/src/index.tsx(reaches consumers structurally as the exported component's prop){ type: 'object-data-table', objectName, bogusKey: 1 }{ type, objectName, visible: 42 }{ type, objectName, drillDown: { enabled: true, mode: 'record' } }any)DrillDownConfig){ type, objectName, drillDown: { enabled: 'yes' } }drillDownis refused{ type, objectName, onRowClick: an arrow function of one untyped parameter }rowimplicitlyany(the key resolved toany, so nothing typed the parameter)rowis contextually typed{ type, objectName, onRowClick: 'not-a-function' }{ type, objectName, data: 'not-an-array' }any[]{ type: 'data-table', objectName }type: string)"data-table"not assignable to"object-data-table"{ type: 'object-data-table' }{ objectName }(notype)typemissingtypewas already required){ type, objectName, bind: 42 }bind?: string){ type, objectName, visibleWhen: 'ready' }any)string)Net for the unpublished type: NARROWS (the literal's own index signature is gone, so declared base members and the two #6914 keys are type-checked;
typeis the registry key). In-repo call sites re-checked: everyplugin-dashboardtest andDrillDownDrawer.tsxcompile unchanged — the tests that write other spellings already carryas any.The ceiling, stated plainly
BaseSchemastill carries[key: string]: any(#5155 remains open). Anchoring inherits it, so an UNKNOWN key (visibleWhn,bogusKey) remains ACCEPTED on BOTH prop types after this PR — on the data-table it always was; on the gallery it is new (G5). The ruling accepted that cost; the pins record it as a counter-probe rather than hiding it.Verification (on the committed heads
f84c14c17— the implementation — and the final head named below, tree clean)Every heavy command ran under
scripts/pm/os-verify-lock.sh(slotdev-6576); verdict lines quoted from the tools, not from a bare exit status.turbo run buildfor the three plugins' dependency closures, then everypackages/*:Tasks: 39 successful, 39 total).pnpm --filter @object-ui/types run build→tsc && node ../../scripts/check-dist-completeness.mjs, exit 0;dist/index.d.tscarries both new names.pnpm --filter … run type-check— script echoed for each:@object-ui/types@17.6.0 type-check,@object-ui/plugin-list@17.6.0 type-check,@object-ui/plugin-dashboard@17.6.0 type-check,@object-ui/plugin-view@17.6.0 type-check— 0 errors each (each script istsc --noEmitplus the package's test project, so every pin and both ledgers are compiled).plugin-viewis the other producer ofobject-gallerynodes; it builds a plain node and never passes throughObjectGalleryProps, so nothing there moved.pnpm --filter … run lint(types / plugin-list / plugin-dashboard): 0 errors each (warnings only, pre-existingno-explicit-anyin files that already carried it; the newObjectDataTableSchematranscribes the literal'sanyspellings unchanged).--), on the final heade5b24a3bb:packages/types/→Test Files 88 passed (88),Tests 1434 passed (1434);packages/plugin-list/→Test Files 63 passed (63),Tests 792 passed (792); the six ledger and pin files together (zod-mirror-parity,handler-keys-json-refusal-6124,base-bind-declared,widget-schema-anchors-6576, bothschemaAnchor-6576pins) →Test Files 6 passed (6),Tests 286 passed (286).packages/plugin-dashboard/onf84c14c17(the second commit touches only a plugin-list test file) →Test Files 86 passed (86),Tests 805 passed (805). The second commit exists because the first post-commit run ofbase-bind-declaredwent RED: itsgit grepscan covers tracked files, and the plugin-list pin's synthetic control spelled the pre-finding(types): two widget prop types declare theirschemaas a hand-rolled inline object with noBaseSchemain its ancestry #6576 literal with abindmember — the ratchet did exactly its job; the control now usesclassName.origin/mainwith the pins added and nothing else:tsc -p tsconfig.test.json— types 17 errors (all in the new pin: TS2724 the two names do not exist, TS2344 on every type assertion), plugin-list 9 errors, plugin-dashboard 10 errors (TS2724, TS2344, four TS2578 unused directives where the literal absorbed the wrong value); vitest on the types pin: 6 failed. GREEN here on all three.origin/mainblob, restore proven by blob hash equal toHEADandgit diff HEADempty; atraprestored both files on every exit path): reverting onlyObjectGallery.tsx→ the types pin fails exactly one test namingpackages/plugin-list/src/ObjectGallery.tsx, and plugin-list's test project reports 8 errors inObjectGallery.schemaAnchor-6576.test.ts(plus the two gallery test literals); reverting onlyObjectDataTable.tsx→ the types pin fails exactly two tests namingpackages/plugin-dashboard/src/ObjectDataTable.tsx(anchor shape; the finding(plugin-dashboard): ObjectDataTableProps.schema reads drillDown and onRowClick and declares neither — both absorbed by its [key: string]: any #6914 casts are back), and plugin-dashboard's test project reports 9 errors, all inObjectDataTable.schemaAnchor-6576.test.ts.schema, cast-aware, minus the members the checker resolves on the builtdistdeclaration; both widgets in one run):ObjectGalleryread-not-declared[](10 reads, 28 declared),ObjectDataTableread-not-declared[](7 reads, 29 declared); synthetic control withdrillDownremoved from the declared set reports["drillDown"], so the instrument sees a missing key. Onorigin/mainthe same census read['drillDown','onRowClick']for the data-table (prior report).check-changeset-presence(11 published source files changed, changeset present),check-changeset-no-major(✅ No changeset declares a major bump),check-changeset-fixed(✅ All workspace packages are in the changeset fixed group),check:readme-exports(✅ OK … 406 self-imports judged (406 real, 0 wrong-path, 0 fabricated)— the@object-ui/typesREADME lists no object-* schema types, so no README edit is required by the gate),check:spec-symbols(exit 0 — neither new name is a spec export; controlGalleryConfigSchemafound in the spec api-surface),check:control-bytesOK,check:phantom-depsOK,check:self-importOK,check:esm-specifiersOK,check:published-distOK,check:side-effects-arrayOK,check:element-data-source-declarationOK,check:spec-floorsOK,check:doc-typesOK. NOT MEASURED locally:check:sdui-registration-pins(❌ No console build to weigh at apps/console/dist/assets— a prerequisite, not a verdict; registrations are untouched) andcheck:eager-closure(needs the console bundle). CI owns the repo-wide farm.../objectstack, final file list):governed-surface predicate: 0 of 15 path(s) hit the register→✅ NOT governed.Deviations from the dispatch, declared
drillDownon the zod mirror: ledgered instead of mirrored. The ruling admits either route (「新类型入镜或按台账既有词表申报」); mirroring it needs a pairedDrillDownConfigSchema— a third new export the ruling did not name, whose wiring intoChartSchemawould move that published validator — and an inline unpaired restatement would strip nested keys silently (z.objectdrops unknown keys), the very drift class the ledger exists for. So the new pair is SEEDED inUnmirroredDeclaredwith theChartSchema.drillDownvocabulary (LOCAL), its doc states why this is a seed and not growth on an existing pair, and the repair is filed as finding(types):DrillDownConfighas no zod mirror —drillDownis declared onChartSchemaandObjectDataTableSchemaand validated on neither #7352. The reviewer should weigh this: the ledger's shrink-only rule is written for keys that appear on registered pairs.onRowClickon the mirror is ahandlerKeyRefusalarm (as the dispatch said), which also means the 6124 census and its 36 / 58 pins moved to 37 / 59 and its file list to nine. The alternative — no arm,RuntimeOnlyDeclared(the pre-finding(types): 28 zod-mirror keys are declaredz.function(), which NO JSON document can satisfy — 14 in-repo corpus files author them and are silently invalid #6124 objectql policy group) — was not taken because the 2026-08-30 ruling's rationale (an undeclared key is a silent accept that forwards the value) applies to a new mirror exactly as to an old one.typekey (cellsandcoverValue), not one — the dispatch assumed onlycells. Both are tests; no producer changed.ObjectDataTableProps.schemais the bare named type, notNamedSchema & {…}: with a dedicated schema type there are no widget-only extras to intersect, which is theObjectMapPropsshape;PivotTable/Timelineintersect because their schemas are generic nodes.datacollapses toany) did not hold: it was measured on aBaseSchema & {…}intersection; anextendsmember overrides. Reported as UNCHANGED above and pinned.ObjectQLComponentSchemaunions (TS and zod) andAnyComponentSchemado not include the two new types. Adding them changes whatvalidateSchemaaccepts forobject-gallery/object-data-tablenodes — a third published surface the ruling did not name. Flagged for the reviewer rather than decided.Not in this PR (for the PM)
DrillDownConfighas no zod mirror —drillDownis declared onChartSchemaandObjectDataTableSchemaand validated on neither #7352 —DrillDownConfighas no zod mirror;drillDownis validated on no node (filed, unassigned).dataProvideris declared on two widget schema types and written by two producers, and no renderer reads it #7353 —dataProvideris declared onObjectDataTableSchema(transcribed) andObjectPivotTableProps.schema, written byDashboardRenderer/DashboardGridLayout, read by nothing (filed, unassigned).ObjectTreeProps.schema: any— reported by the prior dev, outside this fence, not re-filed here.content/docs/plugins/plugin-dashboard.mdxandpackages/plugin-dashboard/README.mdonly carry the registry table forobject-data-table(no interface shape); the twoskills/objectui/guidespages name both widgets only in the list ofbind-honouring nodes. Nothing teaches a stale shape, so no docs page is edited or flagged.[key: string]: anyleaves every component schema open, so a "declare the surface" fix can never reject a misspelled TOP-LEVEL key #5155 remains open; the unknown-key ceiling above is its territory.🤖 Generated with Claude Code
https://claude.ai/code/session_01NRRumy89BYdW9ogbcdHTho
Generated by Claude Code