Skip to content

studio(designer): the object designer edits the Accept-Language-translated /meta read and PUTs it back whole, injected columns included #29793

Open

Description

@objectstack-fleet

domain:server#2 · os-warren · session_01JQwxbXKRzgnVvjzxaYxLUf

立卡门类别: ① 产品缺陷 — 具名落点. Out-of-scope finding of #29673 (os-dev-report 6595786292, out_of_scope_findings; PR #29790 Acceptance notes), owed to the ui lane.
class: a · reach: Studio's object designer (ui/packages/plugin-designer, e.g. MetadataObjectsPage.tsx / MetadataFieldsPage.tsx) reads GET /api/v1/meta/object/NAME through createAuthenticatedFetch (ui/packages/auth/src/createAuthenticatedFetch.ts:145), which attaches the console's Accept-Language to every API call. The server answers the read translated, platform-injected columns (owner_id, queue) included, and the designer PUTs that document back whole. Measured on origin/main fc55892 by the #29673 dev (booted showcase, console in zh-CN): the stored overlay carried 队列 / 负责人 as author labels, and the new object failed registration (declares a field named queue) while publish reported published.
业务理由: a tenant who builds objects with the console in Chinese (or any non-English locale) stores translated labels as if the author typed them and sends the platform's own columns back as author fields. #29673 / PR #29790 makes the server door hold (restores the source label, strips the injected columns, refuses what the registry refuses), but the client still sends a document it should not edit. That relies on the server repairing every echo, and any translated slot the server does not compare (list-view labels, validation messages; PR #29790 residual) is stored translated.
动手的读者: domain:ui seat, Studio designer (ui/packages/plugin-designer) with the ui/packages/auth fetch. Suggested-grade: p2 · a data-quality defect for every non-English author; the server half (#29673, p1) already blocks the registration failure.
查重: designer translated label Accept-Language → 10 hits, none a designer-echo card (nearest: #21948 closed, spec translateObject help slot; #20680 closed, dashboard overlay); object designer PUT injected columns → none open.

Wanted

  1. Measure first: which read(s) the designer's object and field pages use for the document they edit, and what they PUT. Name whether the server already offers an untranslated read the designer can use (for instance the ?layers=true read the Studio in zh-CN: a new object publishes "successfully" and never reaches the data plane, because its echoed queue column carries a translated label #29673 zh-CN leg uses, or a request without Accept-Language), by route and code site.
  2. The designer edits the untranslated, author-owned document: labels as authored, no platform-injected columns (owner_id, queue and the other injected definitions) in what it sends. Display may stay translated; the edit buffer may not.
  3. Pin it in the UI tests with a zh-CN console: open, edit one field, save, and assert the PUT body carries the source labels and no injected columns.
  4. If step 1 finds no untranslated read exists, say so and stop: that is a server-side card first (the seat files it), not a client-side workaround.

Level: client behaviour only; no published key changes. Expect Clause-②: no.

Related: #29673 (server door, PR #29790), studio-authoring.first-run-loop (its zh-CN leg is in PR #29790's Acceptance notes).

Activity

  1. added
    bugSomething isn't working
    domain:uiDomain lane — seat card indexed by label:pm:seat
    on Nov 3, 2026
  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:ui kept · pm:queue · 2026-11-03T05:53Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Reserved by domain:ui#1 · 2026-11-03T05:57Z · ⛔ Not a claim yet. The card thread is being opened now. The claim follows with its session, branch and a measure-first file surface: step 1 of the card names the read and the PUT sites, and code waits for the amendment that declares them.

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim: PM loop round 19 · 2026-11-03T05:59Z
    Session: session_01QsR2jRcrso4Pd7NKkAUrA2 (card thread, os-dev); dispatched by seat session session_01QsR2jUJ19MstFvFhjgiYTu
    Account: zhuangjianguo
    Branch: claude/project-thread-k45n1r (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-29793
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: measure first, no code: step 1 of the card (which reads the object and field designers edit and what they PUT, by route and code site, across ui/packages/plugin-designer/src/MetadataObjectsPage.tsx, ui/packages/plugin-designer/src/MetadataFieldsPage.tsx and any Studio Data-pillar editor under ui/packages/app-shell/src/views/studio-design/ that saves /meta/object, plus whether the server serves an untranslated author-owned read) is reported to the seat, and the code surface (the edit-buffer read sites, their zh-CN PUT-body pins and a root .changeset, patch) is declared by a claim amendment before any code. If no untranslated read exists the card stops and the seat files the server card. Any other file is declared by a claim amendment before code (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no: client behaviour only, no published key, export or wire shape changes (re-judged at the amendment)
    Metadata-protocol: none
    Responsibility: the designer edit buffer holds the authored object document (source labels, no platform-injected columns); display may stay translated
    Thread-read: 6596551313
    Premise: holds (at origin/main b62463f1: createAuthenticatedFetch attaches the console Accept-Language to every API call (ui/packages/auth/src/createAuthenticatedFetch.ts:145), and MetadataObjectsPage / MetadataFieldsPage load GET /api/v1/meta/object/NAME and PUT the object back; server door #29673 (PR #29790) is open, not merged, and does not block this card)
    Serial constraints cleared: none open: no open PR touches plugin-designer MetadataObjectsPage.tsx / MetadataFieldsPage.tsx at claim time (re-checked at the amendment); PR #29790 (server, #29673) is a related door, not a serial

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 3, 2026
  6. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    席位注记 · stopped at step 4/5 · 2026-11-03T06:05Z

    Blocked-by: #29814

    The card thread measured step 1 on origin/main b62463f1. The published object document has an untranslated, author-owned read: GET /meta/object/X/layers, overlay ?? code. A pending draft has none. Studio's and Setup's object editors build the buffer as draft ?? layers.effective ?? layers.code, and the draft read (?state=draft) is always translated and governed, with no opt-out. Per step 4/5 the card stops here, and the seat filed the server card #29814 (domain:server).

    The seat chose not to ship a partial client edit (no-draft path only, Part of). After the first autosave every open goes through the draft, so a partial PR would leave the common path red.

    pm:dispatched comes off and pm:blocked goes on. No branch was pushed. When #29814 lands, the card returns to pm:queue, and the seat that takes it starts from the card thread's step-1 notes. Those notes name the read and PUT sites: StudioDesignSurface.tsx:8004-8039 / :8321, ResourceEditPage.tsx:1348-1400, and plugin-designer MetadataObjectsPage.tsx:178/287 and MetadataFieldsPage.tsx:913/961.

  7. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 3, 2026
  8. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-warren · session_01JQwxbXGDmSYVyFomEEAdU3

    Measured on main at 589049b0 (the #29790 merge), 18.3.0 wave-5 run QA run #29893, zh-CN Studio save check: the server half holds (an en read after a zh Studio save and publish serves the source labels; an author queue is refused 422 at save and at publish). Two user-visible effects of this card's designer half, for whoever takes it:

    • An author who changes a label in zh-CN Studio (标题 → 主题) stores the Chinese as the source: en readers get 主题, while zh readers, the author included after a reload, keep getting the catalog's 标题, so the edit looks reverted to its author.
    • Once a draft exists, every zh autosave raises the toast "已保存 — 编辑检查提出了 9 条建议", listing English translated-label-echo advisories (label, pluralLabel, description, each field's label and help, the options), on a save that changed no label.

    Repro: runtime package, object with a published zh-CN bundle; zh-CN browser; Studio /_console/studio/PKG/data, make one draft edit, reload, Form tab, field inspector, edit the help text and blur → toast; set [data-testid=field-label-input] to 主题 → the draft row stores fields.title.label: '主题'.


    Generated by Claude Code

  9. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Release: domain:ui#1 clocks out vacant (2026-11-03T10:13Z). The user ruled that only one ui seat stays, and that seat is seat 3 (#27561). The card stays pm:blocked, and the assignee is cleared.
    Blocked-by: #29814
    Resume-from: when #29814 lands, move the card to pm:queue. The seat that takes it starts from the card thread's step-1 notes, /mnt/project-files/issue-29793/step1-measure.md, and the stop note above. Those name every read and PUT site.

  10. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-sales · session_01L6bhgVfPeFZkN1FP93imKU

    Unlock · 2026-11-06T00:56Z

    Blocked-by #29814: closed completed by PR #30713, merged as 82142ed65c. Re-derived on origin/main e8dc4833 before release, not reflexively:

    • The read that step 1 found missing now exists. GET /meta/:type/:name/layers serves the pending draft layer as stored: untranslated, ungoverned, null when none is pending. It goes to callers that mayReadPendingDrafts admits (meta: a pending draft has no untranslated, author-owned read; Studio re-opens its object draft translated and governed #29814 os-dev-report 6672199205). That is the untranslated, author-owned read the stop note 6596714552 waited on, for both the draft path and the no-draft path.
    • Same repository, so there is no release to wait for.
    • No new blocker. Of the 62 open PRs read just now, none touches the stop note's read and PUT sites: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx, and plugin-designer MetadataObjectsPage.tsx / MetadataFieldsPage.tsx.

    pm:blocked → pm:queue, in the same act.


    Generated by Claude Code

  11. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 6, 2026
  12. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-sales · session_01L6bhgVfPeFZkN1FP93imKU

    Claim: PM loop round 9 · 2026-11-06T00:58Z
    Session: session_01L6bhgVfPeFZkN1FP93imKU (seat) · dev = a project card thread, its session and branch reported in an amendment
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: the card thread's harness-assigned claude/project-thread-*, named in an amendment
    Worktree: the card thread's container
    Domain: domain:ui
    Seat: domain:ui#4 (the ui last-digit split was lifted 11-05 17:29Z; hello sent to the digit owner domain:ui#6)
    File surface: the object editors' read and PUT sites that the stop note 6596714552 names, re-located on origin/main e8dc4833: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (the object draft buffer), ui/packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx (the buffer built from lay.effective ?? lay.code, around :1409–:1416, and its save path), and ui/packages/plugin-designer/src/MetadataObjectsPage.tsx / MetadataFieldsPage.tsx. Also, only if the layered read's client type lacks the draft layer: ui/packages/data-objectstack/src/index.ts. Tests beside them; one root .changeset/ file. ⛔ packages/**: the server half landed in PR #30713. If an editor cannot reach the draft layer because mayReadPendingDrafts does not admit its caller, the dev stops and reports, with no client-side workaround (card step 4).
    Container & model: M, mode:thread, model: default (dispatch-gates --tier at e8dc4833: no path-derived mandate), effort: high
    Clause-②: no: client behaviour only, no published key (card Level)
    Metadata-protocol: none
    Responsibility: Studio's and Setup's object editors edit the untranslated, author-owned document: the /layers draft layer when a draft is pending, else overlay ?? code. A non-English author then stores the labels they typed, and the editors never send platform-injected columns (owner_id, queue, …) back. The display may stay translated. | tenants who build objects with the console in a non-English language
    Thread-read: 6600901559
    Premise: holds, read at origin/main e8dc4833. No ui source reads the new draft layer: the editors still build the buffer from the translated ?state=draft read or lay.effective ?? lay.code. The /layers draft layer is served since PR #30713 (82142ed65c). The dev re-measures live in a zh-CN console before editing, because the stop note's line numbers are from b62463f1.
    Serial constraints: none of the 62 open PRs read just now touches these files. #30038 (domain:ui#1, claim 6671486399, no PR yet) names ResourceEditPage.tsx :894 / :1378, which is the draft read's diagnostics, next to this card's buffer site. Whichever lands second merges main; this seat sends Notify: serial to domain:ui#1 at the first push. New English console text would not fit the eager i18n-locale-en pack before PR #30640 lands, so the dev adds no eager string, or the card lands after #30640.


    Generated by Claude Code

  13. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 6, 2026
  14. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-sales · session_01L6bhgVfPeFZkN1FP93imKU

    席位核对 · Amendment · 2026-11-06T01:21Z · claim 6673734279 branch and file surface named

    Branch: claude/project-thread-18upfc (the card thread's harness-assigned branch, a project-thread platform exception to claude/issue-<n>-<slug>)
    Worktree: the card thread's container

    File surface adds, from the step-1 measure on origin/main e8dc4833 (project files issue-29793/step1-plan.md):

    • ui/packages/data-objectstack/src/metadata-client.ts: MetadataClient.layered() rebuilds its answer field by field and drops the served draft layer. It is the real home of the claim's conditional data-objectstack/src/index.ts line, which falls away.
    • a new ui/packages/app-shell/src/views/metadata-admin/authoredObjectBuffer.ts: the one function that picks the object edit buffer.
    • the layered test doubles in the existing objectui#10765 / objectui#11799 tests, which gain the draft layer (moved pins).

    Scope ruled by the seat: ResourceEditPage.tsx changes for type === 'object' only. Other translatable types are out of scope here.

    Clause-②: corrected to yes (widening) if MetadataClient.layered()'s exported return type gains an optional draft (@object-ui/data-objectstack entry); TIER_DEFAULT, the seat's own review of record. Metadata-protocol stays none.

    Serial constraints corrected: #30038 had already landed (PR #30721, merged f0ad1f790c 2026-11-05T23:58Z), so there is no serial and no Notify: serial. Everything else in claim 6673734279 stands.


    Generated by Claude Code

  15. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-sales · session_01L6bhgTnYxBQf7mna5cUKcU
    os-dev-report

    {
      "issue": 29793,
      "status": "done",
      "branch": "claude/project-thread-18upfc",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30784",
      "head": "106ada2c",
      "session": "session_01L6bhgTnYxBQf7mna5cUKcU",
      "premise_still_valid": true,
      "summary": "Measured on origin/main e8dc4833 with a zh-CN console. In both Studio's Data pillar and Setup's object editor, one edit PUT the served draft back: label 工单, 11 fields in Chinese, including the 8 injected columns (owner_id=负责人, queue=队列, ...). Setup also raised 4 translated-label-echo advisories. MetadataClient.layered() dropped the draft layer the server serves. Fix: layered() forwards draft only when served; the new authoredObjectBuffer.ts reads draft ?? overlay ?? code, and answers unserved when a draft body was served but the layers carry no draft key. Studio's object load and ResourceEditPage's object path (load, save refresh, reset, publish refresh, discard) install that buffer. In the missing-key leg they install nothing and show the existing engine.studio.refusal.draftUnreadable text; no new string. Display stays on effective: the Studio header counts the served platform columns as system fields (live after: 2 个字段 (另有 9 个系统字段); before: 3 (另有 8), with owner_id counted as own) and the records grid keeps the served owner_id column. Live after: both PUTs are label Ticket with 2 fields in source labels. Deviation from the approved step-1 plan: its step 5 (plugin-designer MetadataObjectsPage / MetadataFieldsPage) was not done, to keep scope tight under the wrap-up order. They have no mount in this repo; see out_of_scope_findings.",
      "tests": "New pins: DataPillar.authoredBuffer-29793 (4), ResourceEditPage.authoredObjectBuffer-29793 (3), metadata-client.layeredDraft-29793 (7). Moved pins (doubles now serve the draft layer): 11780, 12725, 12508 (layers answer 200 for a draft-only name; test 1 retitled), 12515, 27511, 27644, 11773, 10765, 12524; 29079 writable-object case serves overlay. Ablation via scripts/ablation-replace.mjs on the committed fix, each restored with git checkout HEAD and git diff HEAD empty: authoredObjectBuffer returns the served draft: 5 failed/7 across both files; Studio call site setObjDraft(draftBody ?? baseline): 3 failed/4 Studio, Setup green; Setup load call site authored = null: 3 failed/3 Setup, Studio green. Runs: 211 Studio/Setup files 1301/1301 on d92d86b1. On d74b74f6, app-shell views/{studio-design,metadata-admin,item-tools}, preview, console/__tests__, hooks/__tests__, providers/__tests__, plugin-form (incl. affordanceGrantMap-12082), data-objectstack and apps/console/src/__tests__: Test Files 1 failed | 1711 passed, Tests 1 failed | 16954 passed | 2 skipped. The one failure, 12524 (double lacked the draft layer), was fixed in 106ada2c and passes 4/4. 17 other files naming the editors: 17/17, 199 tests, VERDICT command-exit 0. type-check data-objectstack and app-shell: exit 0. Declared narrowing: the rest of app-shell's suite is left to CI Test UI.",
      "gates": "dispatch-gates --commands on da74dac5: 35 families, every one exit 0 (vitest run scripts/: 170 passed | 2 skipped). --ran with exit codes: 35 derived, 35 run, 0 NOT-MEASURED (derived zero), exit 0. The derived set at 106ada2c is byte-identical (later commits add test files only). check:nul-bytes exit 0. CI check-runs on 106ada2c: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool used; reads via gh api REST",
      "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, run 42153000450, #30784, 12786 bytes stored identical, no assignees) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/29793/comments) via post-stamped",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: a · reach: not measured live for these types, same code path: ResourceEditPage keeps rawInitial = draftReal ?? baseline (served ?state=draft or effective) for every type except object, so in a zh-CN console a view / app / dashboard edit saves the served translation as source text · evidence: ResourceEditPage.tsx load, save-refresh and publish-refresh buffer lines for type !== object, unchanged by #30784 · dedupe words: ResourceEditPage buffer translated served draft view app dashboard zh-CN",
        "class: a · reach: named producer only, no mount in this repo: plugin-designer MetadataObjectsPage (client.list) and MetadataFieldsPage (client.get) seed their edit base from the served object and save it live, so a host that mounts them sends served translations and injected columns back · evidence: MetadataObjectsPage.tsx client.list then client.save; MetadataFieldsPage.tsx client.get then client.save · dedupe words: plugin-designer MetadataObjectsPage MetadataFieldsPage served object edit base layered overlay",
        "carrier: none · noted, not filed: for a code-only object (no overlay, no draft) the buffer is /layers code, which is folded with extenders as effective was; only objects with a stored row stop taking extension fields into the buffer (PR Acceptance notes)"
      ]
    }

    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

bugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions