Skip to content

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

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-12670-list-view-page-face
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-12670-list-view-page-face

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12670
Clause-②: yes (narrowing)

Ruling: objectstack-ai/objectstack#22444, comment 6100463199 (ruling C). Scope: triage 6216264566 on objectui#12670, option A under C as it stands. Claim: comment 6216538732, re-stated as 6218329226 for the merge round. Written by the dispatched os-dev of the domain:ui seat 3, session session_01Vk15bz8xHtKGUfXfCm16h4. The renderer half of the same ruling is PR objectui#12668 (objectui#12099); it landed on main as 5c0846e, and this branch merged main after it (merge commit badde80), so the landing head carries both halves.

What changes

  • The authored page arm (packages/types/src/zod/objectql.zod.ts). ListViewBlockSchema is the list-view arm of AnyComponentSchema, in ObjectQLPublicBlockComponentSchema beside the other authored block arms. ListViewSchema left ObjectQLComponentSchema, the way ObjectMapSchema, ObjectGridSchema and ObjectChartSchema left it, and stays exported, unchanged, as the ListView component's props.
  • The bag (ListViewPropsBag, module-private). The installed @objectstack/spec 18.0.0-next.2 has no ComponentPropsMap['list-view'] row, so the bag is built the way object-chart's is: the flat ListViewSchema mirror'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 (specFieldsExcept over the spec's ListViewSchema) 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: type is the list kind, the spec's own view-kind enum (default stripped); objectName and viewType are refused by name (aliasKeyRefusal), naming properties.data and properties.type.
  • The spec's list view checks run in the bag, by reference: checkListViewCalendarVisualization (as on the flat mirror) and checkListViewChartBinding, which the flat mirror cannot attach because its kind is viewType. objectui's own dataset-chart filter refusal (objectui#10327) is read in the bag too, with the bag's type as the kind.
  • The node. type: 'list-view' + NODE_ENVELOPE + flatPropRefusals over the bag (every list view member written flat is refused by name toward properties.KEY; a retired member, objectName / viewType, keeps its own retirement there, so the message is the same flat or in the bag) + the mirror's dataSource binding by reference + the five handlerKeyRefusal runtime slots ListView reads, spelled as the mirror spells them + the objectui#9256 body / children refusals.
  • The record source. requireRecordSource('list-view', ['data'], 'properties'): properties.data, or the node's non-empty dataSource.object (the registration is elementDataSourceBlock-wrapped). Otherwise RECORD_SOURCE_REQUIRED at properties.data, naming both.
  • TypeScript (authoring-nodes.ts, index.ts). ListViewBlockNode = ObjectQLPublicBlockNodeOf('list-view'), exported, its bag closed by ClosedBag. It joins AuthoringNode through ObjectQLPublicBlockNode. The TypeScript ListViewSchema and both TypeScript unions (AnySchema, ObjectQLComponentSchema) are unchanged; one doc comment on the latter now counts six zod arms.
  • Docs. packages/types/src/zod/README.md: the ListViewSchema section names the page arm, with the ruled node as a JSON example, and the ObjectQL public block section describes ListViewBlockSchema.
  • Changeset. .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 names ObjectQLComponentSchema's lost list-view arm in the precedent's spelling, with a BREAKING line for code that parses with it directly.
  • plugin-list README rider (packages/plugin-list/README.md). The page fence's doc-json: fragment declaration is deleted, so check:doc-json judges the fence whole and accepts it. The paragraph that said objectui validate does not judge the page spelling now says what it judges. The kind stays in prose.
  • types README (packages/types/README.md). The by-name list of ObjectQL block node types gains ListViewBlockNode, ObjectPivotBlockNode and EmbeddableFormBlockNode, so it matches the 11 arms of ObjectQLPublicBlockComponentSchema.

Contract evidence (Clause-②)

What objectui validate / StrictAnyComponentSchema and safeValidateSchema answer, measured on the BUILT dist of @object-ui/types, at main dcd1041 and at this branch:

probe node before, tolerant before, strict after, tolerant after, strict
ruled: properties: { data: { provider: 'object', object }, type: 'kanban', kanban } refused: RECORD_SOURCE_REQUIRED at objectName refused: unrecognized_keys (properties) + RECORD_SOURCE_REQUIRED accepted accepted
flat objectName accepted accepted refused: invalid_type at objectName (objectName → properties.data) + RECORD_SOURCE_REQUIRED at properties.data same
properties.objectName refused: RECORD_SOURCE_REQUIRED at objectName refused: unrecognized_keys + RECORD_SOURCE_REQUIRED refused: invalid_type at properties.objectName (objectName → properties.data) + RECORD_SOURCE_REQUIRED at properties.data same
properties.viewType beside properties.data refused: RECORD_SOURCE_REQUIRED at objectName refused: unrecognized_keys + RECORD_SOURCE_REQUIRED refused: invalid_type at properties.viewType (viewType → properties.type) same
flat viewType beside the ruled bag refused: RECORD_SOURCE_REQUIRED at objectName refused: unrecognized_keys + RECORD_SOURCE_REQUIRED refused: invalid_type at viewType (viewType → properties.type) same
no record source: properties: { columns } refused: RECORD_SOURCE_REQUIRED at objectName refused: unrecognized_keys + RECORD_SOURCE_REQUIRED refused: RECORD_SOURCE_REQUIRED at properties.data same
dataSource: { object } alone accepted accepted accepted accepted
the retired node: flat objectName + viewType accepted accepted refused: invalid_type at objectName and at viewType + RECORD_SOURCE_REQUIRED same

So 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 PageComponentSchema for objectName, viewType, columns, name). objectui validate / objectui check judge with StrictAnyComponentSchema (validateAuthoredDocument); the CLI's own pins (packages/cli/src/__tests__/, 29 files) are green on this build.

What the built .d.ts gain or lose (base build at dcd1041 against this branch's build; the same 78 .d.ts files on both sides):

  • zod/objectql.zod.d.ts: gains ListViewBlockSchema. ObjectQLComponentSchemaInferred's arms go from object-view, object-tree, object-calendar, object-kanban, object-gallery, object-data-table, list-view to the first six; ObjectQLPublicBlockComponentSchemaInferred gains list-view as its eleventh. Every other declaration there, ListViewSchema included, is unchanged once comments are stripped and union member order is ignored.
  • zod/index.zod.d.ts: re-exports ListViewBlockSchema; the inferred types of validateSchema / safeValidateSchema / the unions now carry the bag arm for list-view.
  • authoring-nodes.d.ts: gains ListViewBlockNode; index.d.ts re-exports it. objectql.d.ts: one doc comment.
  • Ten other zod/*.d.ts differ 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).
  • Reverse check through a consumer that resolves @object-ui/types from dist (@object-ui/plugin-list's tsconfig.json replaces the root paths): a scratch file typing { type: 'list-view', properties: { objectName: 'deal' } } as ListViewBlockNode failed tsc at that key (TS2322: Type 'string' is not assignable to type 'undefined'), the ruled node beside it compiled; the file was removed and git status read clean.

The PM's mechanism hypotheses, measured

  1. Holds, with the construct chosen from the no-row precedent. At dcd1041 ListViewSchema is BaseSchema + spec fields + type: z.literal('list-view'), dataSource, objectName, viewType, closed by requireRecordSource('list-view', ['objectName']), no properties. 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 follows ObjectChartBlockSchema (the flat mirror's members) rather than ObjectMapBlockSchema (a row), and the flat refusals use the shared flatPropRefusals (as object-grid and object-pivot do) rather than an own map.
  2. No row. ComponentPropsMap at 18.0.0-next.2 has 59 rows, none list-view. The spec publishes ListViewSchema (51 members, strict, columns required, a kanban block's columns required, two object-level checks: the calendar visualization and the chart binding) and ObjectListViewSchema. The bag is the flat mirror's members by reference (the object-chart precedent). ⛔ Not the spec's ListViewSchema verbatim: it requires columns, so the ruled node would be refused, which is what ruling C's declined option A says of that row.
  3. Holds. On main the list-view registration's renderer is ListViewBlock = elementDataSourceBlock(…), so a non-empty dataSource.object counts, on the shared dataSourceSuppliesObject.
  4. Census below.
  5. TS fallout: none found. Both TypeScript unions keep ListViewSchema, so no value typed as either changes; ObjectQLPublicBlockNode / AuthoringNode only gain a member. Non-test code narrowing a node on the list-view literal: 0 (git grep). Type-checked against the rebuilt dist: @object-ui/plugin-list, @object-ui/plugin-view, @object-ui/react, @object-ui/cli, 4 of 4 green, plus @object-ui/types itself (all three legs). The app-shell and console closures (the whole workspace) are left to CI's Type Check.

Census: what the union judges as a list-view node (hypothesis 4)

Instrument: git grep for a list-view literal (185 files outside changelogs), narrowed to files that also name a union face (safeValidateSchema, validateSchema, AnyComponentSchema, StrictAnyComponentSchema, …), then a run of packages/types against 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 to safeValidateSchema (hit, and red before the re-spell).

  • Page nodes in fixtures and docs (judged by the union): 3 JSON fences, content/docs/guide/data-source.md, content/docs/utilities/data-objectstack.mdx and packages/plugin-list/README.md's page-binding section, each { "type": "list-view", "dataSource": { … } }. Accepted before and after (check:doc-json green); nothing to convert. Since the merge, packages/plugin-list/README.md's page fence (PR objectui#12668's) is accepted too, and judged whole.
  • ListView component schemas (not judged by the union): the four non-test type: 'list-view' literals, re-measured on dcd1041: InterfaceListPage.tsx and ObjectDataPage.tsx in @object-ui/app-shell, ObjectView.tsx in @object-ui/plugin-view, a doc comment in objectql.zod.ts. Left as they are.
  • Tests pinning the retired spelling at a published door: 16 packages/types files went red on the move (135 tests), and two plugin-list files hand a flat list view to safeValidateSchema. 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 judges ListViewSchema. 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: checkListViewChartBinding is a chained spec refinement) and the bag carriers (authoring-nodes-bag-carriers-11468). In list-view-dataset-chart-filter-refusal-10327 two controls author a chart list with no dataset binding: the component props still accept them, and the page door now refuses them with the spec's own checkListViewChartBinding issue (asserted against the spec's parse), never at the view filter.

Tests

  • New pin 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's type, 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 that ListViewSchema still judges the component props. Type-level: the arm's and the bag's input types, and the TypeScript ListViewSchema unchanged.
  • At fadb698 (the head): pnpm exec vitest run --maxWorkers=2 packages/types/: Test Files 384 passed (384) / Tests 10494 passed (10494) (lock verdict command-exit 0). The re-spelled cross-package pins plus the CLI suite (plugin-list ×2, plugin-view ×2, app-shell ViewPreview.optionsFold-7928, plugin-map bareMapKeyRetired-10393, plugin-grid groupingNullEntry-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 --listFiles includes the new pin and the helper): exit 0 at fadb698.
  • Ablations, each through ablation-replace.mjs, direction predicted before the run, restore proven by blob hash against HEAD and an empty git diff HEAD:
    • drop the bag's objectName refusal: predicted and observed 3 red (properties.objectName, flat objectName, the no-fallback case), 594 green across the new pin and flat-props-refusal-10872;
    • arm the public-block union with ListViewSchema again in place of ListViewBlockSchema: predicted and observed red on every page-door leg (94 red across the new pin, list-view-options-bag-6152 and spec-object-refinements-7715), the 118 mirror-leg tests green.

At 5bb1b1d (the merged head, after a @object-ui/types build): packages/types/ plus plugin-list's 8355, 8365 and ListViewBlock.pageCarrierSpelling-12099 pins and scripts/__tests__/check-doc-json-fences.test.ts → Test Files 389 passed (389) / Tests 10591 passed (10591). @object-ui/types type-check exit 0. The changeset and README claims were probed on the built face: ObjectQLComponentSchema.safeParse refuses a list-view node on the discriminator; the README fence is accepted; type: board is refused at properties.type. The records above are the earlier fadb698 ones.

Gates

Local subset at fadb698, each exit code captured before any pipe:

  • 0: 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 --test over the 28 paths: NOT GOVERNED.
  • eslint over the 26 changed TS files, as the package lint scripts run it: 0 errors (33 warnings, all no-explicit-any on lines this diff does not touch). With --no-inline-config it reports 2 errors, both on untouched lines that carry an inline disable (FlexBlockNode's empty interface in authoring-nodes.ts, the FormField re-export in index.ts).
  • At 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.
  • NOT MEASURED locally, left to CI: check:doc-examples and check: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

  • Rider done: packages/plugin-list/README.md. At badde80, before the edit, check:doc-json exited 1 with the stale-fragment-marker verdict ("delete the marker"). At 5bb1b1d it exits 0: 246 accepted, 0 refused.
  • Landing order — met. Triage 6216264566 set it: land with or right after PR objectui#12668. objectui#12668 is on main (5c0846e), and this branch merged it.
  • data presence. The record-source rule counts properties.data by presence (!== undefined), the maintainer ruling recorded 2026-09-02 for every arm. So data: { provider: 'object', object: '' } passes the face, and after objectui#12668 it draws the "no object named" hint, as objectName: '' did on the flat arm. Not changed here: it is the shared rule's question, not this arm's. Seat answer 6218339393: A.
  • The legacy aliases ride along. The bag carries every member ListView reads today (fields, filters, the show* flags, densityMode, the options bag), because they are the mirror's members. When spec(ui): ComponentPropsMap has no list-view row, so a page-embedded list view's properties are judged by nothing: kanban.groupField and options.grid pass 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

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3118.5 KB 3744.1 KB
Main entry chunk (gzip) 66.0 KB 350 KB
Entry file index-iLAgp7Vd.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) 21.19KB 7.76KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
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.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.39KB 6.02KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
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.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 597.81KB 144.28KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.20KB 69.22KB
fields (index.js) 290.25KB 74.19KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
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.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 263.43KB 69.61KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.73KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 270.08KB 74.80KB
plugin-kanban (index.js) 59.42KB 18.48KB
plugin-list (index.js) 131.40KB 33.50KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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: fadb698a7682070d8bcb1b10105f15b0e5d741a5
Local-runs: none
Scope: packages/types/src/zod/objectql.zod.ts, packages/types/src/zod/index.zod.ts, packages/types/src/authoring-nodes.ts, packages/types/src/index.ts, packages/types/src/objectql.ts, packages/types/src/tests/list-view-properties-bag-12670.test.ts, packages/types/src/tests/list-view-page-node.ts, packages/types/src/tests/authoring-nodes-bag-carriers-11468.test.ts, packages/types/src/tests/content-channel-remeasure-9256.test.ts, packages/types/src/tests/flat-props-refusal-10872.test.ts, packages/types/src/tests/grid-list-view-conditional-formatting-11533.test.ts, packages/types/src/tests/grouping-field-padded-refused-7347.test.ts, packages/types/src/tests/imported-defaults-8317.test.ts, packages/types/src/tests/list-view-blocks-by-reference-6152.test.ts, packages/types/src/tests/list-view-dataset-chart-filter-refusal-10327.test.ts, packages/types/src/tests/list-view-options-bag-6152.test.ts, packages/types/src/tests/object-chart-legacy-axis-keys-retired-10608.test.ts, packages/types/src/tests/object-grid-show-filters-retired-11068.test.ts, packages/types/src/tests/objectql-union-arms-7363.test.ts, packages/types/src/tests/public-block-responsive-styles-10872.test.ts, packages/types/src/tests/registered-type-arms-10859-b2.test.ts, packages/types/src/tests/spec-object-refinements-7715.test.ts, packages/types/src/tests/strict-face-read-keys-11070.test.ts, packages/types/src/tests/zod-mirror-parity.test.ts, packages/plugin-list/src/tests/ListView.calendarAliasRefused-8355.test.tsx, packages/plugin-list/src/tests/ListView.strayGroupByRefused-8365.test.tsx + packages/types/src/zod/public-blocks.zod.ts (NODE_ENVELOPE, PAGE_COMPONENT_NODE_KEYS, flatPropRefusals, isRetiredRowMember, propsBag, dataSourceSuppliesObject), packages/types/src/zod/base.zod.ts (BaseSchemaCore, specFieldsExcept), packages/types/package.json (exports), packages/types/README.md, packages/types/CHANGELOG.md (precedent spelling), .changeset/12670-list-view-page-face.md, packages/types/src/zod/README.md, scripts/check-doc-json-fences.mjs, .github/workflows/repo-gates.yml; context read and not adopted, at PR objectui#12668 head 36e1cee: packages/plugin-list/src/ListViewBlock.tsx, packages/plugin-list/src/index.tsx, packages/plugin-list/README.md; the spec at 18.0.0-next.2 (objectstack packages/spec/src/ui/view.zod.ts, the list view type enum) and objectui packages/core/src/utils/normalize-list-view.ts at 8614705 (ListViewVisualization, UNDRAWABLE_VIEW_KINDS).

① Derived judgments

What @object-ui/types publishes (judged from source at the head; no build run; exports unchanged: ., ./zod and the subpaths).

  • RIGHT: ListViewBlockSchema is added in objectql.zod.ts and re-exported through ./zod (index.zod.ts); ListViewBlockNode is added in authoring-nodes.ts as ObjectQLPublicBlockNodeOf('list-view') and re-exported from index.ts. The zod ListViewSchema is unchanged in members, refinements and its own requireRecordSource('list-view', ['objectName']), and stays exported; the TypeScript ListViewSchema and the TypeScript ObjectQLComponentSchema union are untouched apart from one doc comment.
  • RIGHT: ObjectQLComponentSchemaInferred loses ListViewSchema (seven arms to six); ObjectQLPublicBlockComponentSchemaInferred gains ListViewBlockSchema (eleventh); AnyComponentSchema composes both (index.zod.ts), so its list-view arm is the bag arm on both faces.
  • WRONG, in spelling only: the exported discriminated union ObjectQLComponentSchema loses an arm a consumer could parse with directly (ObjectQLComponentSchema.safeParse of a list-view node now fails on the discriminator; the inferred type of that export loses the member). The changeset names AnyComponentSchema and "the zod union" and never names ObjectQLComponentSchema; every precedent entry in packages/types/CHANGELOG.md spelled it ("ObjectGridSchema leaves ObjectQLComponentSchema", the same for form, map, gantt, chart). The PR body states it; the changeset, which is the text that ships, does not. One sentence owed on the landing head.

The page arm against what PR objectui#12668's renderer reads (ListViewBlock.tsx at 36e1cee, read, not adopted).

  • RIGHT, the kind: the renderer reads properties.type through isConfigBag(bag) ? bag.type, hands it to ListView as viewType only when isListViewVisualization(kind), and drops any other value (the list draws a grid). The face's properties.type is ViewKindEnum = SpecListViewSchema.shape.type.removeDefault(), by reference; at 18.0.0-next.2 that enum is exactly grid, kanban, gallery, calendar, timeline, gantt, map, chart, tree, the nine ListViewVisualization kinds (page removed upstream; list and detail, the renderer's undrawable rows, are not members). So the face accepts exactly the kinds the renderer draws, and the registry key, a retired kind and a misspelling are refused at properties.type (pinned). No default is authored into the document.
  • RIGHT, the object: the renderer passes data through to the object-provider fold and counts a dataSource.object the gate landed; the face's record source is requireRecordSource('list-view', ['data'], 'properties') plus a non-empty dataSource.object (dataSourceSuppliesObject, the one copy). properties.objectName is a refusal, not a rung. RECORD_SOURCE_REQUIRED sits at properties.data and names both remedies.
  • RIGHT, the refusals: the renderer removes objectName and viewType from the node after the hoist, flat or hoisted from the bag, and warns once per key; the face refuses both, flat and in the bag, at their own paths with one message each naming properties.data / properties.type (aliasKeyRefusal; flatPropRefusals hands the bag's retired member through, so the flat spelling meets the same string). No fallback acceptance: objectName beside a working data is refused.
  • One residual the face accepts and the renderer draws as the no-object hint: data: { provider: 'object', object: '' }. Judged under ③ (open question 1).

The bag's members.

  • RIGHT: z.looseObject(ListViewSchema.shape).omit(LIST_VIEW_NODE_LEVEL_KEYS).extend({ type, objectName, viewType }) is the ObjectChartPropsBag construct (z.looseObject(ObjectChartSchema.shape).omit(OBJECT_CHART_NODE_LEVEL_KEYS)), chosen because the installed spec has no ComponentPropsMap['list-view'] row and the spec ListViewSchema requires columns (ruling C's declined option A). Every member but the three ruled ones is the same schema object as the mirror's (the pin asserts identity over more than 60 members and that every spec list view member is present). The node-level set is read off BaseSchema.shape minus the spec list view's shape, plus dataSource, so type, name, label, description and data stay list view members in the bag while id, className, style, bind, placeholder, body, children stay on the node. Nothing of the mirror is copied; what is new is text only (two retirement strings, the flat-prop guidance, the neither-channel string through the shared generator) and the checkListViewBagDatasetChartFilter adapter, which calls the shared objectui#10327 check with viewType: bag.type.
  • RIGHT: flatPropRefusals('list-view', ListViewPropsBag, LIST_VIEW_FLAT_PROP) generates one refusal per bag key outside PAGE_COMPONENT_NODE_KEYS (type, id, label, properties, events, style, className, responsiveStyles, visibleWhen, visibility, dataSource, responsive, aria), so label keeps BaseSchema's member, responsiveStyles is NODE_ENVELOPE's, dataSource is the mirror's member by reference, and data, columns, filter, kanban, options, name, description written flat are refused toward properties.KEY (pinned, both faces).

Flat-prop refusals at the node level: the five handler keys.

  • RIGHT: onAddRecord, onBulkAction, onDensityChange, onNavigate, onPageSizeChange are declared after the spread as handlerKeyRefusal(..., 'runtime-slot', ...), so the arm's own refusal overrides the generated bag pointer (a later member wins). They are re-invocations with the mirror's arguments rather than ListViewSchema.shape.onX by reference, on the ObjectGridBlockSchema.onNavigate precedent, so check:handler-key-reads reads the disposition off this arm (Repo Gates green, 155 arms, 0 unjudged per the body); the pin asserts description equality with the mirror. In the bag they remain members by reference, so properties.onAddRecord is refused as a runtime slot too (pinned).

The spec refinements in the bag, and the objectui#10327 controls.

  • RIGHT: checkListViewCalendarVisualization (as on the mirror) and checkListViewChartBinding are attached by reference; the second is reachable only here because the bag's kind is the spec's own type. This adds a narrowing beyond the card's two refusals: a page chart list with no dataset binding is refused at properties.chart on the page face. The changeset discloses it; the pin derives the expected issue from the spec's own parse (lit control), and imported-defaults-8317 records the check as a chained spec refinement.
  • RIGHT: in list-view-dataset-chart-filter-refusal-10327, the two controls authoring an unbound chart now assert, on the page door, only custom issues at chart or under options.chart., and that no issue sits at filter or filters; the component door still asserts a full parse. The card's own refusal still does not fire on a neighbour, so the pin keeps its teeth; where the document is spec-shaped the spec's issue paths are compared to the page door's.

The census: 16 packages/types files and 2 plugin-list files.

  • RIGHT: each door leg re-spells the same list view through a test-only helper (asPageListView, bagPath, onPageSpelling) and reads issue paths relative to the bag; each mirror leg is unchanged; no it is deleted. Several pins got sharper: 9256 now asserts the refusal message on the arm, 10872 pins the five runtime slots as the arm's own refusals carrying RUNTIME SLOT and not pointing at the bag, 7363 and 10859-b2 move the arm counts with not.toContain / the full literal list, zod-mirror-parity gains the arm's EXCLUSIONS entry describing the by-reference construct, strict-face-read-keys-11070 and object-grid-show-filters-retired-11068 re-spell their controls in the page spelling. The two plugin-list pins (8355, 8365) hand the door the page spelling and keep their DARK CONTROLs. No pin lost its teeth.

Check-runs on the head (re-read at 2026-10-16T14:58Z): 36 runs, 33 success, 3 skipped (the coverage matrix and its parent, dependabot), 0 failed, 0 in progress. The seven required contexts (Lint, Type Check, Build & E2E, Build Docs, Changeset Declaration, Test, Governed Surface Queue Guard) are all success. Repo Gates, which carries check:doc-json, check:doc-types and check:handler-key-reads, is success and is advisory (not in the required set). Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read and Line Citation Gate are success.

② Semver level

  • RIGHT: @object-ui/types: minor with the BREAKING section in prose is the spelling objectui AGENTS.md §9 requires (no major in the fixed group; check-changeset-no-major green). The body carries the FROM → TO for objectName (to properties.data or dataSource.object), viewType (to properties.type) and every flat list view prop (to properties.KEY), and names the ADR-0087 conversion on the spec side as the carrier for stored nodes, never a fallback read.
  • RIGHT: the PR body's Clause-②: yes (narrowing) matches the diff. It narrows (the retired pair flat and in the bag, every flat list view prop, a chart list with no dataset binding) and widens (the ruled page node, a dataSource-bound node, inline rows); the closed pair takes one arm and the narrowing arm is the one that decides the review owed.
  • WRONG in spelling, as in ①: the changeset does not name ObjectQLComponentSchema losing its list-view arm, which the precedent entries did. Frontmatter naming only @object-ui/types is right: objectui validate moves through the dependency and the fixed group bumps together (Changeset Fixed Group Check green).

③ Boundary flags

  • Open question 1 (report 6217824753): A. requireRecordSource's docblock records that presence is !== undefined, "the ruling's wording, NOT the renderers' truthiness", the maintainer ruling recorded 2026-09-02, and that "WHAT data MEANS IS NOT SHARED, only its PRESENCE is". The binding's non-empty test is a separately ruled rung (objectui#11117), justified because the runtime lands nothing for an empty binding. A value-reading rung for data.object on this one arm would fork the shared rule and re-rule presence outside its ruling; it would also refuse PR objectui#12668's registration default, data: { provider: 'object', object: '' }, the unfilled designer node. Keep A. If the maintainer wants the empty object refused at validate, that is a card on requireRecordSource for every arm together with the registration default, under its own ruling. Not escalated here.
  • Landing order. This branch is built from main without PR objectui#12668. On such a main nothing in the tree is wrong on its own, but the face would accept properties.type, which main's renderer does not read (the hoist keeps type out, so a kanban draws as a grid), and refuse the objectName that main's renderer still reads: the card's contradiction, reversed. So this head is not readied or queued until objectui#12668 is on main and this branch has merged it. At this reading objectui#12668 is open, not merged, mergeable_state: clean, with no auto-merge request on the REST read; queue membership is not readable from this seat (GraphQL refused), so "in the queue" is the brief's word, not a reading of mine.
  • The packages/plugin-list/README.md rider. Once both are on main, check:doc-json judges that README's page fence (list-view with properties.data, columns, kanban) as accepted by the strict face and reports stale-fragment-marker for its html-comment doc-json: fragment declaration ("delete the marker"), exit 1, so Repo Gates goes red. Repo Gates is not in the required set, so the red would not eject anything from the queue: it would land an advisory red that rides main into every later PR until stanched. The reminder is mechanical but advisory, and it fires only on the head that carries both halves. So the rider belongs in THIS PR's landing head, on the merge of main after objectui#12668 lands, as the claim's file surface already says, not in a follow-up PR. The fix should state the kind in prose rather than add "type": "kanban" to the fence, since check:doc-types judges every type literal in a fence against the registry (objectui#12668's own acceptance note).
  • The types README omission. packages/types/README.md lists the exported block node types by name and omits ListViewBlockNode (it already omitted ObjectPivotBlockNode and EmbeddableFormBlockNode). This README ships in the tarball (files). Commandment Add automated testing infrastructure and CI/CD workflows #2: one line, recommended on the landing head; not a contract defect.
  • A record on this head is not the landing record. The landing head must carry the merge of main after objectui#12668, the README rider and the changeset sentence, so a fresh ## Contract review is owed on that head. What it has to re-check is those three edits and the merge; every accept-set judgment above is RIGHT on this diff and is expected to carry over unchanged.

Implemented-by: claude/issue-12670-list-view-page-face
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

VERDICT: FAIL

FAIL on this head for two reasons, neither of them the design: ② the changeset omits the precedent sentence naming ObjectQLComponentSchema's lost list-view arm, a narrowed public export the shipped text must name; ③ this head cannot be the landing head, since landing requires merging main after objectui#12668 and carrying the plugin-list README rider in the same tree. The page arm, the bag by reference, the flat and runtime-slot refusals, the spec refinements, the record-source rule (option A) and the census re-spells are all judged RIGHT; the record on the landing head is expected to PASS once it carries the merge, the README rider, the changeset sentence and, recommended, the types README line.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 73 chunks) 3120.5 KB 3744.1 KB
Main entry chunk (gzip) 66.0 KB 350 KB
Entry file index-DvWaaVBE.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) 21.42KB 7.85KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
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.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.39KB 6.02KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
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.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 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) 597.81KB 144.28KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.96KB 69.45KB
fields (index.js) 290.81KB 74.35KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
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) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
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.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 263.43KB 69.61KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.90KB 46.72KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 270.35KB 74.86KB
plugin-kanban (index.js) 59.42KB 18.48KB
plugin-list (index.js) 132.91KB 34.06KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
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) 120.23KB 39.46KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
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) 1.13KB 0.65KB
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) 5.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.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) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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: 5bb1b1d1594f2a3e70e019a417130a8823b46a0f
Local-runs: none
Scope: packages/types/src/zod/objectql.zod.ts, packages/types/src/zod/index.zod.ts, packages/types/src/authoring-nodes.ts, packages/types/src/index.ts, packages/types/src/objectql.ts, packages/types/src/tests/list-view-properties-bag-12670.test.ts, packages/types/src/tests/list-view-page-node.ts, packages/types/src/tests/authoring-nodes-bag-carriers-11468.test.ts, packages/types/src/tests/content-channel-remeasure-9256.test.ts, packages/types/src/tests/flat-props-refusal-10872.test.ts, packages/types/src/tests/grid-list-view-conditional-formatting-11533.test.ts, packages/types/src/tests/grouping-field-padded-refused-7347.test.ts, packages/types/src/tests/imported-defaults-8317.test.ts, packages/types/src/tests/list-view-blocks-by-reference-6152.test.ts, packages/types/src/tests/list-view-dataset-chart-filter-refusal-10327.test.ts, packages/types/src/tests/list-view-options-bag-6152.test.ts, packages/types/src/tests/object-chart-legacy-axis-keys-retired-10608.test.ts, packages/types/src/tests/object-grid-show-filters-retired-11068.test.ts, packages/types/src/tests/objectql-union-arms-7363.test.ts, packages/types/src/tests/public-block-responsive-styles-10872.test.ts, packages/types/src/tests/registered-type-arms-10859-b2.test.ts, packages/types/src/tests/spec-object-refinements-7715.test.ts, packages/types/src/tests/strict-face-read-keys-11070.test.ts, packages/types/src/tests/zod-mirror-parity.test.ts, packages/plugin-list/src/tests/ListView.calendarAliasRefused-8355.test.tsx, packages/plugin-list/src/tests/ListView.strayGroupByRefused-8365.test.tsx; the prose faces, read because they ship: .changeset/12670-list-view-page-face.md, packages/plugin-list/README.md, packages/types/README.md, packages/types/src/zod/README.md + packages/types/src/zod/public-blocks.zod.ts (NODE_ENVELOPE, PAGE_COMPONENT_NODE_KEYS, propsBag, flatPropRefusals, isRetiredRowMember, dataSourceSuppliesObject), packages/types/src/zod/tombstone.zod.ts (aliasKeyRefusal, handlerKeyRefusal, retirementTombstone, neitherContentChannelGuidance), packages/types/src/zod/base.zod.ts (BaseSchemaCore, specFieldsExcept), packages/types/src/zod/layout.zod.ts (the merge's other side: no checkPageComponentViewData at the head), packages/types/package.json (exports, files, the spec range ^18.0.0-next.2), packages/types/CHANGELOG.md (the precedent spelling), packages/cli/src/commands/validate.ts and packages/cli/src/utils/authoring-face.ts (objectui validate judges with StrictAnyComponentSchema), packages/react/src/SchemaRenderer.tsx (HOIST_PROTECTED_KEYS), packages/core/src/utils/normalize-list-view.ts (LIST_VIEW_KINDS, isListViewVisualization), packages/plugin-list/src/ListViewBlock.tsx and packages/plugin-list/src/index.tsx as they stand at the head, which is main's renderer half (5c0846e), scripts/check-doc-json-fences.mjs and .github/workflows/repo-gates.yml (the fence gate), .github/workflows/ci.yml (the Type Check job carries check:handler-key-reads and check:element-data-source-declaration), .github/workflows/changeset-presence.yml and scripts/check-changeset-presence.mjs (Changeset Declaration), the objectstack repository's packages/spec/src/ui/view.zod.ts at tag @objectstack/spec@18.0.0-next.2 (the list view type enum; read with git show, nothing checked out), and the two shared tests read four ways for the merge: at dcd1041 (base), fadb698 (ours), 40e5873 (main) and badde80 (merged).

① Derived judgments

The head. Six commits on main: the three the earlier record 6218271493 judged at fadb698, then badde80 (a two-parent merge of origin/main at 40e5873, which carries PR objectui#12668 as 5c0846e and PR objectui#12678 as 15d8ca6), ddc1ca9 (the plugin-list README rider) and 5bb1b1d (the changeset sentence and the types README line). 30 files; the net diff against main is the branch's own 28 plus the two prose edits. Every judgment below was re-derived from the head's files and the diff, none carried over.

What @object-ui/types publishes (exports . and ./zod unchanged; files ships dist, README.md, CHANGELOG.md).

  • RIGHT: ListViewBlockSchema is added (objectql.zod.ts) and re-exported through ./zod (index.zod.ts); ListViewBlockNode is added (authoring-nodes.ts, ObjectQLPublicBlockNodeOf('list-view'), its bag closed) and re-exported from index.ts. The zod ListViewSchema is unchanged in members, refinements and its own requireRecordSource('list-view', ['objectName']); the TypeScript ListViewSchema and the TypeScript ObjectQLComponentSchema union are untouched apart from one doc comment.
  • RIGHT: ObjectQLComponentSchemaInferred has six arms at the head (object-view, object-tree, object-calendar, object-kanban, object-gallery, object-data-table); ObjectQLPublicBlockComponentSchemaInferred has eleven, ListViewBlockSchema the eleventh. AnyComponentSchema composes both (index.zod.ts), safeValidateSchema is AnyComponentSchema.safeParse, StrictAnyComponentSchema is its derived twin, and objectui validate reaches it through validateAuthoredDocument, which is StrictAnyComponentSchema.safeParse (packages/cli/src/utils/authoring-face.ts). So the list-view arm on both published faces and at the CLI door is the bag arm.
  • RIGHT, and no longer WRONG in spelling: the exported discriminated union ObjectQLComponentSchema loses an arm a consumer could parse with directly, and the changeset now says so in the precedent's spelling (judged under the three commits, below).

The page arm against the renderer that is ON main (ListViewBlock.tsx and plugin-list/src/index.tsx at the head are 5c0846e's text; the one later main commit, 40e5873, touches app-shell only).

  • RIGHT, the kind. The renderer reads the kind as isConfigBag(bag) ? bag.type : undefined off schema.properties, hands it to ListView as viewType only when isListViewVisualization(kind), and drops any other value, so the list draws a grid. LIST_VIEW_KINDS in @object-ui/core is grid, kanban, gallery, calendar, timeline, gantt, map, chart, tree. The face's properties.type is ViewKindEnum = SpecListViewSchema.shape.type.removeDefault(), by reference; at tag @objectstack/spec@18.0.0-next.2 (the range packages/types/package.json pins) that enum is exactly those nine kinds with .default('grid'), and page is gone from it. So the face accepts exactly the kinds the renderer draws, refuses the registry key, a retired kind and a misspelling at properties.type with invalid_value (pinned), and authors no default into the document (pinned against the spec's own grid default as the control). The hoist keeps type and id out (HOIST_PROTECTED_KEYS, SchemaRenderer.tsx), so the node's own type stays list-view and the bag's type is read from the bag, which is where the renderer reads it; the renderer's own pin ListViewBlock.pageCarrierSpelling-12099 is in the head's green Test shards.
  • RIGHT, the object. The renderer's namesRecordSource counts a non-empty bound objectName (the gate lands dataSource.object there), an object provider only with a non-empty object, and any other data. The face's requireRecordSource('list-view', ['data'], 'properties') counts properties.data by presence (!== undefined) or dataSourceSuppliesObject(node), a non-empty string dataSource.object, the one copy (public-blocks.zod.ts). With neither, RECORD_SOURCE_REQUIRED at ['properties', 'data'] with a message naming properties.data and the node's dataSource.object (pinned on four refused shapes and two accepted sources). properties.objectName is a refusal, not a rung. One residual: data: { provider: 'object', object: '' } passes the face and draws the renderer's no-object hint; judged under ③ (open question 1).
  • RIGHT, the refusals. The renderer removes the node's own objectName and viewType before the gate and warns once per key; the face refuses both, flat and in the bag, at their own paths: aliasKeyRefusal is an optional z.never with one string, so the code is invalid_type and the message reads "Did you mean objectName → properties.data?" / "viewType → properties.type?" plus the document shape (pinned, both faces, four positions). flatPropRefusals hands a retired bag member through by reference (isRetiredRowMember), so the flat spelling meets the bag's own string. No fallback: objectName beside a working data is refused (pinned). A node naming both dataSource.object and properties.data is accepted by the face and the renderer lets the binding outrank data: consistent.

The bag by reference.

  • RIGHT: ListViewPropsBag = z.looseObject(ListViewSchema.shape).omit(LIST_VIEW_NODE_LEVEL_KEYS).extend({ type, objectName, viewType }) is the ObjectChartPropsBag construct (z.looseObject(ObjectChartSchema.shape).omit(OBJECT_CHART_NODE_LEVEL_KEYS)), chosen because the pinned spec has no ComponentPropsMap['list-view'] row and the spec's own ListViewSchema requires columns (ruling C's declined option A). The node-level set is read off BaseSchema.shape minus the spec list view's shape plus dataSource, so id, className, style, placeholder, bind, visible, hidden, body, children stay on the node and type, name, label, description, data stay list view members in the bag. The pin asserts identity (the same schema object) over more than 60 members and the presence of every spec list view member.
  • RIGHT: flatPropRefusals('list-view', ListViewPropsBag, LIST_VIEW_FLAT_PROP) generates one refusal per bag key outside PAGE_COMPONENT_NODE_KEYS (type, id, label, properties, events, style, className, responsiveStyles, visibleWhen, visibility, dataSource, responsive, aria), so label keeps BaseSchema's member (pinned: kept, and a non-string refused), responsiveStyles is NODE_ENVELOPE's, dataSource is declared on the node as the mirror's own member by reference (the spec's ElementDataSourceSchema; pinned: a string binding refused), and data, columns, filter, kanban, options, showSearch, name, description written flat are refused toward properties.KEY (pinned, both faces).
  • RIGHT: the five handler keys ListView reads (onAddRecord, onBulkAction, onDensityChange, onNavigate, onPageSizeChange) are declared after the spread as handlerKeyRefusal(…, 'runtime-slot', …), a refusing z.custom, so a flat one reports custom with RUNTIME SLOT and is not pointed at the bag; in the bag they stay the mirror's members, so properties.onAddRecord is refused as a slot too (pinned both ways; flat-props-refusal-10872 records the five as the arm's own refusals and asserts the description equals the mirror's). The rule's gate, check:handler-key-reads, runs in ci.yml's Type Check job, required and success on this head; check:element-data-source-declaration runs beside it.
  • RIGHT: the spec refinements attach by reference: checkListViewCalendarVisualization (as on the mirror) and checkListViewChartBinding, which only the bag can carry because its kind is the spec's own type; objectui's finding(plugin-list): a chart list view bound to a semantic dataset gets a node with no filter, so neither the authored view filter nor the toolbar Filter reaches its query #10327 dataset-chart filter refusal is read in the bag through a thin adapter that passes viewType: bag.type to the shared check. This narrows beyond the card's two refusals (a page chart list with no dataset binding is refused at properties.chart); the changeset discloses it, the new pin derives the expected issue from the spec's own parse, imported-defaults-8317 records the check as a chained spec refinement, and the finding(plugin-list): a chart list view bound to a semantic dataset gets a node with no filter, so neither the authored view filter nor the toolbar Filter reaches its query #10327 controls that author an unbound chart now assert the spec's issue on the page door and no issue at the view filter.
  • RIGHT: the posture stays the mirror's (looseObject): an invented bag key is unjudged on the tolerant face and refused by name at properties on the strict face (pinned). Both content channels are refused by one neitherContentChannelGuidance string through retirementTombstone (pinned: the message names the node and properties.data).

The census re-spells (16 packages/types files, 2 plugin-list files, read hunk by hunk): each door leg re-spells the same list view through the test-only list-view-page-node.ts (asPageListView, bagPath, onPageSpelling) and reads issue paths relative to the bag; every mirror leg is unchanged; no it is deleted. The arm counts move (objectql-union-arms-7363: seven to six, not.toContain('list-view'); registered-type-arms-10859-b2: the full eleven-literal list), zod-mirror-parity gains the arm's EXCLUSIONS entry describing the by-reference construct, content-channel-remeasure-9256 now asserts the refusal message on the arm, grouping-field-padded-refused-7347 declares the properties.grouping row and the flat grouping as not covered, grid-list-view-conditional-formatting-11533 adds the page faces at properties.conditionalFormatting, strict-face-read-keys-11070 and object-grid-show-filters-retired-11068 re-spell their controls, and the two plugin-list pins (8355, 8365) keep their DARK CONTROLs. RIGHT.

The three new commits.

  • The merge badde80: RIGHT. Of the 121 files it brings from main, three are paths this PR owns: packages/plugin-list/README.md (main's feat(plugin-list): a page list-view node is written data / type, and the metadata page reads properties.type as the list kind (objectui#12099) #12668 text, which ddc1ca9 then edits) and the two shared tests. Read four ways. imported-defaults-8317: base to main removed the checkPageComponentViewData import and row (objectui#12666); base to ours added the checkListViewChartBinding import and row; merged against main is exactly ours' two hunks. spec-object-refinements-7715: base to main deleted the deps(v18): move objectui's @objectstack/* from 18.0.0-next.0 to 18.0.0-next.1 and follow its contract — the bump the held follow-ups wait on #12370 describe block, dropped the check from attached and added specChecksRemovedOnMain with the async census; base to ours added the asPageListView / bagPath import, re-spelled the calendar tripwire's page door and added the comment on the mirror's notAttachable row; merged against main is exactly ours' hunks. Both intents are kept, nothing was dropped, and the PR's net diff for both files is the branch's own hunks and nothing else. The PR touches no layout.zod.ts, where fix(types): drop the page view-data check objectstack main deleted (objectui#12666) #12678 landed; at the head that file carries no checkPageComponentViewData. Nothing regenerated. The head's Test shards 1 to 16 and Type Check are success.
  • The README rider ddc1ca9: RIGHT. The html-comment doc-json: fragment marker above the page fence is deleted, so check-doc-json-fences.mjs judges the fence whole with StrictAnyComponentSchema.safeParse (its line 750; the package-README leg); with the marker in place the gate reports stale-fragment-marker ("the strict face ACCEPTS this list-view node … delete the marker"). The fence is type: list-view with properties.data (an object provider naming deal), columns (two strings) and kanban.groupByField: every key is a bag member, the record source is present, no kind is written so neither kind check fires, and the strict face accepts it; Repo Gates, which carries the gate (repo-gates.yml), is success on this head. The paragraph, sentence by sentence against the face in the diff: (1) "objectui validate judges a page list-view node in this spelling": true, the CLI's face is StrictAnyComponentSchema, whose list-view arm is ListViewBlockSchema. (2) "Its record source is properties.data or a bound dataSource.object, and a node with neither is refused at properties.data": true, requireRecordSource('list-view', ['data'], 'properties') plus dataSourceSuppliesObject (a non-empty object, which is what "bound" means at the gate too), issue path properties.data. (3) "objectName and viewType are refused by name, on the node or in properties, each naming what to write instead (properties.data, properties.type)": true, aliasKeyRefusal in the bag and the same member handed through flat. (4) "A properties.type that names no kind a list view draws is refused": true, the bag's type is the spec enum, which equals the renderer's drawable set exactly at the pinned spec, so "no kind a list view draws" and "outside the enum" are the same set; main's sentence above it, that such a kind draws a grid, describes the renderer on a document that never met validate, and does not contradict this one. (5) "and so is a list view prop such as columns written on the node itself rather than in properties": true, flatPropRefusals. The kind stays in prose, which check-doc-component-types.mjs forces: it walks packages/NAME/README.md and judges every type literal in a fence against the registry.
  • The changeset sentence and the types README line 5bb1b1d: RIGHT. The changeset now carries "ListViewBlockSchema reaches AnyComponentSchema through ObjectQLPublicBlockComponentSchema, the public block union. ListViewSchema leaves ObjectQLComponentSchema, so ObjectQLComponentSchema.safeParse of a list-view node now fails on the discriminator." The five precedent entries in packages/types/CHANGELOG.md (form, gantt, map, chart, grid) each read "ObjectXBlockSchema reaches AnyComponentSchema through ObjectQLPublicBlockComponentSchema. ObjectXSchema leaves ObjectQLComponentSchema.", so this is their spelling with the consequence appended; the BREAKING list gains the line for code that parses with ObjectQLComponentSchema directly and says where to parse instead; the TypeScript bullet now says "no longer an arm of the zod ObjectQLComponentSchema union", which is exact (the TypeScript union keeps ListViewSchema). Frontmatter unchanged. The types README's by-name list now names eleven block node types, ListViewBlockNode, ObjectPivotBlockNode and EmbeddableFormBlockNode added; all eleven are exported by name from packages/types/src/index.ts and match the eleven arms of ObjectQLPublicBlockComponentSchema at the head. True.

Check-runs on the head (re-read 2026-10-16T15:52Z): 36 runs, 33 success, 3 skipped (Test (coverage), its shard matrix, dependabot), 0 failed, 0 in_progress. The repository's ruleset names seven required contexts, Lint, Type Check, Build & E2E, Build Docs, Changeset Declaration, Test, Governed Surface Queue Guard: all success. Repo Gates (advisory; carries check:doc-json, check:doc-types) is success; Changeset Bump Policy, Changeset Fixed Group Check, Changeset Claim Re-read, Line Citation Gate, Test (dist pins) are success. The PR is a draft with no auto-merge request and mergeable_state: clean.

② Semver level

  • RIGHT: @object-ui/types: minor with the break in prose is the spelling objectui AGENTS.md §9 fixes (版本号策略: no major in a changeset; objectui's own breaking changes ship as minor with the breaking semantics written in the body; check-changeset-no-major runs in changeset-guard.yml, Changeset Bump Policy green). Frontmatter naming @object-ui/types alone is right: objectui validate moves through the dependency and the fixed group bumps together (Changeset Fixed Group Check green).
  • RIGHT: the changeset names everything a consumer loses. Enumerated from the diff: a flat objectName or viewType on a page list-view node (named, with the FROM → TO); the same pair in properties (named); any other list view prop written flat, data included (named as the "any other" clause, with the move into properties); a properties.type outside the spec's view-kind enum (named: the bag's type is the spec's enum); a page chart list with no dataset binding (named: refused at properties.chart, as the spec refuses it); the list-view member of AnyComponentSchema's inferred type changing from the flat mirror to the bag arm (named: the arm is the new ListViewBlockSchema); a direct ObjectQLComponentSchema parse of any list-view node (named, with where to parse instead); ObjectQLComponentSchema's inferred type losing the member (named: no longer an arm of the zod union). Nothing that parsed before and is refused now is left unnamed; the widenings (the ruled node, a bound node, inline rows, the arm at a child slot) are stated.
  • RIGHT: the PR body's Clause-②: yes (narrowing) matches the diff: it widens and narrows, the closed pair takes one arm, and the narrowing arm is the one that decides the review owed. The fleet's one reader (clause2-line.mjs) takes the line off the PR body or any committed changeset, and yes (narrowing) maps to the narrowing face; Changeset Declaration (check-changeset-presence.mjs) reads no such line and is green.
  • Observed, not owed: the five precedent arm-move entries carried a bold Clause-②: yes (narrowing) banner line inside the changeset body ("Released as minor under the objectui narrowing rule, with this banner"); this changeset carries the declaration on the PR body only and spells the levelling as "The bump is minor by this repo's release model", the spelling the 17.7.0 entries already shipping at the top of the CHANGELOG use. No objectui gate reads a changeset's Clause-②: line, the face is read off the PR body, and the BREAKING section with the FROM → TO is what an upgrading reader greps. A banner line at the start of a line in the changeset would put this entry in the five precedents' spelling; it changes no verdict here.

③ Boundary flags

  • Nothing is owed before this head lands. main carries the renderer half (5c0846e) and this branch merged it (badde80), so the tree the queue rebuilds is the one judged above: on it the face and the renderer agree on the kind (one enum, nine kinds, equal to the drawable set), on the binding (a non-empty dataSource.object on both), on the retired pair (refused at validate, removed with a warning at render) and on the record source up to the one residual below. The earlier record's three landing conditions are met on this head: the merge after objectui#12668, the plugin-list README rider, the changeset sentence; its recommendation, the types README line, is in too. The governed guard reads this PR as NOT GOVERNED, so the landing waits on this record alone (needs:contract-review, triage 6216264566), then the queue.
  • Open question 1 (report 6217824753, answered A by the seat in 6218339393): still A, nothing on this head makes it wrong. The governing text is requireRecordSource's docblock in objectql.zod.ts: presence is !== undefined on the rungs, the wording of the maintainer ruling recorded 2026-09-02, and the binding's non-empty test is the separately ruled rung (objectui#11117). The head keeps both. What the merge adds to the question is the renderer's own answer for the empty case: namesRecordSource draws the no-object hint for data: { provider: 'object', object: '' }, which is also the registration default plugin-list/src/index.tsx publishes for an unfilled designer node. So B would refuse the designer's default at validate while the renderer answers it visibly, and would fork the shared rule on one arm; A keeps one rule for every arm, and validate's sentence in the README ("a node with neither is refused") stays true, since it speaks of declaring a source, not of its value. If the maintainer wants the empty object refused at validate, that is a card on requireRecordSource for every arm together with the registration default, under its own ruling; not escalated here.
  • The spec-side half of ruling C stays with objectstack. The ComponentPropsMap['list-view'] row, its by-name refusals at lint tier and the ADR-0087 D2 conversion for stored nodes are spec(ui): ComponentPropsMap has no list-view row, so a page-embedded list view's properties are judged by nothing: kanban.groupField and options.grid pass on a page while every list-view door refuses them objectstack#22444's second act, after this lands and the console pin moves; nothing in this PR pre-empts them, and the face here reads the spec by reference, so the row can land without a second edit to this arm. The changeset names the conversion as the carrier for stored nodes, never a fallback read.
  • Two fences carry "type": "kanban" inside properties, in packages/types/src/zod/README.md and in the changeset. Both sit outside check-doc-component-types.mjs's walk (content/docs/**, the root README, app docs and packages/NAME/README.md only), which is why the plugin-list README alone keeps the kind in prose; Repo Gates is green. Should that gate ever walk nested READMEs or .changeset/**, it would need to read a bag's type as a list kind, not a component type. Noted, no action.
  • A nit, not owed: the types README's FlexBlockNode bullet still says "flex and object-chart have no ComponentPropsMap row"; object-pivot, embeddable-form and now list-view have none either. True as written, no longer the whole list.
  • Nothing else found. The test-only helper list-view-page-node.ts is under __tests__/, excluded from the build, and reached by the type-check test leg; the arm's check:handler-key-reads and check:element-data-source-declaration dispositions are read off the arm in the required Type Check job, green.

Implemented-by: claude/issue-12670-list-view-page-face
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

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 ObjectQLComponentSchema's lost list-view arm in the precedent's spelling and the types README names all eleven exported block node types. Re-verified, not adopted: the page arm agrees with the renderer now on main on the kind, the object, the binding and the refusals; the bag is the mirror's members by reference with the three ruled differences; the flat and runtime-slot refusals, the spec refinements in the bag and the census re-spells hold; open question 1 stays A. Rendered 2026-10-16T16:01Z.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · domain:ui seat 3 · session_01Vk15bz8xHtKGUfXfCm16h4 · 2026-10-16T16:03Z

Head reviewed: 5bb1b1d1594f2a3e70e019a417130a8823b46a0f.

Implemented-by: claude/issue-12670-list-view-page-face
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

1. Shape.

  • Draft PR against main. The body's first line is Fixes #12670, and the body has no other closing keyword (scanned in full).
  • 30 files, +1160/−69.
  • Changeset .changeset/12670-list-view-page-face.md: @object-ui/types: minor, with the break in prose. It names ObjectQLComponentSchema's lost list-view arm in the precedent's spelling. No major (objectui AGENTS.md §9).
  • No content/docs/releases/.
  • The paths are the re-stated claim's surface. The dev reported four test and doc-comment paths beyond its literal list: objectql.ts's doc comment, the test helper, and two plugin-list pins that judge a list view at the door. All four are tests or docs the face judges, and the review read them.
  • The PR body was refreshed by the seat for the landing head. No commit moved.

2. Premises measured.

  • The face, probed by the dev on the built @object-ui/types dist at the head (report 6219028517):
    • ObjectQLComponentSchema.safeParse refuses a list-view node on the discriminator;
    • ListViewBlockSchema / AnyComponentSchema accept the ruled page node and refuse the flat one;
    • on StrictAnyComponentSchema, properties.type: board is refused at properties.type;
    • objectName, flat and in the bag, and viewType in the bag are refused at their own paths, naming the replacement;
    • a node with no record source gets the record-source code at properties.data.
  • The README fence: at badde80, check:doc-json reproduced the red ("the strict face ACCEPTS this list-view node … delete the marker"). At 5bb1b1d it judges 246 accepted, 0 refused.
  • The renderer on main (5c0846e) and this face agree on the kind (one enum, nine kinds), the object (properties.data or a bound dataSource.object) and the retired pair. The review re-read both at the head.
  • No browser check. This PR changes what objectui validate and the strict face accept, not a screen. The renderer's screen was feat(plugin-list): a page list-view node is written data / type, and the metadata page reads properties.type as the list kind (objectui#12099) #12668's, and is on main.

3. Gates (check-runs pinned to this head).

  • 36 runs: 33 success, 3 skipped (Test (coverage), its matrix row, dependabot), 0 red.
  • Among the successes: the required Lint, Type Check, Build & E2E, Build Docs, Changeset Declaration, Test and Governed Surface Queue Guard; also Repo Gates (check:doc-json, check:doc-types, check:handler-key-reads), Test (dist pins), Bundle Analysis (PASS, 6218576469), Live E2E (informational), Line Citation Gate and the changeset checks.
  • The dev's local subset at this head: 389 files / 10,591 tests, type-check 0, the doc and changeset gates 0. It is in report 6219028517.

4. Accepted deviations.

  • The bag is the flat mirror's members by reference, on the ObjectChartBlockSchema precedent, not the spec ListViewSchema. The installed spec 18.0.0-next.2 has no ComponentPropsMap['list-view'] row, and the spec schema requires columns.
  • checkListViewChartBinding is attached in the bag. That adds one disclosed narrowing: a page chart list with no dataset binding is refused at properties.chart.
  • Open question 1 is answered A (6218339393): the shared presence rule stands, so data: { provider: 'object', object: '' } validates and draws feat(plugin-list): a page list-view node is written data / type, and the metadata page reads properties.type as the list kind (objectui#12099) #12668's no-object hint, as objectName: '' did.
  • Prose checked against the diff and the dev's probes:
    • the changeset's BREAKING lines (FROM → TO for objectName, viewType and every flat list prop) and its ObjectQLComponentSchema sentence;
    • the plugin-list README's new paragraph on what the face judges: record source, refusals by name, an unknown properties.type, a flat list prop;
    • the types README's list of eleven block node types.

5. Out of scope (where each went).

6. Landing.

  • Not governed: check-governed-queue-guard.mjs --test over the 30 paths reads NOT GOVERNED.
  • 1229 lines changed, under the 3000-line threshold.
  • Clause-②: yes (narrowing), with a same-head CONTRACT_REVIEW_TIER PASS on record.
  • Every check is green or an expected skip. The landing order triage set is met.
  • ⇒ The seat lands it: relay pr_ready + automerge_enable, through the merge queue.
  • On MERGED, Fixes closes objectui#12670. The seat then strips pm:dispatched and reads closed_by.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 16:04
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 16:04
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 378896d Oct 16, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12670-list-view-page-face branch October 16, 2026 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: types plugin tests

Projects

None yet

2 participants