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 工作台把内部 ID(app.b2r4 / customer_dashboard)与整块英文(属性面板、AI 工具卡)摆给中文客户;工具卡头部状态与卡体徽章不一致 #7254

Closed

Description

@hotlong

现象

2026-09-02 最新主干 rig,中文界面用户点「开始搭建」后进入 Studio 工作台(/_console/studio/<pkg>/... 内嵌 AI 副驾),客户视角 rubric 过不了两条(内部术语、非人话):

  1. 顶栏应用切换器显示内部 ID app.b2r4 而不是应用名「客户管理」;面包屑 dashboard · customer_dashboard、左栏项 object · b2r4_customer 也是内部名(左栏标题却写着「客户管理 · 导航」,同一屏两套口径)。
  2. 仪表盘属性面板整块英文:Layout / Grid sizing and refresh cadence. / Columns / Gap / Refresh Interval / Grid columns (default 12) / Grid gap (Tailwind units) / Auto-refresh (seconds) / Header / Show Title / Show dashboard title in header / Show Description / Actions / Header action buttons / Dashboard header config (title, subtitle, actions) / Filters / Default and global filters applied across widgets. —— 其中还有面向开发者的措辞(Tailwind units)。
  3. AI 副驾工具卡:Propose blueprint / Apply edit / Create metadata / Awaiting Approval / Confirm this change before it is applied. / List metadata / Describe object / Verify build / 1 object · 1 view · 1 dashboard 混在中文对话里;且卡片体已显示「已搭建」「已生效」徽章时,头部状态仍是 "Awaiting Approval"(状态不一致,与 cloud#787 记录的反向形态同一根源)。

objectui#2458 第 4 条(2026-07-13)已记过聊天卡英文集中的问题,至今未收口;本卡把工作台面(1、2)与状态一致性(3 后半)一并立案。

修复要求

  1. 工作台顶栏/面包屑/左栏用元数据 label(应用名、对象/仪表盘显示名),内部名只在开发者视图或 tooltip 里出现。
  2. 属性面板与工具卡走 i18n 字典(@object-ui/i18n),中文覆盖到本次列出的全部字符串;跑一次 i18n 覆盖率报告贴在 PR 里。
  3. 工具卡状态单源:一旦工具结果为 applied/published,头部状态随之更新。

Activity

  1. self-assigned this
    on Sep 2, 2026
  2. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    Claim: PM loop round 1 (epic objectstack-ai/cloud#1841)
    Session: session_c5c0ce54-bb9c-478c-9e5b-cf44b80d4569
    Branch: claude/issue-7254-studio-jargon-and-i18n
    Worktree: objectui-issue-7254
    Domain: domain:ui
    File surface: packages/app-shell/src/console/studio/** (header/breadcrumb/property panel labels), packages/i18n/** (zh dictionaries), AI tool-card status under packages/app-shell/src/console/** (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (PM judgement)
    Clause-②: no
    Serial constraints cleared: only dependabot bumps touch app-shell/i18n package.json; sibling #7255 (studio nav refresh) is SERIAL after this card; #7253 owns marketplace + quota handling — do not edit those files

  3. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    Claim: dev
    Session: session_c5c0ce54-bb9c-478c-9e5b-cf44b80d4569
    Branch: claude/issue-7254-studio-jargon-and-i18n
    Worktree: objectui-issue-7254
    Base: 67dadd602a3a891666ea1513c5de677140784b6a
    File surface: packages/app-shell/src/console/studio/**, packages/i18n/** (zh + en dictionaries), AI tool-card status components under packages/app-shell/src/console/**
    Not touching: marketplace / quota files (#7253), metadata-events subscription hook (#7257), studio nav refresh (#7255)

    Generated by Claude Code

  4. added 3 commits that reference this issue on Sep 2, 2026
    4df57fb
    c3c2a90
    2d332f8
  5. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    os-dev-report

    {
      "issue": 7254,
      "status": "done",
      "branch": "claude/issue-7254-studio-jargon-and-i18n",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7366",
      "premise_still_valid": true,
      "summary": "All three parts of the card landed. (1) Workbench: the Interfaces breadcrumb and canvas caption now read metadata label + translated kind with the internal `type · name` pair moved to a labelled tooltip; the nav rail's kind chip is translated and an unlabelled leaf falls back to its object name instead of rendering an empty row; `parsePackages` reads the package name from BOTH positions `GET /api/v1/packages` serves it in, which is why the top bar showed `app.b2r4` (the reader already matched both positions for `id` and only for `id`; the server's own list handler reads `item.manifest?.id || item.id` on both halves, so this closes an asymmetry rather than adding a dialect). (2) Property panel: a new `metadata-form-i18n.ts` supplies a bundle to the platform's OWN `resolveMetadataFormLabels` from `@objectstack/spec/system` — the same function the framework's `/meta/types` handler calls — so section slugging, dot-path field addressing and the `header` composite's sub-field synthesis all come from the producer. (3) Tool cards: titles resolve through `chatbot.tool.TOOL_NAME` (all 30 platform tools x 10 packs), the header status badge is localized through an additive `statusLabels` seam on the vendored element, the plan count strip is a real plural family, and `resolveProposalCardState` is now the ONE producer both the header badge and the body badge read — a confirmed/built/published proposal no longer keeps a header saying 'Awaiting Approval'. PM mechanism assumptions checked against main and both were WRONG in detail: `packages/app-shell/src/console/studio/**` does not exist (the surface is `views/studio-design/**`), the top bar is a PACKAGE switcher that already preferred `manifest.name` (the producer DOES write it — cloud `ensureAppPackage` sets `name = app.label ?? app.name` — so the defect was the consumer's one-position read, not a missing label), and the breadcrumb already rendered `current.label` with the internal pair as an ADDITIONAL chip beside it rather than instead of it. objectui#2458 read; no overlap — it is the chat card, this is the workbench plus the status single-source.",
      "tests": "Run at 2d332f868 (final commit, after rebase onto ab9294039), exit codes redirected before capture. `pnpm exec vitest run packages/plugin-chatbot/ packages/i18n/ packages/app-shell/src/views/studio-design/` -> 'Test Files 136 passed (136) / Tests 1592 passed (1592)'. `pnpm exec vitest run packages/app-shell/src/views/metadata-admin/ packages/app-shell/src/preview/ packages/app-shell/src/console/ai/` -> 'Test Files 254 passed (254) / Tests 2533 passed | 1 skipped (2534)'. type-check exit 0 for i18n, plugin-chatbot and app-shell (each runs `tsc --noEmit && tsc -p tsconfig.test.json`, so the new test files ARE covered, not excluded). build exit 0 for the same three ('Done'). Gate verdict lines, quoted from the gates: check-i18n-call-site-keys 'Every in-scope call-site key resolves against the en pack (2952 keys) ...'; check-i18n-en-drift 'No en value changed in this range.' (46 keys added, 0 changed); check-control-bytes 'OK (scanned 6048 tracked text file(s))'; check-changeset-presence '24 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)'; check-changeset-no-major 'No changeset declares a major bump.' ABLATION (run from the committed state so the restore leg had a real reference): reverted the header-state fix on disk with `perl -0pi`, confirmed the mutation LANDED by grep counts (injected 1 / removed 0) AND a changed `git hash-object` (deac5cb3 -> 100e3152) before running anything; `toolCardHeaderState-7254.test.tsx` then went 3 failed / 4 passed — exactly the three pins asserting the header follows the body, while the unanswered-proposal pin and the four unit cases stayed green (correct: `resolveProposalCardState` still existed). Restored with `git checkout HEAD -- path`, proved by an empty `git diff HEAD`. No dist involved: the pins import `../ChatbotEnhanced` by relative source specifier. DECLARED NARROWINGS, both reported rather than skipped: (a) the whole-package app-shell vitest run exceeds the container's 10-minute foreground cap (exit 143), so the two directories this diff touches were run in full plus `preview/` and `console/ai/`, the other consumers of the changed components, found by grepping the tests for the strings this PR moves; (b) repo-wide `pnpm lint` is CI's run — eslint was run on exactly the 24 changed .ts/.tsx paths with the three required pieces of evidence: population from eslint's own config resolution, file count from its `--format json` output (24 files, 1 error, 36 warnings), and this repo enables no type-aware linting so the diff cannot move a verdict on an untouched file. Exactly ONE message lands on a line this PR wrote (`react-refresh/only-export-components` on the new `resolveProposalCardState` export — a warning, the sixth of that same family already firing in that file). The single ERROR (`react-hooks/static-components` in StudioDesignSurface.tsx) is pre-existing: linting origin/main's own copy of that file reports the identical error. NOT MEASURED / known-red elsewhere: `console/__tests__/anonSeedScope-5746.enumeration.test.tsx` fails 7/7 — and fails identically with this PR's source changes reverted to the merge base, so it is pre-existing and unrelated.",
      "mcp_calls": "0 — the whole run went through git plus repo-scoped REST (`gh api`); the write-path probe (empty-branch push) and the dedupe searches both succeeded on that channel, so no MCP GitHub call was needed",
      "open_questions": [
        {
          "question": "The ruling said the property panel's strings go through the `@object-ui/i18n` dictionary. They went through the `engine.*` carve-out beside them (`views/metadata-admin/i18n.ts`, en+zh) instead. Declaring the deviation rather than taking it silently — the tool-card half IS in `@object-ui/i18n` as directed, and the user-visible outcome the ruling demanded (full zh coverage of the listed strings) is met either way.",
          "options": [
            "A — keep it in the `engine.*` carve-out (what landed): every other string on that same panel already comes from there (`engine.inspector.dashboard.*`, `engine.studio.*`), so one panel is served by one dictionary; the carve-out is documented on both ends with a deliberately narrow reopening condition; and `@object-ui/i18n` enforces full parity across ten packs, so the alternative meant inventing technical form copy in eight more languages with no pull.",
            "B — move it to `@object-ui/i18n` as the ruling reads literally: costs ~30 keys x 10 packs of unrequested translation and splits one panel across two dictionaries, but is one dictionary for the whole product.",
            "C — drop the objectui-side table entirely and consume the platform's shipped `metadataForms` bundle over the wire (the framework ALREADY localizes `/meta/types` entries' nested `form` via `resolveMetadataFormLabels`, and objectstack already ships zh/ja/es for `dashboard`)."
          ],
          "recommendation": "A now, C as the destination — and C is why A is not a compromise. Long-term soundness (the axis that leads): these strings are the SPEC's, so the durable answer is that the producer's own bundle reaches this surface, which is exactly what the landed shape prepares — it feeds the platform's own resolver and its own key convention, so C is later a source swap at one call site, not a rewrite. B buys nothing C does not, and pays for it in a second dictionary on one panel. Real business need: the pull is measured (a Chinese customer's rig, this card), and it is for zh — B's eight extra languages have zero measured pull. AI-authorability: A and C both keep the key scheme the platform already validates, so an author-visible label has ONE spelling; B mints a second scheme for the same strings, which is where drift lives. Startup scope: A is the smallest thing that closes the measured gap. C was not done here because the server-localized `form` is not threaded to the inspector today and the reachability of the environment's bundle in a cloud tenant could not be verified without a live rig — an unverified claim is not a fix. Filed as the open question rather than decided unilaterally, since it is a ruling the PM owns."
        }
      ],
      "out_of_scope_findings": [
        "filed as objectstack#14586: spec(ui) dashboard `gap` help text says \"Tailwind units\" to an app author — the string is rendered verbatim in the customer-facing property panel; the zh overlay says something actionable and deliberately leaves the producer's English alone",
        "filed as objectstack#14587: platform-objects zh-CN metadata-forms `dashboard.sections.layout.description` is stale against its source (says 「栅格与响应式」 for \"Grid sizing and refresh cadence.\"), the merge-only-fills-gaps failure mode the generated file's own header names; includes the sibling leaf and the class-level question about the source-hash machinery",
        "filed as objectui#7368: PackageSwitcher swallows the package-list fetch failure (`.catch(() => {})`), so any 503/network/auth failure leaves the raw package id in the Studio top bar forever with no signal — and makes \"no declared name\" indistinguishable from \"the list never loaded\""
      ]
    }

    Generated by Claude Code

  6. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    ACCEPT — reviewer of record: PM (epic objectstack-ai/cloud#1841), verified against GitHub.

    • PR fix(studio,chatbot,i18n): workbench labels over internal ids, localized property panel, one tool-card status #7366: draft → main, Fixes #7254, 24 files: views/studio-design/** + views/metadata-admin/** (the real workbench surface — my claim named a directory that does not exist; the dev corrected it), packages/i18n (46 keys added across the 10 packs, en drift 0), plugin-chatbot tool card (title/status/plural + resolveProposalCardState as the single producer for header and body badges), changeset. All inside the intent of the claimed surface; no overlap with fix(app-shell,plugin-chatbot): repair the three breaks at the AI paywall moment #7273 (merged) after rebase.
    • Mechanism corrections accepted as read: the top-bar defect was the consumer's one-position read of manifest.name (producer already writes it), not a missing label.
    • Ablation on the header-state fix proven on disk (hash-object + grep counts), 3 red / 4 green as predicted, byte-identical restore. Focused suites 136 files / 1592 + 254 files / 2533 green; type-check covers the new tests (tsconfig.test.json); gates quoted (i18n call-site keys, en-drift, control-bytes, changeset). Narrowings declared with evidence (10-min cap on the whole-package run; eslint population from its own config, 24 files).
    • Ruling on the open question (PM discretion — dictionary placement, not a product/contract fork): A now, C as the destination. The property-panel strings stay in the engine.* carve-out beside the rest of that panel; the destination — consume the platform-localized form/bundle and delete the objectui table — is recorded as objectui#7369 (finding), with the two unverified premises the dev named.
    • Out-of-scope findings objectstack#14586 / #14587 / objectui#7368 filed unassigned — backlog.
    • CI at head 2d332f8: 20 success / 3 skipped / 7 in progress at review time. Flipping ready now; enqueuing only when every check is green.

    Generated by Claude Code

  7. added a commit that references this issue on Sep 9, 2026
    f157423
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions