Skip to content

fix(core,react,auth,app-shell,i18n,console): the zh-CN leftovers from the 2026-09-28 cloud E2E read the session's language (objectui#10900) - #10953

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-10900-zh-cn-leftovers
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-10900-zh-cn-leftovers

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #10900
Clause-②: yes

The four surfaces the 2026-09-28 cloud E2E read in English under zh-CN now read the session's language. English is unchanged and stays the default.

⚠️ Clause-② differs from the claim. The claim (comment 5866735286) declared Clause-②: no on the premise "display strings and locale entries only; no published type". The implementation widens the public surface by four optional members, so this body declares yes: ActionRunner.setTranslator (@object-ui/core), SocialSignInButtonsProps.buttonText, LoginFormLabels.socialButton and RegisterFormLabels.socialButton (@object-ui/auth). Nothing is removed, renamed or narrowed, and no accept set changes. The changeset declares minor for those two packages (the repository's precedent for a widening) and patch for @object-ui/react, @object-ui/i18n, @object-ui/app-shell and @object-ui/console. The seat may amend either.

Strings

Surface Key en (unchanged) zh before → after
Generic action success toast actions.completedSuccessfully Action completed successfully English literal → 操作已成功完成
Login provider button auth.login.socialButton Continue with {provider} English literal → 使用 {provider} 继续
Login divider (CSS uppercases it) auth.login.orText or continue with email English literal → 或使用邮箱继续
Sign-up provider button auth.register.socialButton Sign up with {provider} English literal → 使用 {provider} 注册
Sign-up divider auth.register.orText or continue with email English literal → 或使用邮箱继续
Build Doctor button name + drawer title console.ai.buildDoctor Build Doctor English literal → 构建诊断
Build Doctor tooltip console.ai.buildDoctorTitle Build Doctor — what actually landed? English literal → 构建诊断 — 实际生效了哪些变更?
Build Doctor tooltip before the first message console.ai.buildDoctorDisabledTitle Send a message first English literal → 请先发送一条消息
Setup → marketplace breadcrumb console.breadcrumb.marketplace Marketplace humanized URL slug → 应用市场
Marketplace search placeholder marketplace.searchPlaceholder Search apps by name or manifest ID… 按名称或 manifest ID 搜索应用… → 按名称或标识搜索应用…

{provider} is the component's own single-brace hole (the {seconds} convention in auth.login), filled with the provider's display name: the component's own label for the branded providers it knows, otherwise the name the server reports. The nine new keys are in all ten packs; the eight other packs carry their own translations (see the diff).

What was measured before each choice

  1. The toast. @object-ui/core cannot reach a translator (@object-ui/i18n depends on core). A toast handler receives only the final string, so it cannot tell the runner's fallback from an author's identical text. The only two sites in this repository that install a toast handler on a runner are ActionProvider and useActionRunner in @object-ui/react, which already depends on @object-ui/i18n. Three other constructors (the provider-less useAction() fallback, useActionEngine's standalone engine, and core's one-off executeAction()) never receive a toast handler from this repository's code. So the runner takes an injected translator (the same seam recordDelete takes its t through) and those two owners install the session's t, read at call time so a language switch reaches an existing runner. It is asked only for the fallback: an author's successMessage and a server message stay verbatim. No new dependency edge. The provider-less useAction() fallback runner shows no toast unless a consumer installs a handler by hand, and then it is English.
  2. Login. @object-ui/auth takes text only through labels with English defaults. LoginForm / RegisterForm passed no text to SocialSignInButtons, and their orText label was documented as the divider but rendered nowhere. orText now feeds the divider and a new socialButton template feeds the button. All four callers pass the keys: the console's LoginPage / RegisterPage and @object-ui/app-shell's DefaultLoginPage / DefaultRegisterPage. The capitals in the E2E are the divider's uppercase class.
  3. Build Doctor. The Share button beside it already read console.ai.* through ChatPane's t; the Build Doctor button and BuildDebugDrawer's title now use the same translator.
  4. Marketplace. The breadcrumb is not under console/marketplace/** as the claim assumed. AppHeader's system branch drew the segment after System from humanizeSlug of the URL. Only the system/marketplace routes are mounted by this package, so that segment now reads the pack; host-mounted system/* pages keep their slug. The search matches the localized display name, manifest_id and the localized description. The zh placeholder names the name and 标识, the identifier each card prints under its name, which is the zh pack's existing word for identifiers. It promises nothing the filter does not match, and a pin measures both halves through the page's own filter. The en value is unchanged.
  5. Parity. all-locales-key-parity.test.ts requires every en key in all nine other packs and nothing extra, so each key is in all ten packs. check:i18n-drift reads no en value change.
  6. Serial constraints. PRs 10910, 10911 and 10914 had landed before the first edit (ancestry exit 0); the branch fast-forwarded onto them. PR 10924 landed during the work and is merged in (a merge commit). Its locale edits add commentFailed and the widgetForbidden* keys in blocks this change does not touch. Its AppHeader.tsx hunks (the imports, the admin-status block and the studioDesignPath block) are more than thirty lines from this change's system branch edit. MarketplacePackagePage.tsx is untouched here.

Tests

  • New pins, each rendering the real component or running the real runner under a real I18nProvider in zh and en:
    • ActionRunner.defaultSuccessToast-10900 (@object-ui/core);
    • ActionProvider.defaultSuccessToast-10900, for ActionProvider and useActionRunner, including a language switch on an existing runner (@object-ui/react);
    • socialButtonLabels-10900 (@object-ui/auth);
    • socialButtonsLocale-10900 (the console's login and sign-up pages);
    • authPages.socialLabels-10900 (DefaultLoginPage / DefaultRegisterPage);
    • buildDoctor.locale-10900 (button and drawer);
    • AppHeader.marketplaceBreadcrumb-10900;
    • MarketplacePage.searchPlaceholder-10900 (placeholder plus the filter it describes).
  • Red on base, green on head. With the fix committed, every non-test source file was put back to base 1dae95a41. The fix's anchors were counted at 0 on disk, then the eight suites ran: Test Files 8 failed (8), Tests 19 failed | 17 passed (36). The passing 17 are the English controls and the checks that already held. The restore from HEAD was proved by blob hashes and an empty git diff HEAD. On head: Test Files 8 passed (8).
  • Reverse type check. A label typo in DefaultLoginPage gives exactly TS2353 … 'orTextTypo' does not exist in type 'LoginFormLabels' against the rebuilt @object-ui/auth declarations, so the type-check reads the new .d.ts, not a stale one. It was restored by blob check.
  • At head f6582636f (after merging main at 5c94589f0):
    • the dependency closure of @object-ui/console was rebuilt (34 of 34 tasks);
    • type-check exits 0 for @object-ui/core, i18n, react, auth, app-shell and console;
    • vitest over packages/core/, packages/react/, packages/auth/ and packages/i18n/, plus the four touched app-shell directories (layout, console/ai, console/auth, console/marketplace) and the console's pages/auth: Test Files 479 passed (479), Tests 7063 passed | 13 skipped;
    • check:control-bytes, check:i18n-keys, check:i18n-drift, check-changeset-presence and check:new-line-citations pass.
  • At 9ab3b7207, before the merge:
    • the full packages/app-shell/ and apps/console/ suites: Test Files 978 passed | 1 skipped (979), Tests 10202 passed | 9 skipped;
    • every scripts/ suite: Test Files 177 passed | 2 skipped (179);
    • ESLint over the changed .ts/.tsx files: 0 errors, and each changed source file's warning count is equal on base and head.
  • Declared narrowing. After the merge, the full app-shell, console and scripts/ suites were not re-run locally; CI runs the full farm on f6582636f.
  • NOT MEASURED: Bundle Analysis (the eager-closure budget, including the i18n-locale-en chunk). Reason: it needs a console vite build, which CI runs.

Acceptance notes (observed, not changed here, not filed)

  • The other system/* breadcrumb segments the console host mounts (settings, apps, profile, approvals, ai-approvals, audit-log) still show their humanized English slug under zh.
  • The Build Doctor drawer's body (description, verdict lines, section titles) is still English; only its title was in scope.
  • The runner's other English fallbacks remain: its error-toast fallback for a non-string error, the parallel-chain failure text, and the Undo label on an undoable success toast. setTranslator is the seam any of them would use.
  • The eight non-zh packs translate "manifest ID" literally in the marketplace placeholder, and the English source says "manifest ID" too.
  • LoginForm keeps a hasSocialProviders state that nothing reads (an existing lint warning).

Generated by Claude Code

Body wording amended by the domain:ui seat #1 after contract review 5868740252 (its D1 to D3); no code claim moved.

… the 2026-09-28 cloud E2E read the session's language

Four surfaces a zh-CN session read in English now go through the packs,
with English unchanged as the default:

- the runner's generic success toast, through a translator the runner
  takes (ActionRunner.setTranslator) and ActionProvider / useActionRunner
  install; an author's successMessage and a server message stay verbatim;
- the social sign-in button and divider, through LoginForm / RegisterForm
  labels (a new socialButton template, and the orText label that was
  documented as the divider but rendered nowhere);
- the Build Doctor button and drawer title;
- the Setup marketplace breadcrumb segment, and the zh search placeholder
  without the manifest ID jargon.

Nine keys in all ten packs; pins for each surface under zh and en.

Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
Co-authored-by: Claude <noreply@anthropic.com>
useState's initializer overload left the nested arrow's parameters
without a contextual type (TS7006 under the package build).

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

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 7 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/3917-retire-action-condition-branch.md

  • names content/docs/core/enhanced-actions.mdx → content/docs/core/enhanced-actions.mdx — edited by this change

    • ActionCondition is removed from @object-ui/types (and from the barrel export). - ActionSchema.condition is retyped to the predicate the runtime actually honours: boolean | string | { dialect?: string; source: string } — the same three arms ActionRunner's own ActionDef.condition carries, and the same vocabulary visible and disabled use. - ActionConditionSchema is removed from @object-ui/types/zod (and from the zod barrel); the condition key now validates against that predicate union. - The two teaching sites (content/docs/core/enhanced-actions.mdx Conditional Execution, content/docs/api/schema-reference.md ActionSchema table) are rewritten to the live vocabulary: condition is a gate; a branch is expressed as separate actions with mutually exclusive conditions.

.changeset/6169-chatbot-authoring-face-type.md

  • names packages/app-shell/src/console/ai/AiChatPage.tsx → packages/app-shell/src/console/ai/AiChatPage.tsx — edited by this change

    • showTimestamp, userAvatarUrl, userAvatarFallback, assistantAvatarUrl, assistantAvatarFallback, maxHeight — display fields. - autoResponse, autoResponseText, autoResponseDelay — the local auto-response (demo/playground) fields, already live via a real consumer (packages/app-shell/src/console/ai/AiChatPage.tsx). - onSend — the send-callback, now typed on the published authoring face rather than against the plugin's internal runtime message type. Its messages element is the authoring ChatMessage widened by the three runtime-only approval states a chat runtime hands back (objectui#10018).

.changeset/6661-app-launcher-nav-menu-renderers.md

  • names en.ts → packages/i18n/src/locales/en.ts — edited by this change

    Three new strings — the launcher's and the menu's accessible names, and the menu's empty state — are declared under console.nav in en.ts and its nine sibling packs. An inline defaultValue alone is not a fix: it renders English at one call site and leaves the string untranslatable everywhere (objectui#3517).

.changeset/8318-jsdoc-default-tag-corrections.md

  • names core/src/actions/ActionRunner.ts → packages/core/src/actions/ActionRunner.ts — edited by this change

    • CRUDDialogSchema.size / .closeOnOutsideClick / .closeOnEscape / .showClose — there is no register('crud-dialog' anywhere, so no node of that type ever reaches a renderer. Recorded once on the interface. Per key, the name census differs: two spellings occur nowhere outside the declaration and its zod twin, and showClose's one other occurrence (renderers/overlay/drawer.tsx:38) belongs to DrawerSchema. - ActionSchema.level — type: 'action' is not a rendered node type, and core/src/actions/ActionRunner.ts, which is what makes method / chainMode / reload / close live, does not read level. - CardSchema.variant — card IS registered, twice, and neither registration reads it: the ui route forwards the key to ui/card.tsx, which spreads onto a div and mentions variant nowhere, and the page route forwards only its designer props. - PageNodeSchema.isDefault — page IS registered, and PageRenderer neither reads the key nor forwards it: the wrapper element gets toDomProps(props), an allow-list that does not carry it.

.changeset/action-callback-retired-7068.md

  • names content/docs/core/enhanced-actions.mdx → content/docs/core/enhanced-actions.mdx — edited by this change

    What was measured, on this branch's base (900f8d99). ActionCallback ({ type: 'toast' | 'message' | 'redirect' | 'reload' | 'custom' | 'ajax' | 'dialog', message?, url?, api?, method?, dialog?, handler? }) was declared in crud.ts, mirrored in zod/crud.zod.ts, re-exported by both barrels, and carried on the legacy ActionSchema as onSuccess? / onFailure?. Producers: the package's own phase2-schemas.test.ts fixture and three ts fences in content/docs/core/enhanced-actions.mdx — nothing else (git grep -l ActionCallback over packages content skills hit the five packages/types files; positive control SchemaNodeSchema hit 22). Runtime readers: none — ActionRunner imports UIActionSchema, never this interface, and its own ActionDef.onFailure is a different (runner-native) meaning. It was the THIRD meaning of one key: objectui#5934 had already retired the runner's callback meaning of onSuccess and converged it on the spec's block.

.changeset/action-keys-warning-text-5642.md

  • names ActionRunner.ts → packages/core/src/actions/ActionRunner.ts — edited by this change

    Both halves of the message's tail had outlived the change they described. It told the author the key was warned about rather than rejected because ActionDef "still carries [key: string]: any" — objectstack#4075 step 3 deleted that index signature, and actionKeys.pin.test.ts pins the deletion in the opposite direction ({ ActionDef: false, ActionContext: true }), while actionDef-closed-surface.test.ts pins that tsc now rejects exactly such a key at the construction site. And it prescribed promoting the key to an explicit field on ActionDef "(packages/core/src/actions/actionKeys.ts)" — that file holds the INVENTORY (ACTION_DEF_KEYS); the interface is in ActionRunner.ts. The wrong pointer had teeth: an author who followed it edited the inventory alone, which is precisely the half-change the pin test reddens on, since it re-derives the inventory from the interface's AST.

.changeset/tenant-header-edge-contract-5279.md

  • names packages/auth/README.md → packages/auth/README.md — edited by this change

    packages/auth/README.md gains "The X-Tenant-ID edge contract": what the header means (a routing hint carrying the better-auth activeOrganizationId — not an identity claim, not an authorization input, not what scopes rows), who stamps it and under exactly which condition, who reads it, and what a reader may and may not assume. The framework half is stated as a negative with its pin — resolveAuthzContext takes tenantId from the API-key principal or session.activeOrganizationId and from no header — alongside plugin-sharing's record that trusting x-tenant-id as identity was a vulnerability. The configuration half is quoted from the contract this package can actually resolve, TenantRoutingConfigSchema in @objectstack/spec/cloud, where X-Tenant-ID is the default of a configurable tenantHeaderName and header ranks second of six identification sources behind subdomain.

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.

Compared the checked-out tree with a4fb7082a (merge-base with origin/main): 34 file(s) changed outside .changeset/, read against 1688 pending declaration(s) that publish a body (2288 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3103.0 KB 3104.5 KB
Main entry chunk (gzip) 149.5 KB 350 KB
Entry file index-DalqOC1h.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.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
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.52KB 3.45KB
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) 557.59KB 133.60KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.61KB 63.16KB
fields (index.js) 261.01KB 66.28KB
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.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
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.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
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) 51.96KB 14.83KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 197.72KB 46.92KB
plugin-dashboard (index.js) 137.82KB 36.70KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.51KB 61.80KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.15KB 9.14KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.15KB 22.35KB
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.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
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) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.27KB 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: f6582636f9903c46023f052e1a9af7a90e2ac249

Isolated, adversarial Clause-② review of PR objectui#10953 (card objectui#10900). Inputs: the card and its four comments (handoff 5864728339, claim 5866735286, dev report 5868436755, amendment 5868466841), the PR body, diff, file list and the head's 43 check-runs (REST), the branch at refs/review/pr-10953 and origin/main (read-only), and a detached worktree of the head installed offline for targeted vitest probes. The dev report was read as a claim; every number below was re-measured.

① Derived judgments

Runner translator.

  • Constructors of ActionRunner on the head, non-test, whole tree: ActionProvider (installs the translator), useActionRunner (installs it), the provider-less useAction() fallback (no translator), ActionEngine's standalone branch reached by useActionEngine outside an ActionProvider (no translator; the engine installs no handlers), and the one-off executeAction() helper in core (no translator). The dev lists only the first two. The gap does not reach a user: setToastHandler( is called from exactly two non-test sites in the tree — ActionProvider and useActionRunner — so the three untranslated runners never own a toast handler and the fallback toast cannot fire through them unless a consumer installs one by hand, in which case it is English. Judged: the fallback toast translates on every path that can show it.
  • Author and server text stay verbatim: the message is dyn || action.successMessage || this.defaultSuccessToast(); the translator is asked only inside defaultSuccessToast(), for the one key actions.completedSuccessfully. The core pin asserts translate is never called when a successMessage or a data.message exists. No author text can be routed through the translator.
  • Language switch: useActionRunnerTranslator hands the runner one closure per mount that reads latest.current at CALL time; a dependency-less effect refreshes the ref after every render. The react pin follows a language switch without rebuilding the runner asserts the runner identity is unchanged across changeLanguage('zh') and the next toast is 操作已成功完成. Green at head in my worktree.
  • Stale closure / leak / loop: the closure holds a ref owned by the component, the effect writes a ref and no state, so no render loop; the only stale window is between a render and its commit, and actions run from events after commit. Side effect worth naming: through useObjectTranslation both owners now subscribe to i18next store writes (bindI18nStore: 'added'), so every ActionProvider and useActionRunner caller re-renders once per resource addition. A re-render, not a loop.
  • Provider-less useAction(): the fallback runner has no toast handler, so its fallback toast never fires; a consumer that installs one on runner gets English. The body's "has no host, so it stays English" is honest; the fuller statement is "no toast at all unless a consumer installs a handler, then English".
  • useObjectTranslation outside an I18nProvider does not throw (null context; react-i18next's not-ready t returns defaultValue), so neither owner gains a new provider requirement.
  • Dependency edges: no package.json changed. @object-ui/react already depends on @object-ui/i18n (workspace:*) and imported it from non-test source on base (index.ts, useActionTextLocalizer.ts and three more), so no new chunk edge. @object-ui/core depends on types/formula/spec only; @object-ui/i18n depends on core, so the dev's "core cannot import i18n" is true and the injected seam is the right shape. useActionRunnerTranslator is not exported from the react entry.

Auth.

  • Replacement hazard: labelTemplate.replace('{provider}', …) hands replace a replacer FUNCTION returning PROVIDER_LABEL[p.id] ?? p.name, so $&, $1, $' in a provider name are inserted literally; probed in node (Acme $& Co stays Acme $& Co) and pinned by the auth suite. Only the FIRST {provider} is replaced (string pattern); all ten packs carry exactly one hole, so nothing shipped is affected, but a pack with two holes would leave the second literal.
  • The orText behaviour change: on base both forms computed orText: labels.orText ?? 'or' and read it nowhere (l.orText has zero reads in LoginForm and RegisterForm). A host that passed orText now sees it in the divider. Stated in the changeset ("documented as the divider label but rendered nowhere; it now sets the divider under the buttons") and in the body.
  • Callers: the console's LoginPage / RegisterPage pass socialButton / orText with defaultValue; @object-ui/app-shell's LoginPage / RegisterPage pass bare keys, matching their sibling labels. Four of four consistent. i18next's interpolation is {{…}}, so the single-brace {provider} survives translation, the same convention as the existing {seconds}.
  • Default English byte-identical: base rendered {label} {name} as three text nodes with the same text content and accessible name as the head's one string; the divider default 'or continue with email' is unchanged. The four en controls (Continue with ObjectStack$, Sign up with ObjectStack$, or continue with email) pass on base in my base run.
  • Provider-name precedence (see ②): for the nine ids in PROVIDER_LABEL (google, github, microsoft, apple, facebook, twitter, discord, gitlab, linkedin) the component's own label is inserted whatever the server reports; p.name is used only for other ids, such as the card's objectstack-cloud. Pre-existing and unchanged by this diff.

Build Doctor. aria-label, both title arms and the drawer's SheetTitle read console.ai.buildDoctor* through the same t the neighbouring Share button already used (ChatPane's useObjectTranslation; the drawer takes its own). data-testid="ai-chat-debug-button" is kept. Build Doctor as a literal survives on the head only in two comments and the new pin; no test or E2E selects by the English name or title. The drawer description stays an English literal, which the body declares.

Breadcrumb. The AppHeader.tsx three-dot diff is six lines, all inside the routeType === 'system' branch: pathParts[3] === 'marketplace' reads the pack, the else if (pathParts[3]) arm keeps humanizeSlug for everything else, and console.breadcrumb.system is untouched. The console host's system/apps, profile, approvals, ai-approvals, audit-log and settings routes therefore render exactly as on base. The pin also covers the package page under the marketplace segment.

zh placeholder. The filter is ${loc.displayName} ${it.manifest_id} ${loc.description ?? ''} lowercased, substring match. 「按名称或标识搜索应用…」 promises the name and the identifier; both are matched, and the pin drives a name-only term and an identifier-only term through the real filter. The description is matched but not promised, so the placeholder understates rather than overpromises. Each card prints manifest_id in a code element under its name, and 标识 is the zh pack's existing word for slugs and identifiers (slugLabel: '标识', viewNameHelp: '机器标识…').

Locales. The nine keys are in all ten packs (per-pack grep: 10 hits each, the tenth being the pre-existing top-level marketplace block). all-locales-key-parity.test.ts: 32 passed in my worktree at head. check:i18n-drift in the worktree against 5c94589f0: 0 en value(s) changed (9 key(s) added, 0 removed). en.ts's single deleted line is a comment that repaired a cross-file line address (LoginForm.tsx:429 → in LoginForm), no value moved. Spot-checks: de (Weiter mit {provider} / Mit {provider} registrieren / Build-Diagnose), ja ({provider} で続行, the hole placed first as the grammar needs — the template design earns its keep here), ko ({provider} 계정으로 계속), ru (Продолжить через {provider}), fr, pt, es, ar all carry natural translations with the hole intact; es/fr/pt keep Marketplace for the breadcrumb, a loanword in those packs rather than a leftover. No English value left where a translation was owed.

Pins. Reproduced in a detached worktree of the head, offline install, @object-ui/* aliased to src by the root vitest config. Head: Test Files 8 passed (8), Tests 36 passed (36). Base: the 23 non-test source files checked out at 5c94589f0 (anchors counted on disk: setTranslator 0, buttonText 0, console.ai.buildDoctor 0, console.breadcrumb.marketplace 0, completedSuccessfully in en 0, manifest ID in zh 1), then the same eight suites: Test Files 8 failed (8), Tests 19 failed | 17 passed (36). Reasons are the right ones: core's four are runner.setTranslator is not a function; the rest are the zh text not found (使用 ObjectStack 继续$ ×3, 使用 ObjectStack 注册$ ×3, 应用市场 ×2, dialog 构建诊断, the zh toast ×3, the zh tooltips and placeholder). The 17 passes are real controls: the en renders, the author-successMessage verbatim case (base never translated either), the $& case (base concatenation also yields the literal) and the filter case (the filter is unchanged). Worktree restored: git diff HEAD empty, git status empty. The dev's 19/17 figures match.

CI. 43 check-runs on f6582636f: 40 success, 3 skipped (Test (coverage), Test (coverage shard), dependabot). Bundle Analysis success — eager closure 3103.0 KB of a 3104.5 KB budget, 1.5 KB headroom; the last figure posted on PR objectui#10924's thread was 3096.5 KB, so most of that movement is main's between the two runs, and this diff's own contribution (nine en keys, one 42-line hook, a private field) is a few hundred bytes. Spec Main Shape Gate success. Type Check, Lint, Test shards 1–8, Test (dist pins), Line Citation Gate, Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check all success.

Commits. Three commits on origin/main..refs/review/pr-10953. objectstack's check-commit-card-trailers.mjs run through its exported API with the worktree as cwd over 5c94589f0..HEAD: 3 commits read, 0 offending, 0 trailer findings. The trailer pair is the session URL and Co-authored-by: Claude with the declared address; the author is the same identity; no model identifier anywhere in any message or trailer.

② Semver level

  • Rule (objectstack AGENTS.md §3): Clause-②: yes takes at least minor. Precedent .changeset/10183-date-only-shared-parse-step.md pairs Clause-②: yes with minor for the widening package and patch for the rest. This changeset: @object-ui/core minor (ActionRunner.setTranslator), @object-ui/auth minor (three optional members) — right. @object-ui/react patch — it exports nothing new (verified against the entry) — right. @object-ui/i18n patch for nine pack keys — the repository's standing precedent for pack-key additions is patch (10031, 10043, 10232, 10432, 10474, 10567, 10580, both 10899 changesets, 4191, 5232, 5916 all declare '@object-ui/i18n': patch while adding keys to all ten packs) — right, and consistent with the claim's reading that locale entries are not a Clause-② widening. @object-ui/app-shell / @object-ui/console patch — right. Semver level judged correct.
  • Changeset sentences, each read against the diff: the toast paragraph is true (key, seam, owners, verbatim author/server text, English without a translator); the orText history and its corrected default are true; the Build Doctor paragraph is true; the marketplace paragraph is true, including "other system/* segments are unchanged" and the filter description; "All ten locale packs carry the nine new keys; no existing en value changes" is true; the Clause-② paragraph's four members are the complete list of new public members, and "@object-ui/react exports nothing new" is true.
  • Defect (wording, ships to the CHANGELOG): "The provider's own name is inserted as the server reports it." That holds only for provider ids outside PROVIDER_LABEL; for the nine branded ids the component has always inserted its own label (PROVIDER_LABEL[p.id] ?? p.name), whatever name the server reports. The behaviour is pre-existing and untouched here, and it is true for the card's objectstack-cloud, but the sentence as written is not true in general. Fix: "the provider's display name — the component's own label for the nine branded ids, otherwise the name the server reports". The PR body's "filled with the provider's name as the server reports it" carries the same simplification.

③ Boundary flags

  • Clause-②: yes is honest and complete: the widening is the four optional members named, all additive, plus the nine pack keys the body and changeset also name. Nothing narrows: LoginForm / RegisterForm drop orText from an internal label object that nothing read; SocialSignInButtons's label became a labelTemplate internally; no export is removed or retyped; the toast's precedence server → author → default is unchanged; the breadcrumb's other arms are unchanged; the search filter is unchanged.
  • The dev's five out-of-scope findings, each checked: (1) the other system/* segments still render humanizeSlug under zh — true (six console-host routes); the card names the marketplace breadcrumb only, so correctly out of scope. (2) The drawer body is English — true (SheetDescription literal); the card names the button, and the title is the reasonable reach. (3) The runner's other English fallbacks — true: 'Action failed' twice and 'One or more parallel actions failed' in ActionRunner.ts; the 'Undo' default lives in app-shell/src/chrome/toast-helpers.ts (undoLabel = 'Undo'), which useConsoleActionRuntime wires rather than defines — a mislocation in the report, not a false finding. setTranslator is indeed the seam for them. (4) The eight non-zh packs render "manifest ID" literally (Manifest-ID, ID de manifiesto, ID de manifeste, マニフェストID, 매니페스트 ID, ID манифеста, ID de manifesto, معرف المانيفست) and en says manifest ID — true; the card flagged zh alone, so out of scope, though the jargon objection applies to every pack and a follow-up card is the right carrier. (5) hasSocialProviders is declared and set but never read — true, pre-existing.
  • PR body: no path:line address (scanned), no model identifier, no angle bracket, Clause-②: yes at line start, Fixes #10900. Two imprecisions, neither load-bearing: "Every production runner is built by ActionProvider or useActionRunner" overlooks the useAction() fallback (which the body itself names two sentences later), useActionEngine's standalone engine and executeAction() — none of which ever receives a toast handler from this repo's code, so the toast conclusion stands; and paragraph 5 names the drift gate check:i18n-en-drift, whereas the pnpm script is check:i18n-drift (the file is check-i18n-en-drift.mjs) — the Tests section names it correctly. The provider-name sentence is covered under ②.
  • Serial: PRs objectui#10910 (4357a278b), fix(app-shell): read the single AI quota pool and draw one ring (objectui#8524) #10911 (7c9145fa3) and docs: cite landing commits where pending changesets and source comments name 23 objectui issues that answer 404, and re-qualify 19 bare objectstack numbers (objectui#10803, batch 6) #10914 (1dae95a41) are ancestors of the first commit 4304af157, whose parent is 1dae95a41 — the fast-forward the body describes. PR objectui#10924 (ac15833eb) came in through the merge commit f6582636f only. git merge-tree --write-tree 9ab3b7207 5c94589f0 reproduces f6582636f's tree byte-for-byte (013ad73ae…): a clean automatic merge with no hand resolution, nothing dropped; the three-dot diff against origin/main is the branch's own 35 files, and MarketplacePackagePage.tsx is untouched.
  • Housekeeping the dev disclosed: four gate logs left at the container root (/drift2.log, /keys2.log, /nlc2.log, /presence2.log). Outside the repository; nothing in the diff.

Defects, in one place: (D1) changeset and body: "as the server reports it" is not true for the nine branded provider ids — amend the sentence (wording; no code change owed). (D2) body: the drift gate is check:i18n-drift, not check:i18n-en-drift (wording). (D3) body: "every production runner" overstates; three other constructors exist, none toast-bearing (wording). Observation, not a defect: .replace fills only the first {provider}; every shipped pack has one. None of the three changes what an upgrading consumer receives in code, and the seat may amend the two carriers without moving the diff.

Implemented-by: claude/issue-10900-zh-cn-leftovers
Reviewed-by: session_01DuWo5bdP9SdVebamn99GGk

VERDICT: PASS


Generated by Claude Code

…n shows

For the branded provider ids it knows, SocialSignInButtons inserts its own
label, not the name the server reports; the changeset now says so.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuWo5bdP9SdVebamn99GGk
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3103.3 KB 3104.5 KB
Main entry chunk (gzip) 149.5 KB 350 KB
Entry file index-puEAI3sq.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.58KB 6.17KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
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.52KB 3.45KB
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) 558.56KB 133.87KB
core (index.js) 9.93KB 3.94KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 227.61KB 63.16KB
fields (index.js) 261.01KB 66.28KB
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.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.32KB 11.09KB
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.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
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) 51.96KB 14.83KB
plugin-charts (index.js) 84.09KB 22.93KB
plugin-chatbot (index.js) 198.08KB 46.94KB
plugin-dashboard (index.js) 137.82KB 36.70KB
plugin-designer (index.js) 215.78KB 44.42KB
plugin-detail (index.js) 233.51KB 61.80KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 161.21KB 41.41KB
plugin-gantt (index.js) 170.35KB 42.19KB
plugin-grid (index.js) 228.33KB 62.59KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 115.86KB 28.64KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.17KB 12.20KB
plugin-timeline (index.js) 31.15KB 9.14KB
plugin-tree (index.js) 11.21KB 3.89KB
plugin-view (index.js) 89.15KB 22.35KB
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.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
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) 18.27KB 6.22KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 3.83KB 1.49KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.27KB 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: 7c740d3698edbf7eccce9a45c4a8f529419d73ad

Delta review over record 5868740252 (PASS at f6582636f), same isolation and reading rules. Scope: what moved since that record — one commit, the amended PR body, and the seven pending changesets the changeset-claim-re-read comment 5868227400 lists. Every code judgment in 5868740252 carries over unchanged: the new commit touches no source file.

① Derived judgments

The commit. 7c740d369, parent f6582636f, one file: .changeset/10900-zh-cn-leftovers.md, +3/−2. The frontmatter (lines 1–7) is sha256-identical across both heads (f6b645eb…); with the replaced sentence cut from both versions the files are identical, so nothing else in the file moved. The three-dot diff against origin/main is still 35 files (1289 insertions, one more line than before — the sentence wrapped); the merge-base is still 5c94589f0; SocialSignInButtons.tsx is unchanged since f6582636f; the PR is mergeable and clean.

The sentence. "The provider's display name is inserted as-is: the component's own label for the branded providers it knows, otherwise the name the server reports." Read against labelTemplate.replace('{provider}', …) with a replacer function that returns PROVIDER_LABEL[p.id] ?? p.name: "as-is" is the replacer function (no replacement-pattern reading, no transformation of the name); "the component's own label for the branded providers it knows" is PROVIDER_LABEL[p.id], the nine branded ids; "otherwise the name the server reports" is ?? p.name. True. D1 of 5868740252 is closed.

The commit message. objectstack's check-commit-card-trailers.mjs, run through its exported API over f6582636f..head with the objectui repository as cwd: 1 commit read, both trailer fields recognised (Co-Authored-By with the declared address, and the session trailer with the session URL), 0 pair findings, 0 commit findings, 0 offending commits. The key is spelled Co-Authored-By where the branch's earlier three commits spelled Co-authored-by; the checker accepts both. A values-only scan for the model-identifier shape and the model words: 0 hits. No model name anywhere in the message or its trailers.

CI on 7c740d369. 43 check-runs: 40 success, 3 skipped (the same three as before: Test (coverage), Test (coverage shard), dependabot). Bundle Analysis, Spec Main Shape Gate, Type Check, Lint, Test shards 1–8, Test (dist pins), Line Citation Gate, Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report and Changeset Claim Re-read are all success. All green.

The PR body. A diff of the current body against the body 5868740252 reviewed shows exactly three hunks and a footer note, nothing else:

  • The {provider} sentence now reads "filled with the provider's display name: the component's own label for the branded providers it knows, otherwise the name the server reports" — true, the same measurement as above (D1).
  • The toast paragraph: "The only two sites in this repository that install a toast handler on a runner are ActionProvider and useActionRunner" — true: setToastHandler( has exactly two non-test call sites in the tree, those two. "Three other constructors (the provider-less useAction() fallback, useActionEngine's standalone engine, and core's one-off executeAction()) never receive a toast handler from this repository's code" — true, the same three 5868740252 enumerated. "shows no toast unless a consumer installs a handler by hand, and then it is English" — true (D3).
  • Paragraph 5 now names check:i18n-drift, which is the pnpm script (D2).
  • The footer note records the amendment and says "no code claim moved" — true; the diff carries no other change in wording or meaning. The body still carries no path:line address, no model identifier and no angle bracket; Clause-②: yes and Fixes #10900 stand at line start. Its test figures are stated "at head f6582636f", which stays accurate: the only later commit is changeset-only, and CI re-ran the whole farm on 7c740d369.

The seven pending changesets (5868227400), each body read in full from the head tree and checked against the file this PR touches:

  1. 3917-retire-action-condition-branch.md names content/docs/core/enhanced-actions.mdx: the "Conditional Execution" teaching site is rewritten to the gate vocabulary, a branch as separate actions with mutually exclusive conditions. Head: ## Conditional Execution and ### Branching: one action per branch with "mutually exclusive conditions" intact; this PR's only mdx hunk sits inside ## Post-success behaviour. Not made false.
  2. 6169-chatbot-authoring-face-type.md names AiChatPage.tsx as the "real consumer" of autoResponse / autoResponseText / autoResponseDelay. Head still sets all three (autoResponse: !chatApi, the text, the delay); this PR's two AiChatPage lines are the button's aria-label and title. Not made false.
  3. 6661-app-launcher-nav-menu-renderers.md names en.ts: "three new strings … declared under console.nav in en.ts and its nine sibling packs". Head console.nav carries launcherLabel, menuLabel and menuEmpty; this PR adds keys only (drift: 0 removed) and in other blocks. Not made false.
  4. 8318-jsdoc-default-tag-corrections.md names ActionRunner.ts: it "makes method / chainMode / reload / close live" and "does not read level". Head: zero level reads, the four keys still read; this PR's five hunks are the toast constant, a private field, setTranslator, defaultSuccessToast() and one line of handlePostExecution. Not made false.
  5. action-callback-retired-7068.md names the mdx: the three onSuccess / onFailure fences author successMessage / errorMessage instead, and the "Callbacks" section is a "Post-success behaviour" note pointing at the spec block, with no fence. Head: ## Post-success behaviour exists, the note points at the spec's onSuccess block, and the region holds zero fence lines; this PR extends the "A notice" bullet with prose and inline code only, and does not touch the fences. Its "measured on this branch's base" paragraph is a dated historical reading, not re-asserted against today's tree. Not made false.
  6. action-keys-warning-text-5642.md names ActionRunner.ts: "the interface is in ActionRunner.ts", and the warning text's prescription. Head: export interface ActionDef stands well above the first hunk; setTranslator is a class method and translate a private class field, not ActionDef members, so the ACTION_DEF_KEYS inventory the pin re-derives is untouched (the Test shards are green). Not made false.
  7. tenant-header-edge-contract-5279.md names packages/auth/README.md: it "gains 'The X-Tenant-ID edge contract'" with its sub-sections and "The unstamped-first-request gap". Head: ## The X-Tenant-ID edge contract with ### What it means, ### Who stamps it, ### Who reads it, ### What a reader may assume and ### The unstamped-first-request gap; this PR's single README hunk sits under ### LoginForm / RegisterForm / ForgotPasswordForm, eighty lines above. Not made false.

No pending sentence is made false by this diff, so no dated note is owed. (For the record: the objectui#10533 note form is not spelled in either repository's AGENTS.md; it was not needed.)

② Semver level

Unchanged from 5868740252: the frontmatter is byte-identical (@object-ui/core and @object-ui/auth minor; react, i18n, app-shell and console patch), and the rule and precedents cited there still apply. The one changeset sentence 5868740252 judged untrue is now true; every other sentence, re-read at the new head, is unchanged and still true.

③ Boundary flags

  • Clause-②: yes unchanged; no source file moved since f6582636f, so nothing widened or narrowed further.
  • D1, D2 and D3 from 5868740252 are closed: D1 by commit 7c740d369 (changeset) together with the body edit; D2 and D3 by the body edit. The seven pending-changeset re-reads add no defect.
  • Observation carried over, not a defect: .replace fills only the first {provider}; every shipped pack has exactly one.
  • No new defect.

Implemented-by: claude/issue-10900-zh-cn-leftovers
Reviewed-by: session_01DuWo5bdP9SdVebamn99GGk

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 11:38
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 328abeb Sep 28, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10900-zh-cn-leftovers branch September 28, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants