Skip to content

fix(plugin-kanban,plugin-list): a list view's kanban draws every record of the view, a page per lane, and cards carry the view's first columns (objectui#12619) - #12643

Merged
objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-12619-kanban-all-records
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-12619-kanban-all-records

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Fixes #12619
Clause-②: yes (corrected by the seat from the claim's provisional no, on the measurement below; corrected claim 6211796112 on objectui#12619)

Clause-② measurement, for the seat to correct the line above. The board's paging needs two new optional exported props. Built packages/plugin-kanban/dist/ObjectKanban.d.ts declares lanePaging?: KanbanLanePagingRequest and ownerField?: string on ObjectKanbanComponentProps, and imports KanbanLanePagingRequest from ./KanbanLanePaging.js, so that interface joins the published declaration closure through the props type (it is not re-exported by name from the barrel). No @object-ui/types member is added. The authored accept set does not change: no key is added to the object-kanban node or to the view's kanban block.

What changed

  • Each lane is its own query (@object-ui/plugin-kanban, new KanbanLanePaging.ts). ObjectKanban takes a host prop, lanePaging ({ search?, searchFields?, reloadKey? }). With it, the board asks each lane for its first 50 records: the node's filter AND [laneField, '=', laneId], the node's sort, $count: true, $top: 50. The lane's header count is the answer's total. A lane holding more shows Load more at its foot ($skip = what the lane holds). One more query, or(nin lane ids, is_null), fills the trailing Uncategorized lane. A refresh (host reloadKey, the board's own onMutation or invalidation) asks each lane again at the depth it was loaded to. Counts follow an optimistic drag or delete until the next read. Lanes are paged only when they are known before the query (declared lanes, or the lane field's options) and the board draws no swimlanes. A board without the prop, the standalone object-kanban included, keeps its one query capped by limit.
  • ListView hands the board the query, not a page (@object-ui/plugin-list, kanban branch and the props it hands the board). New kanbanLanesPaged: the lane field's options are known, no swimlane grouping, and this view fetches for itself. Then the board is handed no data. Its node carries the effective filter (selfQueryFilter, as gantt, tree, chart and the server-grouped grid get it). It is handed lanePaging with the toolbar term, searchableFields and refreshKey plus refreshTrigger. The view's own window is still fetched for the empty state, the export and the filter option counts, as for the server-grouped grid. On such a board the footer shows the view's record count from that query's total, without the "Showing first N records" line or the Rows per page picker.
  • Cards carry the view's first columns. With no kanban.columns, the board's cardFields are the view's next two columns past the card title (titleField, resolveNameField), the lane field and the owner field, read by name through columnIdentity. Before, the view's columns went out whole, as { field } entries that the card reads as field names, so a card drew no field lines; below its name it showed at most a subtitle the board derives from the record, and on HotCRM's measured board the name alone. An authored kanban.columns is the author's list and is used whole. cardFields stays the generated node's own spec key (ObjectKanbanPropsSchema: "Fields rendered on each card"). Nothing reads or writes cardFields at the view level.
  • A card field is a line with its label (KanbanImpl): a muted label, then the value. The label used to be an sr-only term plus a tooltip. The card header restates its reduced foot (sm:pb-2) and the card content its reduced top (sm:pt-0): sm:p-4 is emitted after pb-2 / pt-0, so from sm up both padded back to 16px, a blank band between the title and the first field line on every card with field lines.
  • The owner's avatar. ListView names the owner field from the spec's declaration, never a guessed name: resolveInjectedSystemColumns(objectDef).owner and SystemFieldName.OWNER_ID, and the object definition must declare the field. The board draws the expanded owner's initials or picture, gated on field-level security for the owner field and filtered with withoutDeniedFields for the person (new KanbanCardOwner.ts). A bare id draws nothing.
  • kanban.loadMore in all ten language packs; docs in content/docs/plugins/plugin-kanban.mdx; one changeset.

Mechanism hypotheses, measured

  1. Confirmed on 79c1996. The acceptance test below read expected [ …(25) ] to have a length of 45 but got 25. The kanban branch is not paginate, so effectivePageSize resolves the view's declared pagination.pageSize (25). With no declared size it is the fetch batch, 100. That window went down as data. The name-only cards are read in source (column entries as { field } objects), not separately measured on base: the base run failed at the card count first.
  2. The DataSource can answer it. find returns QueryResult.total ("Total number of records (if requested)"), and QueryParams.$count is the declared request, which the lane queries send. queryGroupHeaders also counts, but it is optional, and one find per lane gives both the rows and the count. A gap, not filed: @object-ui/data-objectstack's normalizeQueryResult answers total ?? count ?? records.length, so a server that sends no total would read as "total = page". ObjectStack's findData sends a total.
  3. Confirmed against installed @objectstack/spec@18.0.0-next.1. KanbanConfigSchema is a strictObject of groupByField, summarizeField, titleField, columns ("Fields to show on cards"); it has no cardFields.
  4. No new spec key needed. The 50-per-lane page is the renderer's constant, as the card names it, and not authorable. No Seam: finding.
  5. Drag keeps today's write. The existing move pins pass (rejected-move rollback, requiredWhen prompt, the move grant, landing position, same-column drop). A new lane-mode pin drops a card and reads update(OBJECT, 'open-000', { stage: 'won' }), with both lane counts following the card.
  6. The owner is declared by the spec (ownership, resolveInjectedSystemColumns, SystemFieldName.OWNER_ID), so the avatar is wired. An object with ownership: 'org' gets no owner field (pinned).

Tests (at 73cab08, the merged tree)

  • Before, on 79c1996: packages/app-shell/src/__tests__/listKanbanEveryRecord-12619.test.tsx failed 2 of 2 (25 of 45 cards).
  • After: pnpm exec vitest run --maxWorkers=2 packages/plugin-kanban/ packages/plugin-list/ plus five app-shell kanban files (the new acceptance test, displayPageSizeFromSpec-9853, listCalendarDateWindow-12081, ObjectView.kanbanSummarizeField-11629, ObjectView.kanbanLane-8193) gave Test Files 214 passed (214) and Tests 1975 passed (1975).
  • New pins: ObjectKanban.lanePaging-12619.test.tsx (10 cases: per-lane counts past a window, the query shape, Load more, Uncategorized, search and refresh depth, two one-query controls, drag, owner avatar and its controls) and ListView.kanbanOwnsLanes-12619.test.tsx (9 cases: data withheld, effective filter, footer count, card fields by name, the authored override, owner field and its ownership: 'org' control, and two window-keeping controls). The acceptance test asserts 45 cards across seven lanes with page size 25, and a card that shows Account and Amount with labels but not the third column.
  • Re-judged pins: ListView.viewSwitchRefetch-7394 §1 now asserts that the board got no rows plus the lane request; §5's banner control uses a board with no lane options. ListView.calendarDateWindow-12081's board control waits on the lane request. Each pin still counts the list's own query as before.
  • pnpm --filter @object-ui/plugin-kanban type-check and pnpm --filter @object-ui/plugin-list type-check: exit 0, after building the dependency closure.
  • Patch round 1 (28ce461, merged as ac87f7b): the title row that places the owner avatar is drawn only when the card has an owner, so a board with no owners keeps its markup. kanban-column-cards-6939 is green against its unchanged PRE_REPAIR readings (64 and 86 elements); it read 68 and 90 on 73cab08. Test (shard 1/16) is green on ac87f7b.
  • Patch round 2 (62cc21c, merged as 53c6200): cardPaddingEveryBreakpoint-12619 pins the padding rule over the rendered classes; kanban-column-cards-6939 green with its readings unchanged; vitest 76 files / 1116 tests green; pnpm --filter @object-ui/plugin-kanban type-check 0.

Gates (local subset; the rest is CI's)

node scripts/check-changeset-presence.mjs 0 · pnpm check:new-line-citations 0 (0 new) · check:i18n-keys / check:i18n-drift / check:i18n-dead-keys 0 · eslint on the changed files: 0 errors · check:control-bytes, check:phantom-deps, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots, check:handler-key-reads, check:unreferenced-sources, check:changeset-claims, check:pending-changeset-literals, check:doc-fences, check:unused-deps 0. NOT MEASURED: check:readme-exports (population collapsed: unbuilt packages) and check:doc-snippets (exit 2, precondition not met); @object-ui/app-shell type-check (closure unbuilt). CI runs all three.

Screenshot

NOT MEASURED: screenshot, reason: this container has no backend to serve the board. HotCRM is not checked out, and the sibling objectstack checkout is uninstalled and unbuilt. The seat runs the 1280 px HotCRM board check at review.

Acceptance notes

  • Outside the named file surface: content/docs/plugins/plugin-kanban.mdx (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2, docs-driven) and the cross-package acceptance test in packages/app-shell/src/__tests__/. That package is the one that depends on both halves (the reason listCalendarDateWindow-12081 lives there). kanbanViewOptions in app-shell is untouched.

  • Design boundary: swimlane boards and boards whose lane field declares no options keep the list's window and its "Showing first N" banner. The standalone object-kanban keeps limit. Lane paging is a host request on purpose: limit is declared as the board's row cap.

  • On a lane-paged board, the list still issues its own window query, which feeds the empty state, the export, the filter counts and the footer total. That is one extra query, the same arrangement as the server-grouped grid.

  • Lane queries match the stored lane value exactly. A record whose value differs only by case comes back from the in-no-lane query, and the client's case-folded bucketing puts it in its lane. Header counts still equal the cards drawn.

  • The label on each card field reverses a code comment that kept values only. The card asked for "label: value" lines.

  • Overlap with ListView.tsx work in flight today: PR fix(plugin-list): Display menu closes after a layout is chosen (objectui#12621) #12632 was already in this branch's base, and PR fix(plugin-grid,components,types): a grouped grid draws one header row, with group bands between the rows (objectui#12620) #12633 changed no file here. origin/main (a8560b2) was merged once with no conflict, and the gates above ran on the merged tree.

  • Adds no product-specific widget, dialog, hook or string (see AGENTS.md › Product-neutral renderer)


Generated by Claude Code

…s carry the view's first columns

The board under a list view drew the list's window (one grid page) bucketed
into lanes. ListView now hands the board the view's query instead of rows
(`lanePaging` host prop): ObjectKanban asks each lane for its first 50
records with the lane's count, plus one query for records in no lane, with a
"Load more" at each lane's foot. Cards take the view's next two columns past
the title, lane and owner, by name, and render label and value; the owner's
avatar comes from the spec-declared owner field.

Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4
Co-authored-by: Claude <noreply@anthropic.com>
…t handed it

Since objectui#12619 a board whose lanes are known pages them itself and is
handed no rows. The two query-count pins assert that instead; the row-cap
banner control uses a board that keeps the window.

Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4
Co-authored-by: Claude <noreply@anthropic.com>
…r avatar; changeset

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) 3094.0 KB 3119.4 KB
Main entry chunk (gzip) 73.3 KB 350 KB
Entry file index-DsOh6To9.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) 18.15KB 5.40KB
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.04KB 1.72KB
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) 598.49KB 144.31KB
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) 283.17KB 72.17KB
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) 262.91KB 69.49KB
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) 265.13KB 73.29KB
plugin-kanban (index.js) 59.19KB 18.46KB
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

…wner to place

The row that places the owner's avatar beside the title was drawn on every
card, one element more per card on a board with no owners, which moved the
schema-catalog render pin (kanban-column-cards-6939). A card with no owner
draws its title exactly as before.

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) 3094.9 KB 3119.4 KB
Main entry chunk (gzip) 73.8 KB 350 KB
Entry file index-BxN0h185.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) 598.49KB 144.31KB
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) 283.17KB 72.17KB
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) 262.91KB 69.49KB
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) 265.13KB 73.29KB
plugin-kanban (index.js) 59.40KB 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: TIER_DEFAULT
Head-sha: ac87f7b94a1fb8bbcaf11817204ca739eae82f88
Local-runs: none

The face: the Clause-②: yes declaration alone. Corrected claim 6211796112 on objectui#12619, and the PR body's second line since this seat's edit. The committed tree touches no packages/spec/src/**, no @object-ui/types file and no governed path, so TIER_DEFAULT is the face's tier. Inputs read: the card objectui#12619, the PR diff at the head above (patch round 28ce461 changes one JSX branch of KanbanImpl.tsx, the owner title row; merge ac87f7b brings origin/main and touches no file of this PR), packages/plugin-kanban/src/index.tsx, packages/plugin-list/src/index.tsx, both packages' package.json (exports, peerDependencies) at that head, and the head's check-runs. Read 2026-10-16T09:28Z.

① Derived judgments

  1. ObjectKanbanComponentProps.lanePaging?: KanbanLanePagingRequest — public surface grows, additively; correct. @object-ui/plugin-kanban's one entry (exports["."] → dist/index.d.ts) carries export type { ObjectKanbanComponentProps } from './ObjectKanban', so the optional prop and the interface it names (search?, searchFields?: readonly string[], reloadKey?: string | number) are published. It is a host channel, not an authoring key. src/index.tsx is not in the diff, so the object-kanban registration and its designer inputs are unchanged. A board without the prop keeps its one limit-capped query (pagedLaneIdsKey is null when lanePaging is absent).
  2. ObjectKanbanComponentProps.ownerField?: string — additive; correct. The board guesses no field name. Its only writer, ListView's kanbanOwnerFieldOf, answers from the spec's declaration (resolveInjectedSystemColumns(objectDef).owner and SystemFieldName.OWNER_ID) and only when the object definition declares that field. One default is noted, not judged wrong: the person's object falls back to sys_user when the owner field names no reference. The comment says that is the object the grid's user cell reads, and SystemFieldName.OWNER_ID is the platform's user-owner field.
  3. No new runtime name on either entry. KANBAN_LANE_PAGE_SIZE and the lane helpers are package-private (KanbanLanePaging.ts is not re-exported). KANBAN_VIEW_CARD_FIELD_COUNT is exported from ListView.tsx, but @object-ui/plugin-list's src/index.tsx re-exports by name only, and it is not among them.
  4. Authoring accept set unchanged; correct. No key is added to the object-kanban node or to the view's kanban block. The card-field override reads the spec's kanban.columns whole. ⛔ cardFields is not re-admitted as an authoring key: the diff's cardFields is the existing internal board prop.
  5. Published language-pack key kanban.loadMore, additive in all ten packs (ar … zh). @object-ui/i18n publishes its packs and the keys typed from them, so this widens that surface by one key. Every pack carries it, and Lint and Repo Gates are green on this head: 33 check-runs success, 3 skipped, none red.
  6. New runtime import from a peer: @objectstack/spec/data and @objectstack/spec/system in ListView.tsx. @object-ui/plugin-list declares @objectstack/spec as a peerDependency (^18.0.0-next.1), and both subpaths are already imported elsewhere in this repo (app-shell). No dependency is added.
  7. Behaviour door, not contract: the lane and uncategorized filters are built from operators the spec's filter AST names (=, nin, is_null, joined under or), through @object-ui/core's mergeFilterNodes.

② Semver level

The changeset declares @object-ui/plugin-kanban: minor, @object-ui/plugin-list: minor, @object-ui/i18n: patch, and no major (objectui AGENTS.md §9). The additive props match minor. The one additive i18n key is declared patch, but the packages are one fixed group (.changeset/config.json), so the group releases at the highest level declared, minor; nothing ships under-declared. The changeset text names both new props and the key under "Public surface".

③ Boundary flags

  • The dev's Clause-② measurement (report 6211687683) is answered by ① 1–3 and the corrected claim.
  • Card lines become "label value" for every kanban card, a visible change beyond list-view boards: the card asks for it (target 2), and the code comment it reverses is replaced, not left contradicting. It goes to the seat ACCEPT's browser readings and the maintainer's screenshot acceptance; it is not a contract flag.
  • The out_of_scope_findings:
    • normalizeQueryResult's total ?? count ?? records.length is a pre-existing consumer default, and the platform sends total. No reach, so it is an Acceptance note, not a card.
    • The swimlane and option-less boards keep the window by design (the card's lanes must be known before the query).
    • Neither changes this verdict.

Implemented-by: claude/issue-12619-kanban-all-records
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

VERDICT: PASS


Generated by Claude Code

…t; changeset says what the old card drew

`sm:p-4` is emitted after the header's `pb-2` and the content's `pt-0`, so
from `sm` up both sides padded back to 16px: a blank band between the title
and the first field line on every card with field lines, now every list-view
card. Both sides are restated at `sm:`, pinned as a rule over the rendered
classes. The changeset no longer says the old card drew nothing below its
title: it drew a derived subtitle where the record yields one, and on HotCRM's
measured board the name alone.

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) 3095.8 KB 3119.4 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-BRwu0u2p.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.83KB 144.29KB
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) 283.17KB 72.17KB
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) 262.91KB 69.49KB
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) 265.13KB 73.29KB
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: TIER_DEFAULT
Head-sha: 53c62007a5d99c1644c729fc16586d878b73e2cf
Local-runs: none

The face: the Clause-②: yes declaration alone. Corrected claim 6211796112 on objectui#12619, and the PR body's second line since this seat's edit. The committed tree touches no packages/spec/src/**, no @object-ui/types file and no governed path, so TIER_DEFAULT is the face's tier. Inputs read: the card objectui#12619, the PR diff at the head above (patch round 1 28ce461: one JSX branch of KanbanImpl.tsx, the owner title row; patch round 2 62cc21c: two padding class tokens in KanbanImpl.tsx, a new class-rule pin and the changeset's old-card sentence; merges ac87f7b and 53c6200 bring origin/main and touch no file of this PR; neither round touches an exported type or an entry), packages/plugin-kanban/src/index.tsx, packages/plugin-list/src/index.tsx, both packages' package.json (exports, peerDependencies) at that head, and the head's check-runs. Read 2026-10-16T10:34Z.

① Derived judgments

  1. ObjectKanbanComponentProps.lanePaging?: KanbanLanePagingRequest — public surface grows, additively; correct. @object-ui/plugin-kanban's one entry (exports["."] → dist/index.d.ts) carries export type { ObjectKanbanComponentProps } from './ObjectKanban', so the optional prop and the interface it names (search?, searchFields?: readonly string[], reloadKey?: string | number) are published. It is a host channel, not an authoring key. src/index.tsx is not in the diff, so the object-kanban registration and its designer inputs are unchanged. A board without the prop keeps its one limit-capped query (pagedLaneIdsKey is null when lanePaging is absent).
  2. ObjectKanbanComponentProps.ownerField?: string — additive; correct. The board guesses no field name. Its only writer, ListView's kanbanOwnerFieldOf, answers from the spec's declaration (resolveInjectedSystemColumns(objectDef).owner and SystemFieldName.OWNER_ID) and only when the object definition declares that field. One default is noted, not judged wrong: the person's object falls back to sys_user when the owner field names no reference. The comment says that is the object the grid's user cell reads, and SystemFieldName.OWNER_ID is the platform's user-owner field.
  3. No new runtime name on either entry. KANBAN_LANE_PAGE_SIZE and the lane helpers are package-private (KanbanLanePaging.ts is not re-exported). KANBAN_VIEW_CARD_FIELD_COUNT is exported from ListView.tsx, but @object-ui/plugin-list's src/index.tsx re-exports by name only, and it is not among them.
  4. Authoring accept set unchanged; correct. No key is added to the object-kanban node or to the view's kanban block. The card-field override reads the spec's kanban.columns whole. ⛔ cardFields is not re-admitted as an authoring key: the diff's cardFields is the existing internal board prop.
  5. Published language-pack key kanban.loadMore, additive in all ten packs (ar … zh). @object-ui/i18n publishes its packs and the keys typed from them, so this widens that surface by one key. Every pack carries it, and Lint and Repo Gates are green on this head: 33 check-runs success, 3 skipped (the coverage legs and dependabot), none red, each pinned to this head.
  6. New runtime import from a peer: @objectstack/spec/data and @objectstack/spec/system in ListView.tsx. @object-ui/plugin-list declares @objectstack/spec as a peerDependency (^18.0.0-next.1), and both subpaths are already imported elsewhere in this repo (app-shell). No dependency is added.
  7. Behaviour door, not contract: the lane and uncategorized filters are built from operators the spec's filter AST names (=, nin, is_null, joined under or), through @object-ui/core's mergeFilterNodes.

② Semver level

The changeset declares @object-ui/plugin-kanban: minor, @object-ui/plugin-list: minor, @object-ui/i18n: patch, and no major (objectui AGENTS.md §9). The additive props match minor. The one additive i18n key is declared patch, but the packages are one fixed group (.changeset/config.json), so the group releases at the highest level declared, minor; nothing ships under-declared. The changeset text names both new props and the key under "Public surface".

③ Boundary flags

  • The dev's Clause-② measurement (report 6211687683) is answered by ① 1–3 and the corrected claim.
  • Card lines become "label value" for every kanban card, a visible change beyond list-view boards: the card asks for it (target 2), and the code comment it reverses is replaced, not left contradicting. It goes to the seat ACCEPT's browser readings and the maintainer's screenshot acceptance; it is not a contract flag.
  • The out_of_scope_findings:
    • normalizeQueryResult's total ?? count ?? records.length is a pre-existing consumer default, and the platform sends total. No reach, so it is an Acceptance note, not a card.
    • The swimlane and option-less boards keep the window by design (the card's lanes must be known before the query).
    • Neither changes this verdict.

Implemented-by: claude/issue-12619-kanban-all-records
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

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

Head reviewed: 53c62007a5d99c1644c729fc16586d878b73e2cf (round 0 73cab08, patch rounds 28ce461 and 62cc21c, main merges ac87f7b and 53c6200). Card objectui#12619; claim 6211796112 (Clause-②: yes); contract review of record 6213603195 (TIER_DEFAULT, PASS, this head).
Implemented-by: claude/issue-12619-kanban-all-records
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

1. Shape. Draft PR against main. The body's first line is Fixes #12619, and the body carries no other closing keyword (scanned in full). 22 files, +1510/−41. Changeset .changeset/12619-kanban-every-record.md: plugin-kanban and plugin-list minor, i18n patch, no major; all three are in the fixed group. No content/docs/releases/. Two files outside the first claim were taken into the corrected claim: content/docs/plugins/plugin-kanban.mdx (AGENTS.md #2) and the app-shell acceptance test.

2. Premises measured.

  • Seat's browser check: objectstack examples/app-crm on objectstack origin/main, crm_opportunity, 80 records (prospecting 56 · qualification 5 · proposal 4 · closed_won 9 · closed_lost 4 · empty stage 2), the console from this PR's code at 1280 px. The view carries a 25-row page size and a kanban layout, added as a runtime overlay because app-crm's shipped all view offers no Layout row.
    • PR (round-1 head ac87f7b): every lane header equals its REST count. Prospecting draws 50 cards with Load more, which brings in the remaining 6 (top=50&skip=50) and leaves the header at 56. Uncategorized holds the 2 empty-stage records, from ["or",["stage","nin",[…5 lanes]],["stage","is_null"]]. The footer reads "80 records", with no "Showing first" and no Rows per page.
    • Drag prospecting → qualification: headers move 56→55 and 5→6, and a REST read-back shows stage: qualification.
    • Cards carry "Account …" / "Deal Value …" lines and the owner avatar ("DA", aria-label "Dev Admin").
    • Negative control, origin/main at the same overlay: 25 cards in all (prospecting 17 · qualification 1 · proposal 2 · won 3 · lost 2), headers counting the page, no Uncategorized lane, and the footer "Showing first 25 records. More data may be available."
    • Round 2 changed only two padding tokens, a pin and changeset text after that reading, so the lane readings carry to this head.
  • The same run found the 32 px band between title and first field line (sm:p-4 overriding pb-2 / pt-0). Round 2 restates both sides at sm:, and cardPaddingEveryBreakpoint-12619 pins it.
  • The cardFields premise: the card's override key is read as the spec's kanban.columns, and cardFields is not re-admitted at the view level.

3. Gates (check-runs pinned to this head). 33 success, 3 skipped (Test (coverage), its matrix row, dependabot), 0 red. Among them: Lint, Type Check, Repo Gates, Test (shard 1/16) … Test (shard 16/16), Test (dist pins), Build & E2E, Build Docs, Bundle Analysis (budget PASS, comment 6213429690), Changeset Declaration, Changeset Bump Policy, Changeset Fixed Group Check, Line Citation Gate and Governed Surface Queue Guard. The local subset is in the dev's reports on the card. Round 0's Test (shard 1/16) red (kanban-column-cards-6939, 90≠86 and 68≠64) was fixed in round 1 with that pin's readings unchanged.

4. Accepted deviations.

  • Every kanban card's field lines show their label (target 2), which reverses a values-only code comment; the comment is replaced, not left standing.
  • ListView's change reaches beyond the kanban branch, keyed on kanbanLanesPaged: the selfQueryFilter gate, the hand-off and the footer, as the card's footer target needs.
  • The list keeps its own top-N query beside the lane queries for the footer total, the empty state and the export, as documented.
  • Prose checked sentence by sentence against the diff:
    • in the changeset, "Each lane is its own query", "A refresh asks each lane again at the depth it was loaded to", "Which boards page their lanes", the corrected "Before, a card drew no field lines from the view's columns …", and "Public surface";
    • in the docs, "A list view whose kanban block names no columns hands the board the view's own next two columns …" and the new section "Every record of a list view, a page per lane".

5. Out of scope (where each went).

  • @object-ui/data-objectstack drops $count on both find routes, and normalizeQueryResult answers total ?? count ?? records.length. A backend that volunteers no total would read a full lane as exactly 50 with no Load more. Reach: none measured, because the ObjectStack server returns total unasked (seen on the wire in the seat's check). → Acceptance notes, not filed.
  • A board without lane options, with swimlanes, or a standalone object-kanban keeps its one capped query. → Design boundary, in the docs.
  • A view with a kanban block must carry columns (the platform refuses the block without it), so "no card fields of its own" is spelled columns: [] on such a view. → Noted.

6. Landing.

  • Not governed: check-governed-queue-guard.mjs --test over the 23 paths read NOT GOVERNED.
  • Under the 3000-line threshold.
  • Clause-②: yes, with a same-head TIER_DEFAULT PASS on record.
  • ⇒ The seat lands it: relay pr_ready + automerge_enable, through the merge queue.
  • On MERGED, Fixes closes objectui#12619. The seat then strips pm:dispatched, reads closed_by and reconciles the lane.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kanban: every record of the view in its column, not the first page; cards carry the view's first columns

2 participants