Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

studio(data): the field inspector shows the source label while canvas and grid show the translated label, with no hint that a translation overrides it #11782

Closed

Description

@objectstack-fleet

Filing gate ② — a product decision only the maintainer can make.

Who acts on it: objectui triage → the Studio / app-shell owner. ⛔ Not a claim. Found in a manual browser QA pass of Studio on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.

Maintainer quick-read

Should the field inspector tell the author when a translation overrides the label they are editing?

What prompted it

showcase showcase_account.tax_id: the canvas and grid show "Tax ID" (from the en translation bundle), the inspector's Label shows the source label "Tax ID (EIN)". Nothing on screen explains the difference.

Options

  • A — a hint under Label: "Shown as Tax ID in en (translation)" with a link to the translation.
  • B — show the effective label as the field's title and the source label as the editable value.
  • C — status quo.

Environment

objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.

Duplicate check

Dedupe words: field label translation override inspector · source label vs translated label

Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:i18nThe customer's own language, across UI, metadata and notifications
    on Oct 7, 2026
  2. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: write metadata — the author sees which label users get | 缺项 | P3

    Triage: first grade, enhancement · priority:p3 · domain:ui · area:i18n · pm:queue. Filed as ②, but routed as a UX defect: no contract or product question is open

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T16:12Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in the Studio field inspector's label input ⇒ domain:ui; rationale: a Studio or console surface in objectui. Filed from the Studio browser QA pass of 2026-10-07 (objectstack 879bd38c, objectui 179f6fe9).

    • Why not the decision box: the inspector shows the source label while the canvas and grid show the translated one. Saying so is a display fix inside Studio, with no schema or contract shape to rule. Why p3: nothing is wrong at run time.
    • Direction:
      • under the label input, show the effective translated label for the active locale with a pointer to the translation bundle, when a translation overrides it
      • ⛔ No change to how translations resolve
    • Clause-②: no. Patch changeset in objectui.
  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_01CGZy1BGCjdN5cXqL9cnvB8
    Account: os-support-ai
    Branch: claude/issue-11782-label-translation-hint
    Worktree: objectui-issue-11782
    Domain: domain:ui
    Seat: domain:ui#3
    File surface (on 59ce048), under packages/app-shell/src/views/metadata-admin/:

    • inspectors/ObjectFieldInspector.tsx: the Basic section's Label input only (field-label-input, about :902–:927), a hint line under it;
    • at most one new module-private helper beside it that reads the effective label for the active locale;
    • new designer.field.* rows of i18n.ts (en and zh) for the hint;
    • the tests beside them;
    • .changeset/11782-*.md.

    ⛔ Not on it: studio-design/StudioDesignSurface.tsx (seat 2's objectui#11781 holds the Data pillar's field-inspector mount at about :4500–:4530); how translations resolve (@object-ui/i18n, packages/i18n/**); the Translations editor itself. If the inspector cannot reach the effective label without a change to its mount or to a published package, the dev reports it before opening the PR (stop on breach; explain in the report).
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
    Clause-②: no
    Responsibility: objectui app-shell: Studio's field inspector edits the source label and never says that a translation overrides it, so the canvas and grid read "Tax ID" while the input reads "Tax ID (EIN)" | the platform path: the console already resolves a field's translated label (@object-ui/i18n's useObjectLabel), so the inspector can show that effective label beside the source it edits | every author editing a field label in Studio for an app that ships a translation bundle, starting with the showcase's showcase_account.tax_id
    Thread-read: 6041923394
    Serial constraints cleared: seat 1's objectui#11783 (ObjectFieldInspector.tsx) merged as 57dbe34. No in-flight claim in the lane names ObjectFieldInspector.tsx, and no open objectui PR touches it (read 2026-10-08T01:30Z). Seat 2's objectui#11781 holds StudioDesignSurface.tsx's field-inspector mount, which is off this surface. No other area:i18n card is in flight.

    Why Clause-②: no: a hint inside @object-ui/app-shell, with rows in the designer's own string table, which is not a published language pack. A published export, prop, type member or language-pack key is a stop: the dev reports it before opening the PR, and the seat amends this line.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
    "issue": 11782,
    "status": "done",
    "branch": "claude/issue-11782-label-translation-hint",
    "pr": "#11859",
    "session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode, the parent's id)",
    "premise_still_valid": true,
    "summary": "Studio's field inspector now shows a muted line under the Label input, for example 'Shown as “Tax ID” in en: the app’s translation bundle overrides this label.', when a translation overrides the label being edited. The line appears whenever the translated label differs from the input's current value. The input still edits and commits the source label, and translation resolution is untouched. The effective label is read through the same resolver the Data pillar's grid (ObjectGrid resolveFieldLabel) and form canvas (ObjectFormDesigner fieldLabelOf) use, which is useSafeFieldLabel().fieldLabel from @object-ui/i18n, with an empty fallback so an empty answer means no translation. The language named is the resolver's i18next language. Zone 2 hypothesis 3 is falsified: the designer's locale prop collapses every non-zh language to en-US, so the two are not the same value. There is no link: Studio has no Translations pillar, and the translation editor's base path and item name are not reachable from the inspector without a new prop on the mount in StudioDesignSurface.tsx (off surface). The PR body says why.",
    "tests": "Final head bc2bf4c, after merging origin/main 5aa7f55; all heavy runs went through os-verify-lock. (1) pnpm --filter '@object-ui/app-shell^...' run build: exit 0 (at 2ec68bc). After the merge, pnpm --filter @object-ui/data-objectstack run build: exit 0 (REBUILD_OK). (2) pnpm --filter @object-ui/app-shell type-check, which echoes 'tsc --noEmit && tsc -p tsconfig.test.json': exit 0 (TYPECHECK_OK). tsc -p tsconfig.test.json --listFilesOnly lists the new test file, with ObjectFieldInspector.test.tsx as the control. (3) pnpm exec vitest run --maxWorkers=2 over 211 files: 'Test Files 211 passed (211)', 'Tests 2707 passed | 1 skipped (2708)', VERDICT command-exit 0. The 211 files are the whole metadata-admin/inspectors/ directory, every app-shell test importing the metadata-admin string table, the DataPillar/Studio tests that mount the field inspector, apps/console's preview-samples-designer-options test, and the test files the merge brought in. The pre-merge run of the same 205-file set at 2ec68bc: 205 passed, 2634 tests passed, 1 skipped. (4) New pin file ObjectFieldInspector.labelTranslation-11782.test.tsx: 7 passed. Ablation through ../objectstack scripts/ablation-replace.mjs (wrap mode): the anchor was the hint guard 'if (!translated || translated === sourceLabel) return null;', replaced by 'return null; // ABLATION-11782'. The anchor went from 1 hit to 0 and the replacement from 0 to 1. The blob went from 432eb3a6763b to bc44e7122d62, and an on-disk grep found the marker once. The run was red: 'Tests 4 failed | 3 passed (7)' (the four hint pins red, the three controls green). The restore was proven: blob after restore 432eb3a6763b == blob at HEAD, git diff HEAD empty, git status clean. There was no dist leg, because the test imports the inspector from src through a relative path. Real browser: the preview gallery (apps/console vite :5297, ?only=object), Chromium /opt/pw-browsers/chromium at 1440x900, with an app bundle installed by addResourceBundle on the provider's own i18next instance. Before: no hint. After: 'Shown as “Order Total” in en: …'. With the input set to the translation: no hint. With the input changed again: the hint came back. On an untranslated field: no hint. With &locale=zh-CN: '在 en 中显示为“Order Total”:…'. No page errors. The showcase Studio reading is NOT MEASURED (see deviations).",
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "3 REST writes through the fleet-write relay: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls, request fw-20261008T022514Z-7c41e2, run 37717776709; read-back said 9599 bytes sent and stored, identical. (2) label-write --assign os-support-ai, POST /repos//issues/11859/assignees, request fw-20261008T022605Z-912665, run 37717848611; read-back said MATCHES. (3) This os-dev-report comment, POST /repos//issues/11782/comments. git push ran 3 times (the empty-branch probe, 2ec68bc, bc2bf4c) and is not a REST write. No label writes: the labels tests and 'package: app-shell' on the PR are labeler.yml's.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none · noted in the PR's Acceptance notes, not filed: the inspector's header title and Remove button still name the source label (def.label). This PR only touches the Label input, which is the claim's surface.",
    "carrier: none · noted, not filed: InspectorTextField has no description slot, so the hint is not tied to the input through aria-describedby. Fixing it means editing inspectors/_shared.tsx, which is off the surface (accessibility polish).",
    "carrier: none · noted, not filed: in the preview gallery (dev harness), react-i18next's module-level getI18n() instance is not the instance the tree renders with. A bundle added there never reached the hint; one added to the I18nextProvider's i18n prop did. Unverified guess: StrictMode runs the provider's useMemo twice and the gallery's inline config makes each run call createI18n. Zero pull: dev harness only."
    ],
    "gates": [
    {
    "command": "pnpm --filter '@object-ui/app-shell^...' run build",
    "exit": 0,
    "verdict": "os-verify-lock VERDICT command-exit 0 (at 2ec68bc)"
    },
    {
    "command": "pnpm --filter @object-ui/data-objectstack run build",
    "exit": 0,
    "verdict": "REBUILD_OK (at bc2bf4c)"
    },
    {
    "command": "pnpm --filter @object-ui/app-shell type-check",
    "exit": 0,
    "verdict": "TYPECHECK_OK; os-verify-lock VERDICT command-exit 0 (at bc2bf4c)"
    },
    {
    "command": "pnpm exec vitest run --maxWorkers=2 [211 files]",
    "exit": 0,
    "verdict": "Test Files 211 passed (211); Tests 2707 passed | 1 skipped (2708) (at bc2bf4c)"
    },
    {
    "command": "pnpm exec vitest run packages/app-shell/",
    "exit": null,
    "verdict": "NOT MEASURED: I stopped my own run after 10m33s under the lock with no result read, because another seat was queued; this is a declared narrowing and the full package run is CI's"
    },
    {
    "command": "pnpm exec eslint [3 touched files]",
    "exit": 0,
    "verdict": "0 errors, 11 warnings, all existing no-explicit-any; the diff adds no any"
    },
    {
    "command": "pnpm check:control-bytes",
    "exit": 0,
    "verdict": "check-control-bytes: OK"
    },
    {
    "command": "pnpm check:test-path-roots",
    "exit": 0,
    "verdict": "check-test-path-roots: OK"
    },
    {
    "command": "pnpm check:changeset-claims",
    "exit": 0,
    "verdict": "No pending changeset names a file this change touches."
    },
    {
    "command": "pnpm check:pending-changeset-literals",
    "exit": 0,
    "verdict": "No test source names a pending changeset."
    },
    {
    "command": "pnpm check:i18n-keys",
    "exit": 0,
    "verdict": "Every in-scope call-site key resolves against the en pack"
    },
    {
    "command": "pnpm check:i18n-drift",
    "exit": 0,
    "verdict": "No designer-table en value changed in this range."
    },
    {
    "command": "pnpm check:i18n-dead-keys",
    "exit": 0,
    "verdict": "report-only; designer.field.labelTranslated not among the candidates"
    },
    {
    "command": "pnpm check:i18n-designer-parity",
    "exit": 0,
    "verdict": "Every en row has a zh row, and every shared row carries the same placeholders."
    },
    {
    "command": "pnpm check:new-line-citations",
    "exit": 0,
    "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)"
    },
    {
    "command": "node scripts/check-changeset-presence.mjs",
    "exit": 0,
    "verdict": "3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)"
    },
    {
    "command": "CI on bc2bf4c (one read, no wait)",
    "exit": null,
    "verdict": "in_progress: 42 check runs, 21 success, 3 skipped, 18 in progress, 0 failed"
    }
    ],
    "deviations": [
    "Declared narrowing: the full app-shell package (1085 test files) was not measured locally. The 211-file set above is what ran, and CI runs the full package.",
    "The real-browser reading is the console preview gallery with a bundle installed in the live page. It is not Studio against the showcase backend: the ../objectstack checkout has no install or build, and building the showcase backend on the shared box was out of proportion for a p3 hint. The showcase showcase_account.tax_id reading is NOT MEASURED.",
    "pnpm install in the new worktree was started with & and finished (EXIT=0 in its log) before anything used the tree.",
    "The merge commit of origin/main was amended once, before its first push, to carry the model-free trailer pair. No pushed history was rewritten.",
    "An env | grep for the fleet transport variables also matched the fleet App credential variable and echoed its value into this session's tool output. It was not written to any file, to GitHub or to this report. The seat should judge whether rotation is warranted."
    ],
    "files_changed": [
    "packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx",
    "packages/app-shell/src/views/metadata-admin/i18n.ts",
    "packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.labelTranslation-11782.test.tsx",
    ".changeset/11782-label-translation-hint.md"
    ],
    "line_budget": "not applicable (no skills/** surface)"
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T02:42Z. PR objectui#11859, head bc2bf4c.

    • PR shape: draft against main, with 5aa7f55 merged in (no rebase). main has since moved (82500a7, 9b530d8), and git merge-tree of it and this head is clean; the queue tests that merge. First line Fixes #11782, no other closing keyword. Clause-②: no at line start. The three commits carry only the model-free trailer pair. Assigned to os-support-ai.

    • Scope: 4 files, +222/−0, on the claim's surface (6050311093):

      • ObjectFieldInspector.tsx: one LabelTranslationHint mounted right under the Label input; the input and its commit path are untouched;
      • one designer.field.labelTranslated row in i18n.ts, en and zh;
      • one new pin file and the changeset (patch on @object-ui/app-shell).

      StudioDesignSurface.tsx and packages/i18n/** are untouched. Nothing is added to the package entry. No governed path.

    • Diff read (the seat's own):

      • The hint reads the effective label through useSafeFieldLabel().fieldLabel(object, field, ''), the same resolver ObjectFormDesigner (the form canvas) uses. With '' as the fallback, an empty answer means no translation exists. The seat read resolve in packages/i18n/src/useObjectLabel.ts: it returns the fallback when no app namespace has the key.
      • It renders only when that label is non-empty and differs from the input's current def.label.
      • The language named is the i18next instance's language, not the designer's locale prop. The dev measured that the prop collapses every non-zh language to en-US, which falsifies the brief's Zone 2 Add public roadmap, VitePress documentation site, and GitHub Pages deployment #3. The changeset says this.
      • With no i18n provider (tests, previews), the safe resolver returns the fallback, so the hint renders nothing and never reads the language.
    • Ruling honoured (triage 6041923394): "under the label input, show the effective translated label for the active locale with a pointer to the translation bundle, when a translation overrides it" and "⛔ No change to how translations resolve". There is no link because Studio has no Translations pillar and the editor's address is not reachable from the inspector without a prop on the mount, which is off the surface. The hint names the bundle in words, and the PR body says why (Zone 2 Implement component reordering via drag-and-drop in designer canvas #5's fallback).

    • Changeset sentences checked against the head:

      • "A muted line under the Label input now reads … Shown as “Tax ID” in en: the app’s translation bundle overrides this label.";
      • "the language named is the one that resolver reads";
      • "The line shows only when the translated label differs from the input's current value";
      • "The input still edits and saves the source label exactly as before, and how translations resolve is unchanged".
    • Reverse verification (dev report):

      • Ablation through ablation-replace.mjs: the hint guard replaced by return null gives the four hint pins red and the three controls green. Restored with the blob equal to HEAD.
      • 211 test files at bc2bf4c (the whole inspectors/ directory, every importer of the designer string table, the Data pillar and Studio mounts of the inspector): 2707 tests passed. The full package run is CI's (declared narrowing).
      • Real browser: the console preview gallery with a bundle installed. The hint appears for a translated field, disappears when the input equals the translation, and is absent on an untranslated field; zh-CN reads the zh row. The showcase Studio reading is NOT MEASURED, as the PR body says.
    • Gates: CI on bc2bf4c (head_sha equals the PR head): 43 runs, 40 success, 3 skipped (Test (coverage), its shard template, dependabot), 0 failure. Lint and Type Check are success.

    • Contract review: not required (Clause-②: no).

    Findings:

    • The inspector's header title and its Remove button still name the source label. That is outside the claim's Label-input surface, and its reach is not measured → Acceptance notes
    • InspectorTextField has no description slot, so the hint is not tied to the input by aria-describedby. Fixing it means editing the shared inspectors/_shared.tsx, and the reach is not measured → Acceptance notes
    • In the preview gallery, react-i18next's module-level instance is not the one the tree renders with. This affects a dev harness only, with zero pull → dropped — dev harness only, no user door

    Landing: ready + auto-merge through the queue, now.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T03:01Z. PR objectui#11859 merged through the queue as b0aa892 at 2026-10-08T03:00Z.

    • The merge:
      • One parent, 456238c, an ancestor of origin/main.
      • The landed tree equals git merge-tree of that parent and the accepted head bc2bf4c (tree 8b671eb5 on both).
      • 4 files, +222/−0.
    • Content check, 456238c → b0aa892:
      • LabelTranslationHint in ObjectFieldInspector.tsx: 0 → 2. Its test id field-label-translation-hint: 0 → 1.
      • The designer.field.labelTranslated row in metadata-admin/i18n.ts: 0 → 2 (en, zh).
      • Control: packages/i18n/src/useObjectLabel.ts is byte-identical on both sides, so how translations resolve is unchanged.
    • Closures: the PR's only closing keyword was Fixes #11782, and this merge closed only objectui#11782 (03:00Z). The other issues closed since 02:17Z are other seats' merges. pm:dispatched is removed.
    • Follow-ups: none filed. The header title and the Remove button still name the source label, and the hint is not tied to the input by aria-describedby. Both are in the PR's Acceptance notes, with no reach measured.

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions