Repository navigation
feat(types): a page list-view node is judged in its properties bag — data / type — and objectName / viewType are refused by name (objectui#12670) - #12713
Conversation
…ata / type, with objectName / viewType refused by name (objectui#12670) The authored `list-view` arm of `AnyComponentSchema` is now `ListViewBlockSchema`, built on the `ObjectChartBlockSchema` construct: its `properties` bag is the flat `ListViewSchema` mirror's own members by reference (the spec has no `ComponentPropsMap['list-view']` row), with the list kind as the spec's own `type` and `objectName` / `viewType` refused by name, flat or in the bag, naming `properties.data` and `properties.type`. The record source is `properties.data` or the node's `dataSource.object`. `ListViewSchema` leaves the zod ObjectQL union and stays the `ListView` component's props. Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4 Co-authored-by: Claude <noreply@anthropic.com>
…gs re-spelled onto the page node (objectui#12670) A new pin, `list-view-properties-bag-12670.test.ts`, holds the four acceptance cases on both faces (the ruled node accepted; `objectName` / `viewType` refused by name, flat or in the bag, FROM -> TO; the record source refused at `properties.data`; `dataSource.object` alone accepted), the bag's members by reference, the spec's two list view checks in the bag, and that `ListViewSchema` stays the `ListView` component's props. The pins that handed the component spelling to `safeValidateSchema` / `StrictAnyComponentSchema` now hand those faces the page spelling, through a test-only helper (`list-view-page-node.ts`); their mirror legs are unchanged. The census pins (union arms, flat-prop population, responsive styles, grouping, mirror parity, import boundary, bag carriers) count the new arm. Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4 Co-authored-by: Claude <noreply@anthropic.com>
…arm; plugin-list's read-door pins re-spelled (objectui#12670) The two `plugin-list` pins that judged a list view at the read door (`safeValidateSchema`) now hand it the page spelling of the same fixture; the render halves still render the `ListView` component's props. Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4 Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: ① Derived judgmentsWhat
The page arm against what PR objectui#12668's renderer reads (
The bag's members.
Flat-prop refusals at the node level: the five handler keys.
The spec refinements in the bag, and the objectui#10327 controls.
The census: 16
Check-runs on the head (re-read at 2026-10-16T14:58Z): 36 runs, 33 ② Semver level
③ Boundary flags
Implemented-by: VERDICT: FAIL FAIL on this head for two reasons, neither of them the design: ② the changeset omits the precedent sentence naming |
…12670-list-view-page-face Brings in objectui#12099's renderer half of ruling C (5c0846e) and objectui#12666's page view-data detach (15d8ca6). The two test files both sides edited (imported-defaults-8317, spec-object-refinements-7715) auto-merged, and each keeps both intents. Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4 Co-authored-by: Claude <noreply@anthropic.com>
…hat the face judges it (objectui#12670) The strict authoring face accepts the page spelling of a `list-view` node, so `check:doc-json` reported the fence's `doc-json: fragment` declaration as stale. The marker is gone and the fence is judged whole; the paragraph that said `objectui validate` does not judge the page spelling now says what it judges. The kind stays in prose. Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4 Co-authored-by: Claude <noreply@anthropic.com>
… changeset, and list every exported block node type (objectui#12670) The changeset now spells what the precedent entries spelled for the grid, form, map, gantt and chart arms: `ListViewBlockSchema` reaches `AnyComponentSchema` through `ObjectQLPublicBlockComponentSchema`, and `ListViewSchema` leaves `ObjectQLComponentSchema`, so a direct `ObjectQLComponentSchema.safeParse` of a `list-view` node fails on the discriminator. The BREAKING list names that consumer and where to parse instead. Frontmatter unchanged. The types README's by-name list of ObjectQL block node types gains `ListViewBlockNode`, and the two it already omitted, `ObjectPivotBlockNode` and `EmbeddableFormBlockNode`. Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4 Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: ① Derived judgmentsThe head. Six commits on What
The page arm against the renderer that is ON
The bag by reference.
The census re-spells (16 The three new commits.
Check-runs on the head (re-read 2026-10-16T15:52Z): 36 runs, 33 ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS PASS on this head. The three edits the earlier FAIL named are on it and each is judged RIGHT: the merge keeps both intents in the two shared tests and changes nothing else in this PR's diff; the README fence is a whole document the strict face accepts and every sentence of the new paragraph is true of the face in the diff; the changeset names |
席位核对 — ACCEPT ·
|
Fixes #12670
Clause-②: yes (narrowing)
Ruling: objectstack-ai/objectstack#22444, comment
6100463199(ruling C). Scope: triage6216264566on objectui#12670, option A under C as it stands. Claim: comment6216538732, re-stated as6218329226for the merge round. Written by the dispatched os-dev of thedomain:uiseat 3, sessionsession_01Vk15bz8xHtKGUfXfCm16h4. The renderer half of the same ruling is PR objectui#12668 (objectui#12099); it landed onmainas5c0846e, and this branch mergedmainafter it (merge commitbadde80), so the landing head carries both halves.What changes
packages/types/src/zod/objectql.zod.ts).ListViewBlockSchemais thelist-viewarm ofAnyComponentSchema, inObjectQLPublicBlockComponentSchemabeside the other authored block arms.ListViewSchemaleftObjectQLComponentSchema, the wayObjectMapSchema,ObjectGridSchemaandObjectChartSchemaleft it, and stays exported, unchanged, as theListViewcomponent's props.ListViewPropsBag, module-private). The installed@objectstack/spec18.0.0-next.2 has noComponentPropsMap['list-view']row, so the bag is built the wayobject-chart's is: the flatListViewSchemamirror's own members, by reference, each the same schema object (z.looseObject(ListViewSchema.shape)less the node-level keys). Those members are the spec list view's own (specFieldsExceptover the spec'sListViewSchema) plus objectui's overlay, so one list view has one set of property names wherever it is embedded. Three members differ, each the ruling's:typeis the list kind, the spec's own view-kind enum (default stripped);objectNameandviewTypeare refused by name (aliasKeyRefusal), namingproperties.dataandproperties.type.checkListViewCalendarVisualization(as on the flat mirror) andcheckListViewChartBinding, which the flat mirror cannot attach because its kind isviewType. objectui's own dataset-chart filter refusal (objectui#10327) is read in the bag too, with the bag'stypeas the kind.type: 'list-view'+NODE_ENVELOPE+flatPropRefusalsover the bag (every list view member written flat is refused by name towardproperties.KEY; a retired member,objectName/viewType, keeps its own retirement there, so the message is the same flat or in the bag) + the mirror'sdataSourcebinding by reference + the fivehandlerKeyRefusalruntime slotsListViewreads, spelled as the mirror spells them + the objectui#9256body/childrenrefusals.requireRecordSource('list-view', ['data'], 'properties'):properties.data, or the node's non-emptydataSource.object(the registration iselementDataSourceBlock-wrapped). OtherwiseRECORD_SOURCE_REQUIREDatproperties.data, naming both.authoring-nodes.ts,index.ts).ListViewBlockNode = ObjectQLPublicBlockNodeOf('list-view'), exported, its bag closed byClosedBag. It joinsAuthoringNodethroughObjectQLPublicBlockNode. The TypeScriptListViewSchemaand both TypeScript unions (AnySchema,ObjectQLComponentSchema) are unchanged; one doc comment on the latter now counts six zod arms.packages/types/src/zod/README.md: theListViewSchemasection names the page arm, with the ruled node as a JSON example, and the ObjectQL public block section describesListViewBlockSchema..changeset/12670-list-view-page-face.md,@object-ui/types: minor, with the breaking part for page nodes in the old spelling written out (objectui AGENTS.md §9). It namesObjectQLComponentSchema's lostlist-viewarm in the precedent's spelling, with a BREAKING line for code that parses with it directly.packages/plugin-list/README.md). The page fence'sdoc-json: fragmentdeclaration is deleted, socheck:doc-jsonjudges the fence whole and accepts it. The paragraph that saidobjectui validatedoes not judge the page spelling now says what it judges. The kind stays in prose.packages/types/README.md). The by-name list of ObjectQL block node types gainsListViewBlockNode,ObjectPivotBlockNodeandEmbeddableFormBlockNode, so it matches the 11 arms ofObjectQLPublicBlockComponentSchema.Contract evidence (Clause-②)
What
objectui validate/StrictAnyComponentSchemaandsafeValidateSchemaanswer, measured on the BUILTdistof@object-ui/types, atmaindcd1041and at this branch:properties: { data: { provider: 'object', object }, type: 'kanban', kanban }RECORD_SOURCE_REQUIREDatobjectNameunrecognized_keys(properties) +RECORD_SOURCE_REQUIREDobjectNameinvalid_typeatobjectName(objectName→properties.data) +RECORD_SOURCE_REQUIREDatproperties.dataproperties.objectNameRECORD_SOURCE_REQUIREDatobjectNameunrecognized_keys+RECORD_SOURCE_REQUIREDinvalid_typeatproperties.objectName(objectName→properties.data) +RECORD_SOURCE_REQUIREDatproperties.dataproperties.viewTypebesideproperties.dataRECORD_SOURCE_REQUIREDatobjectNameunrecognized_keys+RECORD_SOURCE_REQUIREDinvalid_typeatproperties.viewType(viewType→properties.type)viewTypebeside the ruled bagRECORD_SOURCE_REQUIREDatobjectNameunrecognized_keys+RECORD_SOURCE_REQUIREDinvalid_typeatviewType(viewType→properties.type)properties: { columns }RECORD_SOURCE_REQUIREDatobjectNameunrecognized_keys+RECORD_SOURCE_REQUIREDRECORD_SOURCE_REQUIREDatproperties.datadataSource: { object }aloneobjectName+viewTypeinvalid_typeatobjectNameand atviewType+RECORD_SOURCE_REQUIREDSo the accept set WIDENS by the ruled page spelling and NARROWS by the retired one, flat or in the bag, and by every other list view prop written flat (the spec's own page component already refuses those as unrecognized keys: measured on
PageComponentSchemaforobjectName,viewType,columns,name).objectui validate/objectui checkjudge withStrictAnyComponentSchema(validateAuthoredDocument); the CLI's own pins (packages/cli/src/__tests__/, 29 files) are green on this build.What the built
.d.tsgain or lose (base build atdcd1041against this branch's build; the same 78.d.tsfiles on both sides):zod/objectql.zod.d.ts: gainsListViewBlockSchema.ObjectQLComponentSchemaInferred's arms go fromobject-view,object-tree,object-calendar,object-kanban,object-gallery,object-data-table,list-viewto the first six;ObjectQLPublicBlockComponentSchemaInferredgainslist-viewas its eleventh. Every other declaration there,ListViewSchemaincluded, is unchanged once comments are stripped and union member order is ignored.zod/index.zod.d.ts: re-exportsListViewBlockSchema; the inferred types ofvalidateSchema/safeValidateSchema/ the unions now carry the bag arm forlist-view.authoring-nodes.d.ts: gainsListViewBlockNode;index.d.tsre-exports it.objectql.d.ts: one doc comment.zod/*.d.tsdiffer byte-wise only by the order the compiler printed union members and by where it re-attached JSDoc comments (a normalised comparison, union members sorted, says identical).@object-ui/typesfromdist(@object-ui/plugin-list'stsconfig.jsonreplaces the rootpaths): a scratch file typing{ type: 'list-view', properties: { objectName: 'deal' } }asListViewBlockNodefailedtscat that key (TS2322: Type 'string' is not assignable to type 'undefined'), the ruled node beside it compiled; the file was removed andgit statusread clean.The PM's mechanism hypotheses, measured
dcd1041ListViewSchemaisBaseSchema+ spec fields +type: z.literal('list-view'),dataSource,objectName,viewType, closed byrequireRecordSource('list-view', ['objectName']), noproperties. The authored arms are wired as described (ObjectQLPublicBlockComponentSchema;ObjectQLPublicBlockNodeOf), and the new arm is wired the same way. Where it deviates: there is no row, so the bag followsObjectChartBlockSchema(the flat mirror's members) rather thanObjectMapBlockSchema(a row), and the flat refusals use the sharedflatPropRefusals(asobject-gridandobject-pivotdo) rather than an own map.ComponentPropsMapat 18.0.0-next.2 has 59 rows, nonelist-view. The spec publishesListViewSchema(51 members, strict,columnsrequired, a kanban block'scolumnsrequired, two object-level checks: the calendar visualization and the chart binding) andObjectListViewSchema. The bag is the flat mirror's members by reference (theobject-chartprecedent). ⛔ Not the spec'sListViewSchemaverbatim: it requirescolumns, so the ruled node would be refused, which is what ruling C's declined option A says of that row.mainthelist-viewregistration's renderer isListViewBlock = elementDataSourceBlock(…), so a non-emptydataSource.objectcounts, on the shareddataSourceSuppliesObject.ListViewSchema, so no value typed as either changes;ObjectQLPublicBlockNode/AuthoringNodeonly gain a member. Non-test code narrowing a node on thelist-viewliteral: 0 (git grep). Type-checked against the rebuiltdist:@object-ui/plugin-list,@object-ui/plugin-view,@object-ui/react,@object-ui/cli, 4 of 4 green, plus@object-ui/typesitself (all three legs). The app-shell and console closures (the whole workspace) are left to CI'sType Check.Census: what the union judges as a
list-viewnode (hypothesis 4)Instrument:
git grepfor alist-viewliteral (185 files outside changelogs), narrowed to files that also name a union face (safeValidateSchema,validateSchema,AnyComponentSchema,StrictAnyComponentSchema, …), then a run ofpackages/typesagainst the new arm to find every pin the move reddens. Positive control:spec-object-refinements-7715.test.ts, known to hand a flat list view tosafeValidateSchema(hit, and red before the re-spell).content/docs/guide/data-source.md,content/docs/utilities/data-objectstack.mdxandpackages/plugin-list/README.md's page-binding section, each{ "type": "list-view", "dataSource": { … } }. Accepted before and after (check:doc-jsongreen); nothing to convert. Since the merge,packages/plugin-list/README.md's page fence (PR objectui#12668's) is accepted too, and judged whole.ListViewcomponent schemas (not judged by the union): the four non-testtype: 'list-view'literals, re-measured ondcd1041:InterfaceListPage.tsxandObjectDataPage.tsxin@object-ui/app-shell,ObjectView.tsxin@object-ui/plugin-view, a doc comment inobjectql.zod.ts. Left as they are.packages/typesfiles went red on the move (135 tests), and twoplugin-listfiles hand a flat list view tosafeValidateSchema. Each kept its intent and was re-pointed, not deleted: the door legs now judge the page spelling of the same list view (a test-only helper,packages/types/src/__tests__/list-view-page-node.ts, re-spells it and reads issue paths relative to the bag), while each mirror leg still judgesListViewSchema. The census pins count the new arm: union arms (objectql-union-arms-7363,registered-type-arms-10859-b2), the flat-prop population (flat-props-refusal-10872, with the five runtime slots recorded as the arm's own refusals),responsiveStyles(public-block-responsive-styles-10872),grouping(grouping-field-padded-refused-7347), the mirror ledger (zod-mirror-parity), the import boundary (imported-defaults-8317:checkListViewChartBindingis a chained spec refinement) and the bag carriers (authoring-nodes-bag-carriers-11468). Inlist-view-dataset-chart-filter-refusal-10327two controls author achartlist with no dataset binding: the component props still accept them, and the page door now refuses them with the spec's owncheckListViewChartBindingissue (asserted against the spec's parse), never at the view filter.Tests
packages/types/src/__tests__/list-view-properties-bag-12670.test.ts, both faces: the ruled node, a bound node, an inline-rows node, at a child slot; every spec list kind in the bag'stype, and the registry key, a retired kind and a misspelling refused; no default authored;objectName/viewType, flat and in the bag, refused at their own paths with the FROM → TO and the document shape; the record source (four refused shapes, two sources); the bag's members by reference; the spec's two checks with the spec's own issue; the flat refusals, the runtime slots, the content channels; and thatListViewSchemastill judges the component props. Type-level: the arm's and the bag's input types, and the TypeScriptListViewSchemaunchanged.fadb698(the head):pnpm exec vitest run --maxWorkers=2 packages/types/:Test Files 384 passed (384)/Tests 10494 passed (10494)(lock verdictcommand-exit 0). The re-spelled cross-package pins plus the CLI suite (plugin-list×2,plugin-view×2,app-shellViewPreview.optionsFold-7928,plugin-mapbareMapKeyRetired-10393,plugin-gridgroupingNullEntry-7217,scripts/__tests__/check-handler-key-read-sites.test.ts,packages/cli/src/__tests__/):Test Files 37 passed (37)/Tests 524 passed (524).pnpm --filter @object-ui/types type-check(three legs; the test leg's--listFilesincludes the new pin and the helper): exit 0 atfadb698.ablation-replace.mjs, direction predicted before the run, restore proven by blob hash againstHEADand an emptygit diff HEAD:objectNamerefusal: predicted and observed 3 red (properties.objectName, flatobjectName, the no-fallback case), 594 green across the new pin andflat-props-refusal-10872;ListViewSchemaagain in place ofListViewBlockSchema: predicted and observed red on every page-door leg (94 red across the new pin,list-view-options-bag-6152andspec-object-refinements-7715), the 118 mirror-leg tests green.At
5bb1b1d(the merged head, after a@object-ui/typesbuild):packages/types/plusplugin-list's 8355, 8365 andListViewBlock.pageCarrierSpelling-12099pins andscripts/__tests__/check-doc-json-fences.test.ts→Test Files 389 passed (389)/Tests 10591 passed (10591).@object-ui/typestype-check exit 0. The changeset and README claims were probed on the built face:ObjectQLComponentSchema.safeParserefuses alist-viewnode on the discriminator; the README fence is accepted;type: boardis refused atproperties.type. The records above are the earlierfadb698ones.Gates
Local subset at
fadb698, each exit code captured before any pipe:check:spec-symbols,check:new-line-citations(0 new citation(s)),check:control-bytes,check:handler-key-reads(155 arms; 0 left unjudged),check:element-data-source-declaration,check:component-surface-parity,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:doc-fences,check:doc-types,check:doc-json,scripts/check-changeset-presence.mjs,scripts/check-changeset-no-major.mjs;scripts/check-governed-queue-guard.mjs --testover the 28 paths: NOT GOVERNED.lintscripts run it: 0 errors (33 warnings, allno-explicit-anyon lines this diff does not touch). With--no-inline-configit reports 2 errors, both on untouched lines that carry an inline disable (FlexBlockNode's empty interface inauthoring-nodes.ts, theFormFieldre-export inindex.ts).5bb1b1d, exit 0:check:doc-json(246 accepted, 0 refused),check:doc-types,check:doc-fences,check:handler-key-reads,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations,check-changeset-presence,check-changeset-no-major,check:control-bytes. eslint over the 26 TS files: 0 errors. Governed guard over 30 paths: NOT GOVERNED.check:doc-examplesandcheck:doc-snippets(exit 2, precondition: the 34-package build they name is not on disk; this diff changes no ts fence),pnpm lint, the app-shell / console type-check, and the full test farm.Acceptance notes
packages/plugin-list/README.md. Atbadde80, before the edit,check:doc-jsonexited 1 with the stale-fragment-marker verdict ("delete the marker"). At5bb1b1dit exits 0: 246 accepted, 0 refused.6216264566set it: land with or right after PR objectui#12668. objectui#12668 is onmain(5c0846e), and this branch merged it.datapresence. The record-source rule countsproperties.databy presence (!== undefined), the maintainer ruling recorded 2026-09-02 for every arm. Sodata: { provider: 'object', object: '' }passes the face, and after objectui#12668 it draws the "no object named" hint, asobjectName: ''did on the flat arm. Not changed here: it is the shared rule's question, not this arm's. Seat answer6218339393: A.ListViewreads today (fields,filters, theshow*flags,densityMode, theoptionsbag), because they are the mirror's members. When spec(ui):ComponentPropsMaphas nolist-viewrow, so a page-embedded list view'spropertiesare judged by nothing:kanban.groupFieldandoptions.gridpass on a page while every list-view door refuses them objectstack#22444 adds the spec row at lint tier, it judges those by its own reading.Generated by Claude Code