Skip to content

fix(plugin-dashboard,app-shell): a served dashboard and a served list view are drawn as served, not re-translated by the packaged bundle (objectui#11295) - #11303

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11295-served-title-not-retranslated
Oct 1, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-11295-served-title-not-retranslated

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11295

Clause-②: yes

A served document is translated once, by the server. When the console draws a dashboard or a list view that came from the /meta read, it now draws the served title and description as given. That read already resolved them for the request's locale, with a published edit kept over the packaged catalog. The client bundle stays the one translation pass for documents the server did not translate: inline blocks, previews, design surfaces, views embedded in an object document, and client-derived tabs. ⛔ No client copy of the server's override rule, and ⛔ no string comparison.

What changed

  • @object-ui/plugin-dashboard
    • DashboardRenderer gains a localized prop. With it, these texts skip the bundle lookup: the widget title, description and sub-caption (options.description), and the renderer's own header label and description. An inline per-locale map is still collapsed.
    • useWidgetSubCaption(dashName, localized) takes the same flag.
    • Header-action labels keep their lookup, because the server's translateDashboard does not translate them.
  • @object-ui/app-shell
    • DashboardView sets localized, and draws the served dashboard label and description in its page header as given.
    • New hooks/useServedViewItems.ts answers one question: did the /meta/view read serve a document under this view's identity?
    • ObjectView draws such a view's label as given, through one helper (viewTabLabel). That covers the desktop tab bar, the mobile switcher and the record page's way-back label. Every other view still goes through viewLabel.
    • AppHeader's breadcrumb matches the URL's view with resolveViewId, the matcher the object page opens it with, and names a served view and a served dashboard as given.
  • README (packages/plugin-dashboard) and content/docs/plugins/plugin-dashboard.mdx document the prop. There is one patch changeset per released package.

The signal (dispatch Zone 2, item 2)

Nothing existed to read. The served document carries no marker: translateMetaDocument / translateMetaList return the translated document only. There is also no per-document context: MetadataProvider is a type cache, and a provider-wide context would wrongly cover inline and preview documents rendered under it. So the signal has two carriers.

  • Dashboard: one prop, localized, set where the served document is handed to the renderer (DashboardView, whose document is useMetadata().dashboards). @object-ui/plugin-dashboard cannot see where its document came from.
  • Views: membership by identity in the /meta/view read's own cache (useServedViewItems + isServedView). A per-view answer is needed, because one tab list mixes three sources:
    • served view documents: view items, overlays and saved views, all from /meta/view;
    • views embedded in the OBJECT document, from /meta/object;
    • client-derived entries: a stack container's expansion and the "all records" fallback.

Premises, measured

  • The server serves these documents translated (Zone 2, item 4).
  • One exception, which shaped the signal: the server's translateObject does not translate an object's embedded listViews. That object-document channel is not the view document the card names. The platform's own objects use it, for example sys_account's mine view, with _views keys in en.objects.generated.ts.
    • Reading at objectstack origin/main: translateObject has no listViews read, and nothing on the server turns an object's listViews into view items.
    • Measurement: the published @objectstack/spec 17.5.0 translateMetadataDocument under zh-CN translated an object's label (Account became 账户) and a view item's label (In Progress became 进行中). It left the object's embedded listViews.mine.label as My Links.
    • So those tabs keep the bundle, which is their only translation. A blanket "every view is served" signal would have regressed them.
  • The view path (Zone 2, item 3).
    • Tab: ObjectView handed view.label to viewLabel as the fallback, and the packaged _views.KEY.label won (the zh-CN reading).
    • Breadcrumb: two causes. First, it looked the URL segment up as a key, so a bare /view/in_progress missed the qualified showcase_task.in_progress and drew the humanized slug, In Progress, whatever was served (the en reading). Second, the bundle (the zh-CN reading).
    • Nothing landed in packages/i18n/src/useObjectLabel.ts and nothing in packages/layout.
  • Description and sub-caption (Zone 2, item 5). Both had the same defect, and both are fixed. widgetSubCaption.ts's header claimed a served document "never reaches limb 2". That was false, because limb 2 ran on every widget with an id. It is now true, through localized.

Tests (at 5c84eb4b5b unless noted)

  • New pins, through the real components, in en and zh-CN:
    • DashboardRenderer.servedLocalized-11295.test.tsx (6)
    • DashboardView.servedLocalized-11295.test.tsx (4)
    • ObjectView.servedViewLabel-11295.test.tsx (6, real ViewTabBar)
    • AppHeader.servedLabels-11295.test.tsx (10)
  • What the pins cover:
    • a served published edit draws as served;
    • an unedited served document shows the server's translation;
    • an inline dashboard keeps the bundle (control);
    • an object-embedded view keeps the bundle (control);
    • a dashboard the read did not serve keeps the bundle (control).
  • Red first: the dashboard pin at e3782d26ec (no fix) gave 2 failed / 4 passed. The 2 red cells are the published-edit cells; the unedited and inline cells stay green.
  • Reverse verification, after commit: the 5 implementation files were checked out from base e3782d26ec. The on-disk proof: localized / servedViews occurrence counts were 0 in all five. The 4 pin files then gave 12 failed / 14 passed of 26, the predicted split: 2 + 2 + 6 + 2 red, every unedited and control cell green. The files were restored with git checkout HEAD --. git diff HEAD was empty, and all 5 blob hashes equal HEAD.
  • Cross-package type, reverse: in DashboardView, localized was swapped for an unknown prop. tsc --noEmit in app-shell then failed with TS2322 against DashboardRendererProps, so the app-shell type-check holds the rebuilt prop type. Restored, blob equals HEAD.
  • pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build: exit 0. The rebuilt dist/DashboardRenderer.d.ts and dist/widgetSubCaption.d.ts carry localized.
  • pnpm --filter @object-ui/plugin-dashboard type-check and pnpm --filter @object-ui/app-shell type-check: exit 0. Both chain tsconfig.test.json, so the new tests are compiled.
  • pnpm exec vitest run packages/plugin-dashboard/: 156 files, 1426 passed, 6 skipped, at 27fa9a0f1b. The later commit touches only packages/app-shell/src/views/ObjectView.tsx, which no plugin-dashboard test can import.
  • The app-shell union: 118 files, 1564 passed, exit 0. It covered:
    • ObjectView*, DashboardView* and layout/;
    • every suite a git grep for tWidgetTitle, widgetTitle(, viewLabel( or useWidgetSubCaption finds;
    • every suite that reads a touched file by path, in apps/console, examples/schema-catalog, collaboration, data-objectstack, plugin-grid, plugin-view, sdui-parser, types, i18n and scripts/__tests__.
  • Repo checks, exit 0 at 5c84eb4b5b:
    • check-changeset-presence: 2 released packages, 2 changesets;
    • changeset:check;
    • check:new-line-citations: 0 new;
    • check:control-bytes, check:doc-fences, check-doc-links;
    • check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots;
    • check:unreferenced-sources, check:changeset-claims, check:pending-changeset-literals, check:phantom-deps, check:self-import.
  • Lint, narrowed and proven:
    • Population: eslint.config.js scopes its rules to **/*.{ts,tsx}, so all 10 changed TS files are in it.
    • Counts: eslint --format json over them gave 10 files, 0 errors.
    • Warnings: per file and per rule, the counts equal the base versions of the same files, read with the same config.
    • Invariance: the config has 0 parserOptions / projectService, so no type-aware rule exists and untouched files cannot move.
  • NOT MEASURED:
    • check:doc-snippets: PREREQUISITE NOT MET. It needs 34 built packages, and this run built the app-shell closure. The docs edits are prose, with no code fence added. CI runs it.
    • check:readme-exports: the same reason. No README fence or export changed.
    • The whole-repo pnpm lint: owned by CI.

Acceptance notes

Recorded here; nothing filed from this run.

  • Object document listViews are not translated by the server.
    • translateObject (objectstack packages/spec/src/system/i18n-resolver.ts) never reads them. os i18n extract writes _views keys for them.
    • So a non-console client gets the authored text for those tabs, and the console's bundle is their only translation. This PR keeps that bundle on purpose.
    • Seam: spec:translateObject (objects[].listViews.*.label) → runtime: /meta/object → renderer: ObjectView tab. The HTTP door is not measured.
  • Nav entries with an absent label inherit their target's label through useObjectLabel (useNavTargetLabel, UnifiedSidebar, nav-menu-renderer). That is the same second pass over a served view or dashboard label. Not measured, and not touched here: the nav label path is objectui#11201's area.
  • Object labels: objectLabel(objectDef) re-resolves a served object label through the bundle. The server keeps an explicit object label edit since objectstack#8284. This is the same class, not measured, and not in this card's scope.
  • Page and report breadcrumbs pass through the bundle the same way. Today the server has no override rule for those types (PACKAGED_BASE_ACCESSORS is object, dashboard and view), so nothing differs visibly yet.

Same-day churn

main moved 4 commits past base (d79f525d9e). None of them touches a file here, useObjectLabel.ts or MetadataProvider.tsx, so the branch was not merged.

Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ (domain:ui seat 1, dispatched os-dev run).


Generated by Claude Code

claude added 4 commits October 1, 2026 00:25
…, description and sub-caption as given (objectui#11295)

DashboardRenderer gains a `localized` prop: the host says the document was
read from the server's `/meta` route, already translated for the request's
locale with a published edit kept over the packaged catalog. The widget
title, description and sub-caption, and the renderer's own header label and
description, then skip the client bundle lookup; an inline per-locale map is
still collapsed. Without the prop the bundle composition is unchanged.

Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Co-authored-by: Claude <noreply@anthropic.com>
…s served (objectui#11295)

DashboardView draws the served dashboard's label and description as given
and passes `localized` to DashboardRenderer. The view switcher tabs (desktop
and mobile), the record page's way-back label and the breadcrumb draw a
view's label as given when the `/meta/view` read served that view
(`useServedViewItems`, by identity); a view embedded in the object document
or derived client-side keeps the bundle, its only translation. The
breadcrumb matches the URL's view through `resolveViewId`, so a bare
`/view/<key>` finds the qualified served view instead of the slug.

Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Co-authored-by: Claude <noreply@anthropic.com>
…translated once (objectui#11295)

Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Co-authored-by: Claude <noreply@anthropic.com>
… and label, not the view object (objectui#11295)

The two way-back sites list those three members as their hook dependencies;
passing the whole object made `react-hooks/exhaustive-deps` ask for it. The
warning count on ObjectView.tsx is back to the base's.

Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation plugin tests package: app-shell labels Oct 1, 2026
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 3 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/7070-no-invented-gantt-date-fields.md

  • names app-shell/src/views/ObjectView.tsx → packages/app-shell/src/views/ObjectView.tsx — edited by this change

    • app-shell/src/views/ObjectView.tsx — the console object page. The inline branch becomes ganttViewOptions, the sibling of calendarViewOptions and timelineViewOptions: the declared block spread whole, title floored at 'name', no date field invented. - plugin-list/src/ListView.tsx — the render branch AND the capability gate. - plugin-view/src/ObjectView.tsx — generateViewSchema, the authored object-view element route, which bypasses ListView entirely.

.changeset/8114-detail-tab-activity-timeline.md

  • names plugin-dashboard/README.md → packages/plugin-dashboard/README.md — edited by this change

    README.md ships in this package's files, so the example went out in every tarball. DetailTabs renders a tab's content through ANGLE-BRACKETS(SchemaRenderer schema={toRenderableSchema(tab.content)} /), which makes content.type an SDUI node position judged by the component registry — so a reader copying the tab got the registry's Unknown component type panel (OBJUI-001) where the timeline should be. Same shape as the line-chart widget in plugin-dashboard/README.md (objectui#7896's census; fixed by objectui#7951) and the fourth known instance.

.changeset/8760-unfulfilled-chart-stubs.md

  • names content/docs/plugins/plugin-dashboard.mdx → content/docs/plugins/plugin-dashboard.mdx — edited by this change

    • At render. SchemaRenderer's lazy branch re-checks hasLazy(type) on every pass and returns the Loading ANGLE-BRACKETS(type)… placeholder. Registry.register() deletes a lazy entry only for keys the loaded module actually registers, so for an unfulfilled key the entry SURVIVES the load and every later pass takes the same branch. Measured on b775500af through the real chain: { "type": "line-chart" } painted role="status" / data-lazy-loading="line-chart" / Loading line-chart…, permanently. Not the OBJUI-001 panel the card expected — no alert, no error, no console warning. A skeleton that never resolves reads to a user as a slow network. - At authoring. A stub is enough to put a key into getKnownTypes(), so check:doc-types and the CLI's generated KNOWN_SCHEMA_TYPES snapshot both blessed all three. content/docs/plugins/plugin-dashboard.mdx taught "type": "line-chart" inside a card body, and every gate was green on it.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with 1ccb5ba7d (merge-base with origin/main): 12 file(s) changed outside .changeset/, read against 1870 pending declaration(s) that publish a body (2482 pending in total). · run

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3585.1 KB 3607.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-nTXAYxd-.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) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
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.17KB 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.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
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.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 570.17KB 136.43KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 229.96KB 63.80KB
fields (index.js) 261.11KB 66.26KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
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.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.35KB 9.18KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 41.23KB 11.53KB
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) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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.01KB 3.93KB
plugin-calendar (index.js) 52.90KB 15.35KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.36KB 37.31KB
plugin-designer (index.js) 216.45KB 44.60KB
plugin-detail (index.js) 244.79KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.75KB 44.64KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 231.61KB 63.61KB
plugin-kanban (index.js) 49.32KB 15.48KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
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) 119.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
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.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 0.20KB 0.18KB
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) 4.74KB 2.26KB
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 (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-components.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) 21.59KB 7.71KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 5c84eb4b5b51bd3dd966ff7ae37cde1fe51cb847
Local-runs: none

Inputs: card objectui#11295 (body, claim 5921983728, dev report 5922666442), PR #11303 (body, 14-file list, net diff e3782d26ec..5c84eb4b5b: +1218 / −36), the head's check-runs, objectui#11201 ruling B (5921167691), and objectstack origin/main 8d329f02ee for packages/spec/src/system/i18n-resolver.ts and packages/rest/src/meta-item-read-gate.ts (both byte-identical to the dev's reading at 5f6b63a6fd).

① Derived judgments

  • A1 — the dashboard signal is a host prop, localized?: boolean on the published DashboardRenderer: right. Nothing on the served document can carry the answer: objectstack's translateDashboard returns the translated document only (label, description, widgets, globalFilters rebuilt; no marker). MetadataProvider is a type cache, and a provider-wide context would also cover the metadata-admin DashboardPreview and any inline block rendered under it. The prop is destructured out of the ...props spread, so it never reaches the DOM. No string is compared with anything; the server's override rule is not copied. The docblock names the promise (the document arrived translated by /meta), the setter (DashboardView), the covered texts, the unset case (inline, preview, design surface) and the header-action exception. Clear.
  • A2 — which texts skip the bundle: right, measured against translateDashboard. The server translates the dashboard label / description, per widget title / description and the sub-caption written into options.description; it does not touch header.actions. The diff skips the bundle for exactly that set (tWidgetTitle, tWidgetDescription, useWidgetSubCaption(dashName, localized), the renderer's header h2 / p) and leaves tActionLabel alone. An inline per-locale map is still collapsed: resolveLabel(...) and pickLocalized(...) run before the localized early return at every site.
  • A3 — the one setter is DashboardView: right. Its previewSchema is the /meta read's document (useMetadata().dashboards, preferLocal) with widgets pruned by registered objects; the file's own comment records it was never a host-supplied preview channel. The other two hosts at the head, metadata-admin/previews/DashboardPreview.tsx and DashboardWithConfig.tsx, are design surfaces and correctly leave the prop unset. Observation, not a gap: DashboardGridLayout (dashboard-grid) still calls useWidgetSubCaption(schema.name) with no carrier; only inline SDUI blocks reach it today, so it belongs on the family list in ③, not in this card.
  • A4 — the view signal, useServedViewItems + isServedView, a per-view answer by identity: right, and the membership test is sound for every producer in the repo. The hook reads useMetadata().getItemsByType('view') from @object-ui/react, the same context app-shell's MetadataProvider re-exports, so the test and the real console answer from one cache; outside a provider the read is the no-provider stand-in and every view keeps the bundle. A served view item lands in objectDef.listViews under the key applyViewItem stamps as its name (the registry's qualified OBJECT.KEY), and buildViewTabs makes that key the tab id, so item.name === view.id is the identity match. A per-view answer is required because one tab list merges three sources with different translation points (served items; the object document's own listViews; client-derived tabs). Name collisions: the test is name-only, not object-scoped; served names are registry-qualified while embedded keys are bare, so the only collision is an embedded key spelled as another item's full qualified name or as an aggregated container's bare object name — no producer in the repo does that. A later tightening (require viewKind && object on the matched item) is cheap and is noted, not required. Qualified vs bare: the tab list's ids are the merged keys, and the breadcrumb now resolves the URL segment with resolveViewId in both directions (A7), so the crumb and the tab ask the same identity.
  • A5 — "the server does not translate an object's embedded listViews": correct at objectstack origin/main 8d329f02ee. translateObject resolves label / pluralLabel / description, walks fields and inline actions, and spreads everything else through untouched — listViews is never read. translateView has no container or listViews walk, and PACKAGED_BASE_ACCESSORS is object, dashboard, view. The dev's further reading that nothing in the engine turns an object's listViews into view items is outside this review's named reads and is not re-read; the signal is sound in either world, because anything the engine did serve would be served under a qualified id and drawn as given.
  • A6 — scope beyond the card's named sites: inside the card's direction and the claim's surface. The dashboard's own label / description (page header, renderer header, the AppHeader dashboard crumb) are the served document's title and description the direction names ("the renderer draws the served title and description as given"; DashboardSchema spells the title label), drawn from the same /meta document and re-translated by the same second pass. The record page's way-back label and the mobile switcher draw the tab's string through the one helper pair (viewTabLabel / viewOriginLabel), so the open view is named one way everywhere; splitting them would have left the old second pass on two of three sites. All of it sits in the claim's three named files plus one new hook module, which the claim allowed ("may need a prop or context the dev measures"). No file in packages/layout, nothing in packages/i18n/src/useObjectLabel.ts.
  • A7 — the breadcrumb matching the URL's view through resolveViewId: right and necessary. At base the crumb indexed listViews[viewName] directly, so a bare /view/in_progress missed the qualified key and drew the humanized slug whatever was served (the measured en reading); the pin could not hold without it. The matcher is the one in @object-ui/core the object page opens views with; no second copy. Its result is a strict superset of the direct lookup (exact, bare-to-qualified, qualified-to-bare), so no previously matched view changes.
  • A8 — pins: the card's four are all present, through the real components, in en and zh-CN. (i) served widget title carrying a published edit drawn as served: DashboardRenderer.servedLocalized-11295 and DashboardView.servedLocalized-11295, both locales; (ii) an unedited widget still shows the packaged translation the server put in: present in all four files; (iii) the inline, non-served control keeps the bundle: the third block of the renderer pin; (iv) the view's tab and breadcrumb: ObjectView.servedViewLabel-11295 (real ViewTabBar) and AppHeader.servedLabels-11295 (bare and qualified URL, plus the dashboard crumb and a not-served-dashboard control). Cell count 6 + 4 + 6 + 10 = 26. Red-first 2 of 6 on the renderer pin is the predicted split (the two edited cells; unedited and inline green). The reverse of the five implementation files turning 12 of 26 red — 2 renderer, 2 page, 2 tab, 6 crumb (bare, qualified, dashboard, both locales) — with every unedited and control cell green is the split the cells imply; not re-run here, consistent with the test bodies. Not separately pinned: the mobile switcher and the way-back label, which draw through the same helpers as the pinned tab.
  • A9 — the card's three prohibitions hold. No second translation pass over a served value on any touched site; no copy of the server's override rule (no packagedBase comparison, no string equality anywhere in the diff); packages/layout untouched (objectui#11201, seat 2).
  • A10 — gates at the head (check-runs are the verdict). Concluded green: Lint, Type Check, Spec Main Shape Gate, Build & E2E, Build Docs, Test (dist pins), Test shards 2/8, 3/8, 5/8, 6/8, 7/8, 8/8, Doc Snippet Type Check, README Export Check (the two the dev could not run locally), Changeset Bump Policy / Declaration / Claim Re-read / Fixed Group / Overwrite Report, Doc Fence / Example Id / Component Type / Internal Docs Link checks, Line Citation Gate, Control Byte Scan, Inert vi.mock Specifier Check, Governed Surface Queue Guard, Pre-Install Import Graph Check, Live E2E (informational), the skill checks, label, Action Ref Convention, Bundle Analysis, Docs Route Eager Closure Check. Skipped by path condition: the coverage shard, Test (coverage), dependabot. Not concluded at this read: Test (shard 1/8) and Test (shard 4/8) — named as in progress, treated as neither pass nor fail; the merge waits on their conclusion, not this record.
  • A11 — docs. packages/plugin-dashboard/README.md and content/docs/plugins/plugin-dashboard.mdx document the prop in prose, no new fence; the doc gates above are green on the head.
  • Observation, non-blocking, pre-existing class: the AppHeader dashboard crumb and DashboardView's resolveKeyedI18nLabel hand a served label through without collapsing an inline locale map; the base did the same whenever the bundle missed, and DashboardSchema.label is not measured here to be map-valued.

② Semver level

  • Two changesets, one per released package, check-changeset-presence and the Changeset gates green.
  • @object-ui/app-shell: patch — right. No export changes; hooks/useServedViewItems.ts is an internal module; DashboardView, ObjectView, AppHeader change behaviour only.
  • @object-ui/plugin-dashboard: patch — holds, with minor the stricter reading. The diff adds one public optional prop, localized?: boolean, to the exported DashboardRenderer (DashboardRendererProps, carried into dist/DashboardRenderer.d.ts), and an optional second parameter to useWidgetSubCaption, which the package barrel (src/index.tsx) does not export. Under semver proper an additive public prop is a minor; the repo's written policy (AGENTS.md 版本号策略) pins only major and leaves minor/patch to the normal bump, the changeset body names the new surface and its contract, and the fixed group takes the highest bump either way. Judged acceptable as a fix changeset whose vehicle is one additive optional prop; the seat may raise it to minor before merge — not blocking.
  • Clause-②: yes — right. A published renderer's prop surface changes, which is the very case objectui#11201's ruling B separated out when it set Clause-②: no for a renderer change with "no schema, type or public prop change". The ACCEPT re-reads the export the dev named (localized in the rebuilt .d.ts).

③ Boundary flags

Every dev flag (deviations) and the out-of-scope findings, answered; open_questions is empty.

  • Scope beyond named sites (dashboard label / description on three surfaces, way-back label, mobile switcher): answered in A6 — inside the card's direction.
  • Breadcrumb matcher switched to resolveViewId: answered in A7 — required for the pin, one matcher, superset.
  • New file hooks/useServedViewItems.ts; README and mdx edited: allowed setting point; docs-driven rule met in prose; doc gates green.
  • Build flag --workspace-concurrency=2, ablation by git checkout + grep -c, cleanup: procedural; the reported shape is consistent with the cells (A8); not re-run.
  • Full plugin-dashboard suite ran at 27fa9a0f1b, not the final head: the final commit touches only packages/app-shell/src/views/ObjectView.tsx; the head's own test shards are the gate verdict — six concluded green, 1/8 and 4/8 not concluded (A10).
  • Attribution trailer form: not a contract matter.
  • Same-day churn: re-measured at this read. origin/main is 1ccb5ba7de, five commits past base e3782d26ec; none touches any of the PR's 14 files. objectui#11201's PR fix(layout): a present navigation label renders verbatim, with no translate-if-equal-to-name exception, and an inline locale-map label renders its text (objectui#11201) #11297 has since landed: packages/layout/* moved (this PR does not touch it) and packages/i18n/src/useObjectLabel.ts moved by comment-only lines (+5 / −3 inside a docblock), so viewLabel / dashboardLabel behaviour did not shift under this PR. The claim's wait condition (trace landing in useObjectLabel.ts) never triggered, and the serial constraint is now cleared anyway. No branch update is needed beyond GitHub's behind state.
  • The objectui#11201 principle: this PR applies ruling B's reading — the server is the one translation point for a served document; a present served label renders verbatim — to dashboards and list views; it adds no text-against-name matching.
  • Out-of-scope finding (1), class b — fileable, in objectstack, not here. reach: is met by the gate's named-real-producer arm (sys_account.listViews.mine, label My Links, with _views keys shipped in en.objects.generated.ts); the published @objectstack/spec 17.5.0 translator measurement supports it and the /meta/object HTTP door is not measured, which the gate does not require when a named producer exists. A5 confirms the server side at 8d329f02ee. The fix repo is objectstack (the translateObject / os i18n extract seam in the spec and cli i18n lane); this seat cannot file there, so it goes the way this card itself arrived: one request on the seat post for objectstack triage, one card for the whole channel (not one per view), asking first whether an object's embedded listViews is a translated channel at all (views are first-class records since objectstack#4959, and translateView's docblock promises every client already-localized labels). Different family from this card (a server gap, not a client second pass), so not folded into this card's closure.
  • Findings (2)–(4), carrier none, not measured — Acceptance notes, no card now. They are the same family as this card (a client bundle pass over a label the server already resolved). (2) nav entries inheriting a served target label through useObjectLabel is objectui#11201's path, landed on main as 1ccb5ba7de — one line on that card or the seat post, no new card. (3) objectLabel(objectDef) re-resolving a served object label while the server keeps an explicit edit (objectstack#8284) is the family's broadest site and the cheapest to measure (a tenant object rename under zh-CN in the console). (4) page and report crumbs: no server override rule for those types, nothing visible. Per the filing gate, the family gets one closure card with enumerated sites — (2), (3), (4) and the DashboardGridLayout carrier from A3 — opened on the first measured reach, not single-point cards.

Implemented-by: claude/issue-11295-served-title-not-retranslated
Reviewed-by: session_0122Knsowci76D2rBWReCzzZ

VERDICT: PASS

…shboardRenderer gains the public `localized` prop (objectui#11295)

Patch round 1: the contract review read the new prop (and the same flag on
`useWidgetSubCaption`) as new public API of a published package, so the
plugin-dashboard changeset moves from patch to minor. app-shell stays patch.

Claude-Session: https://claude.ai/code/session_0122Knsowci76D2rBWReCzzZ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3585.0 KB 3607.4 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-DrvsIn4N.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) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
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.17KB 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.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
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.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 570.17KB 136.43KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 229.96KB 63.80KB
fields (index.js) 261.11KB 66.26KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
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.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 40.95KB 11.48KB
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) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
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.01KB 3.93KB
plugin-calendar (index.js) 52.90KB 15.35KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 139.36KB 37.31KB
plugin-designer (index.js) 216.45KB 44.60KB
plugin-detail (index.js) 244.79KB 64.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 173.75KB 44.64KB
plugin-gantt (index.js) 173.03KB 43.07KB
plugin-grid (index.js) 231.61KB 63.61KB
plugin-kanban (index.js) 49.32KB 15.48KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 23.50KB 7.82KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 33.05KB 9.67KB
plugin-tree (index.js) 11.20KB 3.89KB
plugin-view (index.js) 90.32KB 22.76KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
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) 119.55KB 39.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
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.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.19KB 1.62KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 0.20KB 0.18KB
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) 4.74KB 2.26KB
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 (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-components.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) 21.59KB 7.71KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 2d563c1f6e257d5f20106c1f3f79db7abc2152a7
Local-runs: none

Delta record on PR #11303 at 2d563c1f6e, over the previous record 5922835154 (PASS at 5c84eb4b5b). Inputs: the delta git diff 5c84eb4b5b 2d563c1f6e (both heads by sha; one file, +1 / −1), the PR's 14-file list and 5-commit list, the PR body (unedited since the previous head), the patch-round dev report 5922859065 on card objectui#11295, and the check-runs on the new head, read twice without waiting. Every judgment of 5922835154 not re-stated below carries over unchanged: no source, test, doc, package.json or publish-contract field moved between the two heads, so nothing it measured can have moved.

① Derived judgments

  • D1 — the delta is the one line the seat ruled, and nothing else: right. git diff 5c84eb4b5b 2d563c1f6e touches .changeset/11295-dashboard-served-localized.md alone: '@object-ui/plugin-dashboard': patch becomes '@object-ui/plugin-dashboard': minor, +1 / −1. The PR's commit list is the previous four plus one, 2d563c1f6e chore(changeset): @object-ui/plugin-dashboard takes a minor bump …, on the dev's branch; the PR file list is still the 14 files 5922835154 read, both changesets counted in it; main was not merged in (no merge commit in the delta, and origin/main is still 1ccb5ba7de, the commit the previous record's churn reading measured). A1 to A9 and A11 of the previous record are therefore re-affirmed as written, not re-derived.
  • D2 — the changeset's prose is still true under minor: right. Its first line, fix(plugin-dashboard): a served dashboard draws its own title, description and sub-caption, not the packaged catalog's (objectui#11295), names the defect the change corrects and never spelled a bump level, so nothing in it went stale. The body names the vehicle — "DashboardRenderer gains a localized prop … useWidgetSubCaption takes the same flag as an optional second argument" — which is exactly the additive public surface the previous record's ② read as the stricter minor reading; and its "What does not change" paragraph makes the non-breaking contract explicit, so this minor reads as additive, not as the repo's breaking-as-minor case (AGENTS.md 版本号策略: objectui's own breaking changes also go minor, with the break described in the body; this body describes none, because there is none). It is rightly not re-spelled feat(: the repo judges a changeset by what it publishes, not by the fix/feature prefix (AGENTS.md retired the "feature 要写、bug 修复不用" criterion); no changeset gate ties the prefix to the level — the four structural gates read the front matter alone, and the claims gate reads a body against the files it names and against its own front matter's negations; and the pending set on this very head already carries 36 minor changesets whose first line is fix(…). The Changeset Claim Re-read gate is green on the head.
  • D3 — @object-ui/app-shell: patch still right. The delta does not touch app-shell, so A4's reading stands at the head: hooks/useServedViewItems.ts is not exported from packages/app-shell/src/index.ts, neither package's package.json is in the PR's file list, and DashboardView, ObjectView and AppHeader change behaviour only. Note for the reader, not a defect: the fixed group in .changeset/config.json takes the highest declared level, so the group ships minor either way; patch on app-shell is the honest per-package declaration, not the version the package will carry.
  • D4 — gates at the new head (check-runs are the verdict). 42 check-runs. Concluded green (29): Lint, Build & E2E, Build Docs, Bundle Analysis, Test (dist pins), Doc Snippet Type Check and README Export Check (the two the dev could not run locally at either head), the five changeset gates — Changeset Bump Policy, Changeset Declaration, Changeset Claim Re-read, Changeset Fixed Group Check, Changeset Overwrite Report — Doc Fence Language / Doc Example Id / Doc Component Type / Internal Docs Link checks, Line Citation Gate, Control Byte Scan, Shell Escape Residue Scan, Inert vi.mock Specifier Check, Governed Surface Queue Guard, Pre-Install Import Graph Check, Docs Route Eager Closure Check, Action Ref Convention, Skill Eval Token / Skill Guide Path / Skill Example checks, Live E2E (informational), label. Skipped by path condition (3): the coverage shard, Test (coverage), dependabot. Nothing concluded as anything but success or skipped. Not concluded at this record's second read (10): Spec Main Shape Gate, Type Check, and Test (shard 1/8) through Test (shard 8/8) — named as in progress, treated as neither pass nor fail; the merge waits on their conclusion, not this record. The changeset gates in particular, since they are the only derived family the delta can reach: Changeset Bump Policy (no major declared; minor is inside the policy), Changeset Declaration (two changesets for the two released packages the diff touches), Changeset Fixed Group Check, Changeset Overwrite Report (the edited file is one this PR itself adds, so no other change's declaration was overwritten; the script's own header lists a bump-level correction among the legitimate edits anyway) and Changeset Claim Re-read — all five concluded success on 2d563c1f6e. The dev's local changeset:check, check-changeset-presence, check:changeset-claims and check:control-bytes at the head (exit 0 each, per 5922859065) agree with them and are not re-run.

② Semver level

  • Two changesets, one per released package the diff touches; Changeset Declaration and the other four changeset gates green on the new head.
  • @object-ui/plugin-dashboard: minor — right, and now the reading the previous record named as the stricter one. The diff adds one additive optional public prop, localized?: boolean, to the exported DashboardRendererProps of DashboardRenderer (carried into dist/DashboardRenderer.d.ts per the dev's build at the previous head), and an optional second parameter to useWidgetSubCaption, which the package barrel does not export. Additive, no removal, no changed default, no behaviour change without the prop: minor under semver proper, and inside the repo's policy (no major; minor/patch independent of objectstack). The previous record's one non-blocking point is closed.
  • @object-ui/app-shell: patch — right (D3).
  • Clause-②: yes — unchanged in the PR body and still right: a published renderer's prop surface changes. The ACCEPT re-reads the export the dev named (localized in the rebuilt .d.ts), as the previous record said.

③ Boundary flags

Every dev flag (deviations) in the patch-round report 5922859065 answered; its open_questions and out_of_scope_findings are empty. The previous record's ③ carries over whole.

  • The stale PR-body sentence, "There is one patch changeset per released package." — an Acceptance note, not a blocking defect. Judged on what reads it: nothing that gates or releases. The release reads the declared changesets (AGENTS.md: the platform's release criterion reads this repo's declared changesets), and both changeset files are correct at the head; the changeset gates read .changeset/ out of the tree, no workflow under .github/workflows/ carries PR_BODY, and the body lines the PM tooling does read — the Fixes #11295 relation and Clause-②: yes — are unchanged and correct. The sentence misdescribes one declaration in prose the dev wrote once and, by the report's own convention, left for the seat. One thing raises its weight without making it blocking: the repo merges by squash with the PR body as the squash commit message, so the sentence lands in the merge commit if the body is not edited first. So: the ACCEPT corrects it in its own text, and the seat may edit the body line before merge to the dev's suggested wording — "There is one changeset per released package: minor for @object-ui/plugin-dashboard, patch for @object-ui/app-shell." — which this record reads as accurate. ⛔ Not a reason to send the PR back to the dev: the body is not the diff, and the diff is right.
  • Worktree procedure (recreated from the branch at 5c84eb4b5b after confirming the local branch, the fetched remote head and HEAD equal; no install, because the changeset checks are plain node scripts; removed afterwards without --force): procedural, consistent with the one-commit delta; not re-run.
  • CI on the new head not read by the dev ("just pushed; convergence is the seat's"): answered in D4 — read here, twice, with the ten still-running runs named.
  • Same-day churn: origin/main is unchanged at 1ccb5ba7de since the previous record's reading, so nothing on main touches any of the PR's 14 files, packages/i18n/src/useObjectLabel.ts or MetadataProvider.tsx; the delta's one file exists only on this branch and cannot be raced. No branch update is needed beyond GitHub's behind state.
  • Carry-over, unchanged: scope beyond the named sites (A6), the breadcrumb matcher (A7), the new hook file and the two docs edits, the build flag and ablation shape, the plugin-dashboard suite at 27fa9a0f1b, the attribution trailer form, the objectui#11201 principle, out-of-scope finding (1) class b for objectstack triage, and findings (2) to (4) as Acceptance notes toward one family closure card — all as 5922835154 answered them.

Implemented-by: claude/issue-11295-served-title-not-retranslated
Reviewed-by: session_0122Knsowci76D2rBWReCzzZ

VERDICT: PASS

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

Labels

documentation Improvements or additions to documentation package: app-shell plugin tests

Projects

None yet

2 participants