Repository navigation
finding(app-shell): the machine-name chip is unconditional in every non-English panel — its "label already spells the name" predicate cannot hold once the label is translated #8231
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Sep 7, 2026 Triage: lands in
domain:ui(packages/app-shellmetadata-adminSchemaForm); rationale: class (a) — a reproducible defect with the mechanism read off the source and an already-observed instance.prettify('columns')isColumnsand can never equal 「列数」, solabelMatchesNameis false for every localized field and the chip renders beside every label; #8218 observed exactly that ("columns / gap / refreshInterval / header 四个 chip" at once).Bug.⭐ The reading worth preserving is the inversion, not the noise: in
en-USthe same four fields hide the chip, so the affordance is near-invisible in the locale it was designed for and unconditional in the one it was not. A predicate that compares a humanized machine name against a visible label is only ever a fair comparison while the label is English — it does not degrade under translation, it inverts.priority:p3: visual noise on a maker surface. ⛔ Nothing is mis-saved, mis-read or lost, and the chip's content is correct — it is when it renders that is wrong. That ceiling is why this is not p2 despite affecting every field in every non-English panel.pm:awaiting-maintainer, ⛔ notpm:queue, and the reason is on the card rather than in this seat's judgement: it was filed by a maintainer (hotlong) who wrote that picking among the three options is a maintainer call, and the three are genuinely different decisions — option 1 (fix the predicate against the untranslated label) needs the localization overlay to preserve the source string; option 2 (hide it in the maker surface) needs a prop threaded from the host because one component serves two audiences; option 3 (keep it unconditional, make it quieter) abandons the exception-marker semantics entirely. ⇒ 1 and 2 are not compatible — doing 1 is wasted if 2 is chosen. Dispatching a dev to guess would produce work that a later ruling discards.⛔ This seat does not pick among the three. Grading and routing only; the label puts it where the decision is, and the grade says how much it costs to leave it there (little — hence p3).
One note for whoever rules: #8218's acceptance was satisfied — it only asked that no untranslated English string reach the panel, and the tooltip fix did that.
⚠️ So this card is not a reopened #8218 and ⛔ should not be closed as one.
Generated by Claude Code
状态转换:
pm:awaiting-maintainer→pm:queue(2026-09-09)维护者回批逐字:「C 桶那 24 张的批量转
pm:queue同意」。判据:机器名 chip 在每一个非英语面板里都无条件显示 —— 它「label 已经拼出了这个名字」的前提,在 label 被翻译之后不可能成立。⇒ 前提可证伪、修法明确的缺陷,⛔ 无产品语义分叉。
bug、package: app-shell、domain:ui、i18n、priority:p3留下。⚠️ 根因见 objectstack #17017。
Generated by Claude Code
⛔ 异议:本卡被判为「修法明确、无产品语义分叉」,而源上有一条绿着的 pin 依赖当前行为
domain:ui#2执行席(sessionsession_018HrVaotisyhgmot9o2MLRq),2026-09-19T13:44Z。
⭐ 本卡本轮排到了队首(它的文件面刚随 objectui#9953 落地而释放),本席在派发前做前提复核,
⛔ 于是没有派发。全部读于origin/main树尖79ac2d632,取数时刻 2026-09-19T13:43:26Z。两句互相矛盾的话,都在这张卡上
卡面自己(立卡者,逐字):
三个答案都站得住,而且不是同一个决定 … Picking among the three above is a maintainer call.
状态转换评论
5595068043(逐字):判据:… ⇒ 前提可证伪、修法明确的缺陷,⛔ 无产品语义分叉。
⇒ 维护者当时批的原话是「C 桶那 24 张的批量转
pm:queue同意」——⭐ 那是一次按桶的批准,
⛔ 本席读不出它逐张确认了「这一张没有分叉」。而判据那句是席位的读法,不是维护者的字句。⭐⭐ 而源上的证据站在「有分叉」这一边
packages/app-shell/src/views/metadata-admin/SchemaForm.deDeveloperize-8218.test.tsx里有一条绿着的
pin,它的 fixture 用label: '列数'、字段名columns,然后:const chip = screen.getByText('columns'); expect(chip.tagName).toBe('CODE'); expect(chip).toHaveAttribute('title', '机器名');英文那一例用同一个 form(label 仍是
列数),断言screen.getByText('columns')带
title: 'Machine name'。⇒ ⭐ 两条断言都以「chip 在一个被翻译的 label 旁边渲染」为前提。 任何把谓词修好、让 chip 在翻译
label 旁不再渲染的改法,都会让getByText('columns')抛错、两条一起变红。⚠️ 而那条 pin 的注释自己点名了本卡的缺陷,逐字:The chip renders only when the visible label does NOT already spell the machine name — which, under
a localized panel, is EVERY field:prettify('columns')can never equal 「列数」. That is exactly the
shape #8218 hit.⇒ 写 pin 的人知道这是缺陷,并把它当作 fixture 的机制用了。
为什么这不是「顺手改 pin 就行」
卡面三个选项的用户可见后果不同:① 修谓词(拿未翻译 label 比)—— 需要把源串一路穿进
SchemaForm,本席查过:该文件今天收不到任何未翻译 label(metadataForms/sourceLabel/
untranslated在其中零命中);② 在 maker 面隐藏;③ 保持无条件、只是变安静。
⇒ ①②③ 分别是「少显示一些」「一类用户完全看不到」「永远显示」,⛔ 不是同一个产品答案。⭐ 本班已有两张卡走到这一步才被发现(objectui#9430 与 objectui#8263),⇒ 本席这次在派发前量,
⛔ 不再花一个 dev 去撞同一堵墙。所求(⛔ 本席不定级、不改路由、不自行选项)
- ⭐ 确认或推翻「无产品语义分叉」这句判据。若卡面那句「maintainer call」仍然成立
⇒ 本卡应进决策箱,而不是取卡队列。 - 若确认它可以被派发,请点明按哪一个选项派 —— 本席不替维护者在 ①②③ 之间选。
⚠️ 无论哪个方向,承接者都必须同时处理SchemaForm.deDeveloperize-8218.test.tsx的那条 pin:
⛔ 不是删掉它,而是连同它记录的理由一起改写。
⛔ 本席未认领本卡、⛔ 未改它的
pm:queue、⛔ 未碰定级。同笔只加pm:retriage。
Generated by Claude Code
- ⭐ 确认或推翻「无产品语义分叉」这句判据。若卡面那句「maintainer call」仍然成立
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Sep 19, 2026 3 remaining items
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsClaim: PM loop round 3 —
domain:uiexecution seat 3
Session:session_01D486C1axmXnrkJMNUfz2eb
Branch:claude/issue-8231-machine-name-chip-source-label
Worktree:objectui-issue-8231
Domain:domain:ui
Seat:domain:ui#3
File surface:packages/app-shell/src/views/metadata-admin/SchemaForm.tsx(FieldRow's predicate),packages/app-shell/src/views/metadata-admin/metadata-form-i18n.ts(the overlay preserves the source string),SchemaForm.deDeveloperize-8218.test.tsx(rewritten together with its reason, ⛔ not deleted), new tests beside them, one.changeset/8231-…md(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus(default judgement tier) — dispatch-gates refuses objectui (the answer is quoted on objectui#10226's claim) ⇒ tier is this seat's judgement.
Clause-②: no
Thread-read: 5749674288
Serial constraints cleared: open PRs and livepm:dispatchedclaims read 2026-09-24T16:58Z — none touchesSchemaForm.tsx,metadata-form-i18n.tsor the 8218 pin.Ruling-ref:
5749674288(director seat, batch #198 item 1, letter 1, maintainer 「同意」; fallback 3 pre-authorised on a measured cost). Maintainer instruction this session: 「任务很多,并发加到5」. WhyClause-②: no: this changes a maker-surface display predicate and an internal overlay; no published acceptance set or export changes. If threading the source label requires a new exported prop or type, that is a breach: stop and report.
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsos-dev-report
{ "issue": 8231, "status": "done", "branch": "claude/issue-8231-machine-name-chip-source-label", "pr": "https://github.com/objectstack-ai/objectui/pull/10320", "session": "session_01D486C1axmXnrkJMNUfz2eb (subagent; the parent's harness-stamped id, which matches the claim)", "premise_still_valid": true, "summary": "Ruling 1 landed; fallback 3 was not needed. FieldRow now judges prettify(name) against the untranslated source label: untranslatedFieldLabel(fieldSpec), else schema.title, else prettify(name). localizeMetadataForm stamps each field's incoming label under a module-private symbol before resolveMetadataFormLabels runs. Object spread carries the stamp through the resolver, and fields the resolver synthesizes (the header composite's children) are stamped with an undefined source. Cost measured: no exported prop or type changes (FormFieldSpec and the SchemaForm props are untouched), so Clause-2 stays no. It took a new leaf with no runtime imports, field-source-label.ts, so SchemaForm's static closure gains no @objectstack/spec/system importer (19 files at base, 20 now, 0 spec/system importers). It also took two changes outside the claimed surface, both needed for the fix to hold. (1) mergeServerFields copies shallowly instead of via JSON, which dropped the symbol. (2) The sectioned row schema's title override takes the source label instead of the translation; otherwise FieldRow's schema.title fallback would still read the translation, and every title reader prefers fieldSpec.label anyway. The 8218 pin is rewritten with its reason: under the fix the old hand-labelled 列数 fixture would have stayed green for the wrong reason, because it bypasses the overlay. The new fixture goes through the real overlay and asserts chip absent beside gap and present beside columns (source 'Grid width') in en and zh. One ruling premise did not hold: the example 'shown for refreshInterval / Auto refresh' assumed an English source label, but every dashboardForm field is authored without a label, so all four layout fields hide the chip in both locales, as en always did. Assignee on arrival: os-project-manager, left untouched.", "tests": "All at head d35e00806. (1) Red before, green after: fix committed, then SchemaForm.tsx, metadata-form-i18n.ts and mergeServerFields.ts reverted to base 8b1f06619 with the new tests kept (EXIT trap; untranslatedFieldLabel hits after revert: 0 and 0). Result: 7 failed / 17 passed. Red: the zh dashboard chip set was actions, columns, gap, header and one more, against [] in en; the raw-schema 'source' was chipped in zh only; the rewritten 8218 zh case failed. The en cases were green before and after, which is the inversion. Restore was proven by git diff HEAD being empty and the 3 blob hashes equal to HEAD. After the fix: 3 files, 31 passed. (2) pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/metadata-admin/: 287 files passed, 3081 tests passed, 1 skipped (lock VERDICT command-exit 0). (3) turbo build --filter=@object-ui/app-shell^...: 28 of 28. pnpm --filter @object-ui/app-shell type-check (tsc --noEmit and tsc -p tsconfig.test.json, whose include covers src/**/*.test.tsx): VERDICT command-exit 0. (4) eslint on the 6 touched files (package config, --format json): 6 files, 0 errors, 18 warnings, all on pre-existing lines. (5) Exit 0: check-changeset-presence, changeset:check, check:changeset-claims, check:pending-changeset-literals, check:new-line-citations (0 new), check:control-bytes, check:test-path-roots, check:unreferenced-sources, check:spec-symbols, check:vi-mock-specifiers, governed --test (NOT GOVERNED). NOT MEASURED: check:eager-closure, reason: it needs apps/console/dist/eager-closure.json from a console build, which was not run; the static-closure probe above is the substitute. The full pnpm test, lint and type-check runs are left to CI. CI at report time on d35e008: 42 check runs, 21 success, 3 skipped, 18 in_progress, 0 failed. Gates derived by hand from objectui package.json and .github/workflows (lint.yml, ci.yml), because dispatch-gates refuses objectui. Deviation: one lock call hit queue-timeout 99 (NOT MEASURED) and was retried with the same slot; that run is the one reported in (2).", "mcp_calls": "0", "api_writes": "3 total, 2 of them through the fleet-write relay: pr_create, i.e. POST /repos/objectstack-ai/objectui/pulls (draft, #10320, run 36036507125), and this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/8231/comments. The third is git push, 3 times (empty probe branch, then 2 commits). Zero label writes, zero PR-body PATCH. Reads went through REST GET only.", "open_questions": [], "out_of_scope_findings": [ "none filed. Noted in PR Acceptance notes only: the record widget rebuilds its key row's spec from keyField.label as a fresh object, so a translated key label there would lose the stamp. No overlay covers a record key today, so it is not reachable. carrier: none" ], "files_changed": [ ".changeset/8231-machine-name-chip-source-label.md (+24)", "packages/app-shell/src/views/metadata-admin/SchemaForm.tsx (28 lines changed)", "packages/app-shell/src/views/metadata-admin/metadata-form-i18n.ts (+76)", "packages/app-shell/src/views/metadata-admin/field-source-label.ts (new, 63)", "packages/app-shell/src/views/metadata-admin/mergeServerFields.ts (19 changed)", "packages/app-shell/src/views/metadata-admin/SchemaForm.deDeveloperize-8218.test.tsx (87 changed)", "packages/app-shell/src/views/metadata-admin/SchemaForm.machineNameChip-8231.test.tsx (new, 208)" ], "line_counts": "7 files, 484 insertions, 21 deletions vs base 8b1f06619", "head_sha": "d35e00806432095394b27870d0ee539a719d29e6", "deviations": [ "The file surface grew beyond the claim: field-source-label.ts (new leaf) and mergeServerFields.ts (producer-side JSON clone). Both are needed; see summary. The claim comment was not edited.", "The ruling's refreshInterval/'Auto refresh' example does not match the spec, which authors no field labels. The locale-independent predicate still holds, and the present-case is shown with a fixture source label.", "Worktree removed after the PR opened. node_modules deleted first, git worktree remove with no --force." ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actions✅ ACCEPT — PR objectui#10320 at
d35e008·pm:dispatched→pm:blockedon objectui#10287domain:uiseat 3,session_01D486C1axmXnrkJMNUfz2eb, 2026-09-24T18:06Z. Reviewed against the diff, the tree and CI.Implemented-by: claude/issue-8231-machine-name-chip-source-label Reviewed-by: session_01D486C1axmXnrkJMNUfz2ebitem reading shape draft · base main· line 1Fixes #8231· line 2Clause-②: noruling letter 1 delivered; the pre-authorised fallback 3 was not needed scope 7 files. Two sit outside the claim (a new private leaf, and the mergeServerFieldsshallow copy); both are disclosed, required, and accepted by the reviewcontract review PASS at d35e008(75/75 at tier), recorded on the PR. This seat corrected two imprecise figures in the PR bodyruling premise the 「refreshInterval / Auto refresh」 example does not match spec 17.4.0 (no authored labels; the field is refreshIntervalSeconds). The rule holds; noted for the directorThe PR waits outside the queue on
Spec Main Shape Gate(objectui#10287; fix PR objectui#10315 is open). The card body gainsBlocked-by: #10287andUnlock-action: re-check PR #10320.
Generated by Claude Code
- added and removed
on Sep 24, 2026 objectstack-fleet commented
on Sep 24, 2026 ContributorMore actions🟢 LANDED — PR objectui#10320 merged as
78b572f60(merge queue)domain:uiseat 3,session_01D486C1axmXnrkJMNUfz2eb, 2026-09-24T19:23Z. Merged 2026-09-24T19:22Z. Ruling 1 (5749674288) is onmain.Verified by content on objectui
origin/main:FieldRowinpackages/app-shell/src/views/metadata-admin/SchemaForm.tsxjudges the machine-name chip against the untranslated source label (untranslatedFieldLabel, newfield-source-label.ts).metadata-form-i18n.tskeeps the source string beside its overlay. The objectui#8218 pinSchemaForm.deDeveloperize-8218.test.tsxis rewritten together with its reason, not deleted, and the new pinSchemaForm.machineNameChip-8231.test.tsxis present. The squash commit carries no model-named trailer.Fixes #8231closed the cardcompleted, but the auto-close does not strip labels;pm:dispatchedis removed in this stroke. The other labels stay.
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
维护者速读
事情:Studio 表单里那个显示「机器名」的小标签(chip),它的显示条件是拿英文猜出来的名字去跟可见标签比。于是:
prettify('columns')=Columns,永远不等于「列数」⇒ 每一个字段旁边都挂着那个 chip。Columns==Columns⇒ 它几乎从不出现。⇒ ⭐ 这个功能在它被设计的那个语言里近乎隐形,在它没被设计的语言里无条件刷屏 —— 正好反了。
为什么要你拍板:立卡席写得很清楚 ——「三个答案都站得住,而且不是同一个决定」,并把它留给你。这不是修法问题,是这个 chip 到底为谁服务的产品问题:
refreshInterval。席位意见:荐 1。它是唯一让这个功能说到做到的选项 —— chip 的承诺是「标签没告诉你机器名」,而 1 让这句话在每种语言里都为真;2 是把问题挪走(仍然没人修好判据),3 是承认这句话不再成立。⚠️ 四棱④(创业阶段不扩散)轻微反对 1:它和 2 都要新管线,只有 3 零新增 —— 所以如果覆盖层保留原串的代价被实测为高,3 是诚实的回退,⛔ 不是失败。
SchemaForm.deDeveloperize-8218.test.tsx上有一条绿着的 pin 依赖当前行为。⛔ 它不能被删掉,要连同它记录的理由一起改写 —— 否则下一个人会把这次的决定读成一次回归。你要做的:回一个数字 —— 1 / 2 / 3。
os-decision-facets
columns/gap/refreshInterval/header)的 chip 同时全显,en-US 下同样四个全隐。⛔ 未测的是有没有人抱怨过 —— 所以这条轴说明它真的坏了,⛔ 不说明它急。Governing text:
packages/app-shell/src/views/metadata-admin/SchemaForm.tsx的FieldRow判据 ·metadata-form-i18n.ts的覆盖层 · objectui#8218 的验收面(只要求「无未翻译英文串进入面板」,⛔ 未涉及何时显示)。Split out of objectui#8218, which fixed the chip's tooltip (it was a hardcoded English
title="Machine name") but deliberately did not touch WHEN the chip renders. That is a product call, not a rendering one, so it is filed rather than decided.The mechanism
packages/app-shell/src/views/metadata-admin/SchemaForm.tsx, inFieldRow:The chip exists to answer "the visible label does not tell you the machine name, so here it is." That predicate compares a HUMANIZED MACHINE NAME against the VISIBLE LABEL — which is only ever a fair comparison while the label is English.
Studio localizes these panels:
metadata-form-i18n.tsoverlaysmetadataForms.dashboard.fieldssocolumnsis labelled 「列数」,gap「间距」,refreshInterval「自动刷新」,header「页眉」.prettify('columns')isColumns, which can never equal 「列数」 — so the guard is false for EVERY field and the chip renders beside every label in the panel.Symmetrically, in
en-USthe same four fields hide the chip (labelColumns==prettify('columns')), so the affordance is near-invisible in the locale it was designed for and unconditional in the one it was not. That inversion is what objectui#8218 observed as "columns / gap / refreshInterval / header 四个 chip" all showing at once.Why it was not fixed in objectui#8218
Three answers are all defensible and they are not the same decision:
SchemaFormdoes not currently receive. Needs the localization overlay to preserve the source string.refreshInterval. Needs a prop threaded from the host, since the same component serves both audiences.objectui#8218's acceptance only asked that no untranslated English string reach the panel, which the tooltip fix satisfies. Picking among the three above is a maintainer call.
No assignee, no
pm:queue— triage as you see fit.Generated by Claude Code