Skip to content

Record page, record form, drawer and preview card still show the base translation of an object renamed in a .custom override #30390

Closed

Description

@objectstack-fleet

domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG

Family closing card for the served-object-label defect (ruling 6652679548 on #30311). #30311 (PR #30388) fixes the sidebar, recent list, object list title, app header and /data title; this card carries every other site. ⛔ Not a claim. Triage sets lane and grade.

Business reason. A customer renames an installed object in its .custom override. After #30311 the list shows the new name, but opening a record, its form, its drawer or its preview card still shows the base package's translation of the old name, so the customer sees two names for one thing.

Mechanism (the #30311 card thread, os-dev-report 6654022838; the list page measured live on zh-CN, the record surfaces code-read): useObjectLabel's objectLabel(def) / objectPluralLabel(def) look the catalog key up first and use the served label only as a fallback, so the base package's string wins over a served override.

Sites (objectLabel( / objectPluralLabel( over a served definition at 23114841; not every one passes served text: { name, label: name } fallbacks and a widget ref's own label need a per-site reading):

  • ui/packages/app-shell: AppContent 4, ActivityObjectLabel 1, ConsoleLayout 1, ObjectView 3 (import wizard, delete confirmations, objectLabelOf), ObjectDataPage 1 (record drawer title), RecordDetailView 11, RecordFormPage 2, appReportIndex 2, RecordPreviewCard 1, recordDrawerStack 2, PackagedActionsSection 1, WidgetRefCellFaces 1.
  • outside app-shell: fields RecordHoverCard 1, plugin-detail 3, plugin-form 2, plugin-gantt 1, plugin-grid 1.

Two routes (the owner chooses and says why on the PR):

  1. Per site, with the app-shell private helper servedObjectPluralLabel PR fix(app-shell): draw a served object or list view label as served in the Console sidebar, recent list and object list header #30388 adds (and a singular sibling), plus the same rule in the plugin packages.
  2. Change the order inside the published useObjectLabel (ui/packages/i18n): served label first, catalog key only when none is served. One change closes the class, but it changes a published hook's answer (Clause-② reading owed).

Expected. Every Console surface that names a served object draws the served label as given; the catalog key only when no served label is at hand; en unchanged.

Dedupe: served object label catalog, objectPluralLabel served definition, record page renamed object translation → only #30311 and #30244.

Links: #30311, PR #30388, #30244, PR #30308.

Activity

  1. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:ui · 2026-11-05T10:04Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    bugSomething isn't working
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 5, 2026
  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG

    Claim: PM loop round 4 · 2026-11-05T10:37Z
    Session: session_01Utp6CZgb7dMvMK3Biysr7P (card thread, os-dev); dispatched by seat session session_01Utp6CbPN5UYMnBaNJPJWfG
    Account: os-bill
    Branch: claude/project-thread-x9e7d4 (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-30390
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: route 1 (seat ruling below): the measured sites in ui/packages/app-shell/src/** (33), ui/packages/fields, ui/packages/plugin-form, ui/packages/plugin-gantt, ui/packages/plugin-grid, plus the two same-class sites ui/packages/components/src/renderers/**/containers.tsx (record header) and ui/apps/console/src/components/FormPage.tsx (form view title), their tests, one root .changeset/ file; ⛔ ui/packages/i18n source, ui/packages/plugin-kanban (#30220, #30410), plugin-form/src/WizardForm.tsx (#30220), StudioDesignSurface.tsx (PR #30381), packages/** (stop on breach; explain in the report)
    Container & model: M-L, mode:thread, model: default tier (opus) — dispatch-gates --tier at 0e4dfbe2: no path-derived mandate, effort: high
    Clause-②: no — route 1 changes no published export; the dev corrects to yes (widening) if a helper is exported from a package index
    Metadata-protocol: none
    Responsibility: a customer renames an installed object in its .custom override; after #30311 the list shows the new name but the record page, form, drawer and preview card show the base translation | useObjectLabel looks the catalog key up before the served label | every reader of a renamed object
    Thread-read: 6655202070
    Premise: holds (measure /mnt/project-files/ui-seat3/measure-30390.md at a91409c4: 42 sites + 1 alias, 38 real)
    Serial constraints cleared: PR #30388 (served-label helper) merged efcc1a7af. Route ruling: route 1 (per site) — route 2 would flip 14 client-fallback call sites to machine names or English in zh-CN and turn ~140 test files' fixtures; route 1 is the honest per-site reading either way. plugin-detail's 3 humanize-only sites (no served definition in hand) go to the report as out of scope.

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CZgb7dMvMK3Biysr7P
    os-dev-report

    {
      "issue": 30390,
      "status": "done",
      "branch": "claude/project-thread-x9e7d4",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30475",
      "session": "session_01Utp6CZgb7dMvMK3Biysr7P",
      "premise_still_valid": true,
      "summary": "Route 1 (seat ruling on the Claim): 39 call sites draw a served object label as given and ask the client catalog only when none is served. app-shell reads the rule through hooks/servedObjectLabel.ts (servedObjectLabel added, servedObjectPluralLabel gains an optional fallback; a provider-free module, re-exported by useNavTargetLabel; not exported from the package entry, Clause-2 no); fields, plugin-form, plugin-gantt, plugin-grid, components and the Console FormPage apply it inline. Not changed: the draft-label rung, objectViewPageHeader (already wrapped), plugin-detail x3 (no definition in hand), PackagedActionsSection (bare fetch without the session language).",
      "tests": "Pins (objectstack#30390 describes): servedObjectLabel-30390 (6), RecordFormPage.listLinkPlural-11733 (+2), RecordDetailView.relatedListTitlePlural-11733 (+1), RecordPreviewCard (+2), closedAffordanceNotice.i18n-11000 (+2). Reverse leg at 54a922c2 (pre-change source restored tree-only, restored from HEAD, git diff HEAD empty): 9 renamed cases RED, controls GREEN. zh-CN fixture pass: 31 files, 5 English-in-zh-CN fixtures corrected (assertions unchanged) then 5/5 files 31/31 tests. Consumer sweep at 54a922c2, 615 files: 595 passed, 1 skipped, 19 RecordDetailView.* failed to load (new import of useNavTargetLabel pulled MetadataProvider; a test mock read an uninitialized spy) -> helpers moved to a provider-free module at 67d3e713, 28 files re-run: Test Files 28 passed (28), Tests 237 passed (237). Type-check after merging origin/main (2e899586): turbo type-check over app-shell, fields, plugin-form, plugin-gantt, plugin-grid, components, console: Tasks 80 successful, 80 total, VERDICT command-exit 0.",
      "gates": "head 2e899586; dispatch-gates --ran: 36 derived, 36 run, 0 NOT-MEASURED, 0 UNRUN; every derived family exit 0 (list in gates_ran). Plus ui check:new-line-citations: 0 new citations, exit 0. CI check-runs: in_progress at report time (PR opened as draft just before).",
      "gates_ran": [
        "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0",
        "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0",
        "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0",
        "node scripts/check-closing-keyword-parity.mjs :: exit 0",
        "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
        "node scripts/check-comment-mask-corpus.mjs :: exit 0",
        "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0",
        "node scripts/check-empty-changeset.mjs --self-test :: exit 0",
        "node scripts/check-sdui-manifest.mjs :: exit 0",
        "node scripts/check-sdui-manifest.mjs --self-test :: exit 0",
        "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0",
        "node scripts/release-pending-publish.mjs --self-test :: exit 0",
        "pnpm --dir ui exec vitest run scripts/ :: exit 0",
        "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0",
        "pnpm check:changeset-gate-self-tests :: exit 0",
        "pnpm check:closed-ceremony-text :: exit 0",
        "pnpm check:cross-package-test-inputs :: exit 0",
        "pnpm check:dispatcher-error-vocabulary :: exit 0",
        "pnpm check:driver-memory-census :: exit 0",
        "pnpm check:engine-double-contract :: exit 0",
        "pnpm check:error-status-conformance :: exit 0",
        "pnpm check:gitlink-declared :: exit 0",
        "pnpm check:nul-bytes :: exit 0",
        "pnpm check:published-files :: exit 0",
        "pnpm check:query-options-erasure :: exit 0",
        "pnpm check:refd-timer-probe :: exit 0",
        "pnpm check:registry-log-declared :: exit 0",
        "pnpm check:rest-log-spy-declared :: exit 0",
        "pnpm check:skill-identifier-liveness :: exit 0",
        "pnpm check:test-source-alias :: exit 0",
        "pnpm check:tier-file-adoption :: exit 0",
        "pnpm check:type-check-coverage :: exit 0",
        "pnpm check:type-check-debt :: exit 0",
        "pnpm check:undeclared-dep-imports :: exit 0",
        "pnpm check:watch-hint-literal :: exit 0",
        "pnpm check:where-matcher :: exit 0",
        "pnpm --dir ui check:new-line-citations :: exit 0"
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "31 files, +486/-177 (src +225/-132, tests +261/-45); measure estimated src +110/-45, tests +250: src is higher because the comments on the changed sites were rewritten and the helpers moved to their own module",
      "files_changed": [
        ".changeset/30390-served-object-label-record-surfaces.md",
        "ui/apps/console/src/components/FormPage.tsx",
        "ui/packages/app-shell/src/console/AppContent.tsx",
        "ui/packages/app-shell/src/console/__tests__/AppContent.createLandingOriginPlural-11733.test.tsx",
        "ui/packages/app-shell/src/console/__tests__/AppContent.recordSaveToastNamesRecord-26172.test.tsx",
        "ui/packages/app-shell/src/console/home/__tests__/HomeActivity.objectLabel-12238.test.tsx",
        "ui/packages/app-shell/src/hooks/__tests__/servedObjectLabel-30390.test.ts",
        "ui/packages/app-shell/src/hooks/servedObjectLabel.ts",
        "ui/packages/app-shell/src/hooks/useNavTargetLabel.ts",
        "ui/packages/app-shell/src/layout/ActivityObjectLabel.tsx",
        "ui/packages/app-shell/src/layout/ConsoleLayout.tsx",
        "ui/packages/app-shell/src/layout/__tests__/InboxPopover.activityObjectLabel-12212.test.tsx",
        "ui/packages/app-shell/src/views/ObjectDataPage.tsx",
        "ui/packages/app-shell/src/views/ObjectView.tsx",
        "ui/packages/app-shell/src/views/RecordDetailView.recordReadFailure-11902.test.tsx",
        "ui/packages/app-shell/src/views/RecordDetailView.relatedListTitlePlural-11733.test.tsx",
        "ui/packages/app-shell/src/views/RecordDetailView.tsx",
        "ui/packages/app-shell/src/views/RecordFormPage.listLinkPlural-11733.test.tsx",
        "ui/packages/app-shell/src/views/RecordFormPage.tsx",
        "ui/packages/app-shell/src/views/appReportIndex.ts",
        "ui/packages/app-shell/src/views/record-preview/RecordPreviewCard.test.tsx",
        "ui/packages/app-shell/src/views/record-preview/RecordPreviewCard.tsx",
        "ui/packages/app-shell/src/views/recordDrawerStack.tsx",
        "ui/packages/app-shell/src/views/widget-ref-cells/WidgetRefCellFaces.tsx",
        "ui/packages/components/src/renderers/layout/containers.tsx",
        "ui/packages/fields/src/RecordHoverCard.tsx",
        "ui/packages/plugin-form/src/ObjectFormContainer.tsx",
        "ui/packages/plugin-form/src/closedAffordanceNotice.i18n-11000.test.tsx",
        "ui/packages/plugin-form/src/closedAffordanceNotice.tsx",
        "ui/packages/plugin-gantt/src/ObjectGantt.tsx",
        "ui/packages/plugin-grid/src/RecordPointerCell.tsx"
      ],
      "deviations": [
        "Body order follows _common.md (维护者速读 before Fixes).",
        "Harness after-PR assign/review and PR subscription skipped per the dispatch Writes line and os-dev.md.",
        "Commit trailers are the model-free pair the repo requires, not the harness's model-named Co-Authored-By.",
        "PackagedActionsSection left unchanged although measured as served: its /meta/object read is a bare fetch without the session Accept-Language."
      ],
      "mcp_calls": "0",
      "api_writes": "3 — git push (branch, not REST); relay pr_create POST /repos/objectstack-ai/objectstack/pulls via repository_dispatch (run 42031760319); this report comment POST /repos/objectstack-ai/objectstack/issues/30390/comments via post-stamped",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: seat domain:ui#3 (ruled out of scope on the Claim) · noted, not filed · plugin-detail record-reference-rail (two objectPluralLabel calls) and record-related-list name a related object by humanize(objectName) through the catalog only; no served definition is in hand, so a renamed object keeps the base translation there · dedupe: related list humanize object label, reference rail plural label served",
        "carrier: seat domain:ui#3 · noted, not filed · PackagedActionsSection fetchObjectMetadata is a bare fetch without the session Accept-Language, so the packaged-actions table's object column keeps the catalog-first order; drawing its served label would show the browser's language · dedupe: packaged actions object label locale, meta object bare fetch accept-language"
      ]
    }
  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG

    Landed · PR #30475 · 2026-11-05T15:18Z

    Reading Value
    PR #30475 MERGED 2026-11-05T15:17Z, merge commit 8b0fbb87b; Fixes #30390, card closed by the merge. Seat ACCEPT 6658990508 on 2e899586, head-move re-check 6659932077 on the landed head 3567f3b9 (merge of main, PR diff unchanged).
    What landed 39 record-scoped sites (record page, form page, console create/edit dialog, drawer, preview card, hover card, record-pointer and object-ref cells, closed-form notice, gantt name column, page-header record chrome, AI dock chip, Activity row, report index) draw the served object label as given; the catalog lookup only when none is served, the machine name last. A .custom rename now holds on these surfaces.
    Out of scope plugin-detail related list / reference rail (name only) and the packaged-actions object column (bare fetch without session language) → #30486.

    State change: pm:dispatched removed, assignee cleared.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions