Skip to content

feat(fields,plugin-grid): a declared object-ref / recipient-picker widget names what the value references in every list (objectui#12613) - #12646

Draft
objectstack-fleet[bot] wants to merge 9 commits into
mainfrom
claude/issue-12613-sharing-rule-labels
Draft

objectstack-fleet[bot] wants to merge 9 commits into
mainfrom
claude/issue-12613-sharing-rule-labels

Conversation

@objectstack-fleet

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

Copy link
Copy Markdown
Contributor

Fixes #12613
Clause-②: yes — corrected from the claim's provisional no (claim 6214243680). Measured on the built packages/fields/dist/index.d.ts at d47fb07: six new exported names (UnresolvedReferenceMark, objectRefOptionLabel, RECIPIENT_RECORD_KINDS, RECIPIENT_REGISTRY_KINDS, FIELD_RECIPIENT_TYPE, recipientCandidateLabel), and two widened members: CellRendererProps gains the optional dependentValues, a string-keyed Record of unknown values (the generic is spelled in words because the body sanitizer drops angle-bracket shapes), and resolveCellRendererType's object arm gains widget?: string. @object-ui/app-shell's dist/index.d.ts gains only a side-effect import, and its package.json sideEffects names the new registration module. @object-ui/plugin-grid's published closure is unchanged. Stored values and the authored metadata accept set are unchanged.

What changed

The platform already declares the display intent: sys_sharing_rule.object_name is Field.text({ widget: 'object-ref' }) and recipient_id is Field.text({ widget: 'recipient-picker', dependsOn: ['recipient_type', 'object_name'] }) (objectstack origin/main 43567a8fc). The grid ignored it: resolveCellRendererType read only type and format, so both columns drew through the text cell. The producer is right; the renderer did not read a declared key. So the fix is in the renderer, keyed on the declared widget, never on an object or field name.

@object-ui/fields (the rule)

  • resolveCellRendererType promotes a textual field that declares widget: 'object-ref' or widget: 'recipient-picker' to the cell registered under that widget key. Other widgets (filter-condition, position-ref, …) and non-textual types keep their answer.
  • Both keys are registered with the stored text as their default face (the RECORD_POINTER_CARD_TYPE arrangement). A host without the label faces therefore draws exactly what it drew before.
  • CellRendererProps.dependentValues (optional): the row, the cell-side counterpart of the edit widget's dependentValues. A call site that passes nothing gets the text it drew before.
  • The recipient kind table moves into widgets/recipientKinds.ts. It is published with recipientCandidateLabel, objectRefOptionLabel (the picker's Label (name) spelling) and UnresolvedReferenceMark, for the host face. The edit widgets keep their own reads inline, exactly as on main, and list and store what they did.

@object-ui/app-shell (new: the label faces)

  • It registers the object and recipient faces under the two keys. They load, together with their label directory, lazily into WidgetRefCellFaces-*.js, outside the eager closure.
  • Object face: icon and label come from the console metadata store's object list (ensureType('object'), the same GET /meta/object list the picker offers), and the tooltip reads Label (name). The icon is drawn as the console's navigation draws an object's (LazyIcon, falling back to the Database glyph).
  • Recipient face:
    • Users, teams and business units are named by EXACT id: every id any cell asks for in one tick goes out as one $in query per kind (chunked at 100).
    • A recipient past the picker's first 500 candidates is named too.
    • Fields the viewer may not read are dropped (withoutDeniedFields), as the lookup picker drops them.
    • Positions come from the metadata store.
    • The field kind is read off the shared object's schema.
  • A value nothing names (deleted record, renamed object, a refused read) draws the raw stored value, muted, with the shipped unresolved-reference mark. It is never blank.

@object-ui/plugin-grid

  • resolveGridCellRendering carries the widget hint (GridCellFieldLike.widget). Column paths A–C pass it explicitly, and path D and the panel pass the whole field def.
  • Every type cell on paths A–D, the link cells and the inline record panel hand the row over as dependentValues.
  • The inline editor still reads declaredType. The grouped-band region objectui#12633 changed is untouched.

Why app-shell holds the faces: every packages/fields module rides the eager ui-components chunk, whatever imports it (scripts/vite-ineffective-dynamic-imports.ts). That chunk's per-chunk ceiling refused round 0's label reader: 289,748 / 289,000 gzip bytes measured on round 0's head. main alone sat at 288,585 at 8ed7e5a.

Premise measurements (dispatch §2)

  1. Confirmed: both widget hints and the recipient_type / access_level selects are on sys_sharing_rule, and the four listViews name the columns as strings (path B).
  2. Confirmed on origin/main by ablation: with the widget promotion disabled, the promotion cases go red (below).
  3. The Studio Access pillar's naming is not a shared helper: its explain report arrives already named from /api/v1/security/explain. The faces reuse the edit widgets' kind table and spellings instead.
  4. access_level already draws as a chip: SelectCellRenderer draws a Badge per option label. The platform declares no option colour, and the permission matrix's tones are private functions inside PermissionMatrixEditor, so no generic cell is coupled to them.
  5. Implemented as stated.

Card targets

  • 1 Object column: icon, label, and the api name in the tooltip — done.
  • 2 Recipient label — done for all kinds. The type chip before it ("Position · …") is an accepted deviation. Every list view that shows recipient_id also shows the recipient_type column beside it, and the chip's text is that sibling select's translated option label, which a cell does not hold.
  • 3 Access level chip — already a chip; the tokens are an accepted deviation (above).

Tests

  • Acceptance cases: packages/app-shell/src/views/widget-ref-cells/__tests__/WidgetRefCellFaces-12613.test.tsx.
    • sales_manager renders "Sales Manager".
    • The object renders its icon and "Account", with tooltip "Account (crm_account)".
    • A recipient past the first 500 candidates is named by exact id, in exactly one $in query per kind.
    • A denied name field is left out of the label.
    • An unknown id reads muted.
  • packages/plugin-grid/src/__tests__/widgetHintedColumns-12613.test.tsx pins the widget key and the row on paths A–D with probe faces.
  • packages/fields/src/__tests__/widgetRefCells-12613.test.tsx pins the promotion, the default faces and the published spellings.
  • Round 2 on d47fb07: the targeted 21 files → Test Files 21 passed (21), Tests 572 passed (572). Ablations on the committed head (scripts/ablation-replace.mjs, each restore proven: blob == HEAD, git diff HEAD empty):
    • record reads put back on the candidate query → 2 red (exact id, and the policy case past the first page);
    • icon dropped → 1 red;
    • withoutDeniedFields removed → 1 red.
  • Round 0 ran the full packages/fields/, packages/plugin-grid/ and packages/plugin-detail/ suites (751 files, 8776 tests green). Round 1 ablations: promotion guard disabled → 7 red across the three files; the recipient-picker registration deleted → 2 red.
  • Censuses: object-ref / recipient-picker are classified in cellRenderers.objectLiteral-8596 and in summaryChip.badgeFitCensus-8464 (whose fit-side count moves 36 → 38).

Gates (local subset, on d47fb07)

turbo run build --filter='./packages/*' 0 · fields / app-shell / plugin-grid type-check 0 · pnpm --filter @object-ui/console build 0 · node scripts/check-eager-closure-budget.mjs 0 · pnpm check:sdui-registration-pins 0 · check-side-effects-array 0 · check-phantom-dependencies 0 · eslint on the changed files: 0 errors · check-changeset-presence 0 · check:new-line-citations 0 new · governed-queue guard NOT GOVERNED · control-byte scan: none.

Merge round, head f667f86 (merges origin/main f78efdd; report 6216423846): one conflict, in packages/plugin-grid/src/ObjectGrid.tsx against objectui#12608. The same seven cell closures changed on both sides. Each keeps main's pointerFace?.(row) ?? first, and this branch's dependentValues={row} on the fallback renderer element. The 21 targeted files plus ObjectGrid.recordPointerCell-12608 → Test Files 22 passed (22), Tests 575 passed (575). The package build, the three type-checks, the console build and check-eager-closure-budget exit 0. check:sdui-registration-pins, check-side-effects-array, eslint on the resolved file, check-changeset-presence and check:new-line-citations exit 0.

Bundle (on f667f86): ui-components 288,876 / 289,000 gzip bytes; eager closure 3118.4 KB of 3119.4 KB. main's v18 dependency bump took most of the aggregate. On d47fb07 the closure was 3096.6 KB. The faces chunk is lazy. No ceiling, budget file, allow-list or chunk group was touched.

Browser check (1280 px): run by the seat on d47fb07. The readings are in the seat's ACCEPT on this PR.

Surface notes

  • @object-ui/app-shell was added on the dev's measurement (corrected claim 6214243680): src/views/widget-ref-cells/**, src/index.ts (the side-effect import) and package.json sideEffects. The changeset lists @object-ui/app-shell: minor.
  • Also outside the first surface, both forced by the change: two census rows (plus the fit-side count) in packages/plugin-detail/src/__tests__/summaryChip.badgeFitCensus-8464.test.tsx, and the @object-ui/fields README cell-resolution example (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2).

Acceptance notes (not done here; carrier: none)

  • DetailSection (@object-ui/plugin-detail) resolves object_name to the object face but passes no row, so a record page's recipient_id still reads as text. Passing dependentValues={data} there is one line.
  • The By Object view's group band prints the object api name: band labels are strings built in the grid's grouping, not cells.
  • Kanban and gallery cards resolve the same way: the object is named, and the recipient reads as text (no row handed over).
  • @objectstack/spec's widget description says "Form widget override"; list cells now read it for these two hints too.
  • On f667f86, ui-components has 124 gzip bytes of headroom, and the eager closure as a whole has 1.0 KB (vendor-objectstack 0.0 KB). The next page-load change of any size may trip one of them. The ceiling change is objectui#12653's (in flight, another seat); nothing was raised here.

Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4


Generated by Claude Code

…dget picks a read cell that names what the value references (objectui#12613)

resolveCellRendererType promotes a textual field declaring widget
'object-ref' or 'recipient-picker' to a read cell registered under the
widget key. The object-ref cell draws the object's label from the catalog
ObjectRefField lists (one read per data source), with the picker's
"Label (name)" spelling as its tooltip. The recipient cell reads the row's
recipient_type through a new optional CellRendererProps.dependentValues and
names the recipient with the picker's own kind table, batched per directory
object with one $in query. A value nothing names draws muted with the
shared unresolved-reference mark; a call site that passes no row draws the
text it drew before. The grid passes the widget hint and the row on every
column path.

Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4
Co-authored-by: Claude <noreply@anthropic.com>
…lls on every grid path and classify them in the cell censuses (objectui#12613)

The grid case draws a neutral object declaring the same two widget hints
through column paths A-D, with a plain text control column holding the same
strings. The object-literal and Badge-fit censuses name the two new
registered types. The directory and catalog modules read the DataSource type
instead of any; README and changeset describe the new cells and the optional
dependentValues prop.

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) 3096.6 KB 3119.4 KB
Main entry chunk (gzip) 73.9 KB 350 KB
Entry file index-CVtXEZp9.js —
Status FAIL —

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.

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ✅ pass
Per-chunk ceilings ❌ over its ceiling
Per-chunk membership (declared packages) ✅ pass
Ceiling sensitivity (headroom) ✅ pass
Ceiling freshness (checkout vs. base branch) ✅ pass

📦 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) 290.06KB 74.32KB
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.41KB 73.36KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 129.90KB 33.12KB
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

…ist, through one catalog mechanism (objectui#12613)

Every packages/fields module rides the console's eager ui-components chunk,
and the batched $in reader for the record kinds put that chunk over its
per-chunk ceiling. The record kinds now read the picker's one candidate query
(moved into recipientKinds as loadRecipientCandidates and shared with the
picker), so all five lists go through one catalog-per-data-source mechanism
and the directory is half its minified size.

Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4
Co-authored-by: Claude <noreply@anthropic.com>
…pp-shell, so the eager ui-components chunk keeps only the rule and the keys (objectui#12613)

Every packages/fields module rides the console's eager ui-components chunk
whatever imports it lazily, and that chunk's per-chunk ceiling refused the
label directory. @object-ui/fields now keeps the widget promotion, the two
keys with a text default face (the RECORD_POINTER_CARD_TYPE arrangement) and
the optional dependentValues prop, and publishes the edit widgets' reads and
kind table plus UnresolvedReferenceMark. @object-ui/app-shell registers the
naming faces under the two keys and loads them, with the directory, lazily on
the first cell that draws one. The grid test now probes the grid's half of
the contract (key and row on every path); the faces are pinned in app-shell.

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) 3096.6 KB 3119.4 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-D58sVTjx.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.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) 290.79KB 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) 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.41KB 73.36KB
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

…he object face draws its icon, and fields publishes only what the face imports (objectui#12613)

The app-shell directory reads record-kind recipients by exact id, one $in
query per kind per tick, and builds the label at render with the viewer's
denied fields removed (withoutDeniedFields), so a recipient past the picker's
500-row candidate page is named. The object face reads the console metadata
store's object list for label and icon and draws the icon with LazyIcon.
@object-ui/fields stops publishing loadObjectCatalog and
loadRecipientCandidates: the widgets keep their own reads inline, and only the
kind table, recipientCandidateLabel, objectRefOptionLabel and
UnresolvedReferenceMark remain exported for the face.

Claude-Session: https://claude.ai/code/session_01Vk15bz8xHtKGUfXfCm16h4
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Live E2E (informational) is red on d47fb07, and the red is not this PR's · domain:ui seat 3 · 2026-10-16T11:42Z


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3116.0 KB 3119.4 KB
Main entry chunk (gzip) 64.8 KB 350 KB
Entry file index-BvbPb5Bs.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.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) 290.67KB 74.30KB
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.41KB 73.36KB
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

…aring-rule-labels

# Conflicts:
#	packages/plugin-grid/src/ObjectGrid.tsx
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 70 chunks) 3118.3 KB 3119.4 KB
Main entry chunk (gzip) 65.8 KB 350 KB
Entry file index-Dfn_OPJG.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.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) 290.67KB 74.30KB
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.26KB 69.57KB
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.35KB 74.86KB
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: f667f86cc04e5f7d6c05c93f5cdf9d92bd511200
Local-runs: none

Face: the review is owed by the Clause-②: yes declaration alone. reviewFace over the 19 paths, with the changeset and the PR body as the declaration texts, returns declaration (no schema hit, no governed path, no (narrowing) arm). The lane seat renders it in-seat at tier.

Inputs:

  • card objectui#12613, with claims 6210498989, 6214243680 and the correction 6214255863, and the dev reports through 6216423846 (merge round);
  • the PR body;
  • the file list and net diff against main at the head (GET /pulls/12646 with the diff accept);
  • the head's check-runs (36): 32 success, including Lint, Type Check, Repo Gates, Test (shard 1/16) … (16/16), Test (dist pins), Build & E2E and Bundle Analysis; 3 skipped (Test (coverage), its matrix row, dependabot); 1 red, Live E2E (informational), which is objectui#12649's standing red (this PR touches no e2e/** path; comment 6214725254);
  • packages/plugin-grid/src/index.tsx and package.json at the head, plus cellRendererResolution's importers on main.

The seat's earlier browser check on d47fb07 is not re-used as a gate here. The merge round changed only the ObjectGrid.tsx closures that main's objectui#12608 also changed (item 5).

① Derived judgments

  1. @object-ui/fields gains six exported names — RIGHT. Its one entry is exports["."] → dist/index.d.ts. The barrel adds:

    • UnresolvedReferenceMark: before, a module-private function. Its props are inline: raw, hint, optional className.
    • objectRefOptionLabel(name, label);
    • RECIPIENT_RECORD_KINDS and RECIPIENT_REGISTRY_KINDS: read-only records typed by RecipientMapping / RegistryRecipientMapping. These two reach the .d.ts closure as the constants' types, not as barrel names.
    • FIELD_RECIPIENT_TYPE ('field');
    • recipientCandidateLabel(labelFields, row).

    Each has a named reader in this diff: WidgetRefCellFaces.tsx imports UnresolvedReferenceMark and objectRefOptionLabel, and refLabelDirectory.ts imports the other four. Nothing is exported without a reader. No export is removed: RecipientPickerField.tsx's hunks carry no removed export line (the kind table was module-private there), and ObjectRefField.tsx only reads the new helper.

  2. CellRendererProps.dependentValues?: Record<string, unknown> — RIGHT. One optional member is added. A call site that passes nothing compiles unchanged, and the stated runtime answer is unchanged: a face that needs a sibling and gets none draws the stored text.

  3. resolveCellRendererType's object argument gains widget?: string — RIGHT. The promotion is closed in three ways:

    • the set WIDGET_CELL_RENDERER_TYPES holds exactly object-ref and recipient-picker;
    • it applies only over TEXTUAL_BASE_TYPES, the bound the format hints already keep;
    • it is keyed on the declared widget, never on an object or field name.

    A widget outside the set (filter-condition, position-ref) and a non-textual type keep their answer. The widget step runs before the format step. A field declaring both one of these widgets and a format hint is not a combination the platform writes (sys_sharing_rule's two fields declare no format), so the order decides nothing today.

  4. Two registry keys, object-ref and recipient-picker, registered to TextCellRenderer — RIGHT. This is the RECORD_POINTER_CARD_TYPE arrangement: the package owns the rule and the keys, and a host overrides the faces. A host without app-shell draws exactly the text cell it drew before.

  5. @object-ui/plugin-grid — RIGHT, and its published closure does not move.

    • GridCellFieldLike.widget? lives in cellRendererResolution.ts. That module is not re-exported from src/index.tsx; its only importer on main is ObjectGrid.tsx.
    • The diff's ObjectGrid.tsx hunks pass widget on paths A–C, and path D and the panel pass the whole field def.
    • They hand the row over as dependentValues in every type cell, the link cells and the record panel (dependentValues={record}).
    • The merge round's conflict resolution keeps main's pointerFace?.(row) ?? (objectui#12608) first in all seven closures. So a referenceVia pointer column still draws main's pointer face, and only the fallback renderer element carries the row. The net diff over those closures is exactly the dependentValues={row} attribute. The inline editor still reads declaredType.
  6. @object-ui/app-shell — RIGHT.

    • src/index.ts adds one side-effect import, so dist/index.d.ts gains no name.
    • package.json's sideEffects lists the new registration module under both dist/ and src/, so a bundler keeps the registration. check-side-effects-array is green in the dev's gates.
    • The faces load through React.lazy into WidgetRefCellFaces-*.js, outside the eager closure. That was measured by the dev, and Bundle Analysis is green on this head (budget comment 6216466834).
  7. The authored metadata accept set — unchanged. The PR reads a key the platform already declares (Field.widget, as sys_sharing_rule writes it). It adds no authoring key, and stored values do not change.

② Semver level

  • @object-ui/fields, @object-ui/plugin-grid and @object-ui/app-shell are each minor (.changeset/12613-widget-ref-read-cells.md). No major (objectui AGENTS.md §9).
  • fields widens a published surface, so minor is the floor.
  • plugin-grid's types do not move, but its cells draw differently, which is a behaviour addition, so minor.
  • app-shell registers new faces: minor.
  • The PR body's Clause-②: yes matches a diff that only widens.

③ Boundary flags

  • Eager-closure headroom (not this PR's to raise). On this head the dev measured:

    • ui-components: 288,876 / 289,000 gzip bytes;
    • the aggregate: 3118.4 / 3119.4 KB, after main's v18 dependency bump;
    • vendor-objectstack: 0.0 KB of headroom.

    This PR touches no ceiling. objectui#12653 (in flight, another seat) carries the ceiling change. Flagged for the round report, not blocking.

  • @objectstack/spec's widget description reads "Form widget override", and list cells now read the key for two hints. The description is objectstack's spec docblock. → The PR's acceptance notes; not this PR's.

  • DetailSection passes no row, so a record page's recipient_id still reads as text. Kanban and gallery cards are the same. These are incomplete reach, not a wrong answer. → The PR's acceptance notes.

Implemented-by: claude/issue-12613-sharing-rule-labels
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-16T13:42Z

Head reviewed: f667f86cc04e5f7d6c05c93f5cdf9d92bd511200. Before it: rounds 0–2, the last at d47fb07, then the merge round, which merges main f78efdd. Card objectui#12613; latest claim 6214243680 (Clause-②: yes), with the append-only correction 6214255863. Contract review of record 6216766786 (TIER_DEFAULT, declaration face, PASS, this head).
Implemented-by: claude/issue-12613-sharing-rule-labels
Reviewed-by: session_01Vk15bz8xHtKGUfXfCm16h4

1. Shape.

  • Draft PR against main. The body's first line is Fixes #12613, and the body has no other closing keyword (scanned in full).
  • 19 files, +1354/−87.
  • Changeset .changeset/12613-widget-ref-read-cells.md: @object-ui/fields, @object-ui/plugin-grid and @object-ui/app-shell, each minor; no major.
  • No content/docs/releases/.
  • Every path is inside the corrected claim's surface. @object-ui/app-shell was added on the dev's measurement. The census test and the fields README were added in claim 6214243680.
  • The PR body was refreshed by the seat for the merge round: its gates, bundle readings and headroom note now read f667f86. No commit moved.

2. Premises measured (the seat's browser check, on d47fb07).

  • Setup: objectstack examples/app-crm with a fresh database. The console was built from this PR's code and from origin/main at 1280 px. Seeded data: ten sys_sharing_rule rows, one per recipient kind, plus a missing target for each of user, team, position and object.
  • Object column:
    • the PR draws "Account", "Activity", "Contact", "Lead" and "Opportunity", each with the object's icon and the tooltip Label (name);
    • main prints crm_account and the rest.
  • Recipient column, PR vs main:
    • position → "Sales Manager" (main: sales_manager);
    • field → "Account Owner" (main: owner_id);
    • business unit and unit-and-subordinates → "EMEA Division" (main: the raw record id);
    • team → "West Sales Team" (main: the raw id);
    • user → "Dev Admin" (main: the raw id).
  • Missing targets: no_such_position, team_does_not_exist, usr_does_not_exist_0000 and the object crm_no_such_object draw their raw value, muted, with the unresolved-reference mark. None is blank.
  • Access level draws as a chip on both builds: it is a select cell, unchanged.
  • Browser console: no page errors on either build. Both log the same pre-login 404 / 401 resource errors and one AuthProvider fetch warning.
  • The merge round changed only the seven ObjectGrid.tsx closures that objectui#12608 also changed. Main's pointer face stays first, and the row rides on the fallback element. So the readings carry to this head, with both pins green on it: widgetHintedColumns-12613 and main's ObjectGrid.recordPointerCell-12608.

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

  • 36 runs: 32 success, 3 skipped (Test (coverage), its matrix row, dependabot), 1 red.
  • Among the successes: Lint, Type Check, Repo Gates, Test (shard 1/16) … (16/16), Test (dist pins), Build & E2E, Build Docs, Bundle Analysis (budget PASS, 6216466834: eager closure 3118.3 of 3119.4 KB), the changeset checks, Line Citation Gate and Governed Surface Queue Guard.
  • The red is Live E2E (informational), objectui#12649's standing red (comment 6214725254), not this diff's.
  • The dev's local subset on this head is in report 6216423846: 22 files / 575 tests, builds, type-checks, the budget script.

4. Accepted deviations.

  • The recipient cell carries no "Position · …" type chip. Every list view that shows recipient_id also shows the recipient_type column beside it, and that chip's text is the sibling select's translated option label, which a cell does not hold.
  • The access-level chip keeps the select cell's neutral badge. The platform declares no option colour, and the permission matrix's tones are private to PermissionMatrixEditor.
  • The label faces live in @object-ui/app-shell, not in @object-ui/fields. Every fields module rides the eager ui-components chunk, and its ceiling refused round 0's reader (289,748 / 289,000).
  • Prose checked sentence by sentence against the diff:
    • the changeset's "promotes a textual field declaring widget: 'object-ref' or widget: 'recipient-picker' to a cell key of that name", "A call site that passes nothing draws the stored text exactly as before", "load lazily, on the first cell that draws one", "record recipients by their exact id, one $in query per kind for the whole page" and "It is never blank";
    • the fields README's cell-resolution example.

5. Out of scope (where each went).

  • DetailSection passes no row, so a record page's recipient_id reads as text; kanban and gallery cards are the same. This is incomplete reach, not a wrong answer. → Acceptance notes.
  • The By Object view's group band prints the object api name: band labels are strings, not cells. → Acceptance notes.
  • @objectstack/spec's widget description says "Form widget override", and list cells now read the key too. → Acceptance notes.
  • The eager-closure headroom: 124 bytes on ui-components and 1.0 KB in aggregate on this head (dev merge-round report). → objectui#12653 (in flight, another seat) carries the ceiling change, and the round report names it.

6. Landing.

  • Not governed: check-governed-queue-guard.mjs --test over the 19 paths reads NOT GOVERNED.
  • 1441 lines changed, under the 3000-line threshold.
  • Clause-②: yes, with a same-head TIER_DEFAULT PASS on record.
  • Every check is green except Live E2E (informational). That red is neither this PR's nor red by design, so the queue-entry rule holds the PR until objectui#12649 lands.
  • ⇒ The PR stays draft. Card objectui#12613 goes pm:blocked on objectui#12649, with Unlock-action: re-check PR #12646.
  • On unlock, the seat re-reads the head and its checks. It has the dev merge main if the PR is conflicted, or if the bundle budget moved, then lands it through the relay (pr_ready + automerge_enable).
  • On MERGED, Fixes closes objectui#12613.

Generated by Claude Code

This branch has not been deployed

No deployments
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.

Sharing Rules list shows the recipient's and object's labels, not api names

2 participants