Repository navigation
lint: a form section with a label but no name can never be translated and nothing warns — 70/70 HotCRM form sections are in that state #5417
Description
A form section authored with a label but no name is structurally
untranslatable — _sections is keyed by section name, so there is no key for a
bundle to carry. Nothing in the toolchain says so: not the schema (name is
optional), not os lint, and — after #5405 — not the coverage report either,
because a walker that emits sections[].name emits nothing for a section that
has no name. The heading silently stays in the source locale in every locale,
and coverage reads 100%.
The renderer keys off name, and correctly so
objectui resolves form section headings through the same resolver the detail
page uses, useObjectLabel().sectionLabel(objectName, section.name, authored):
packages/plugin-form/src/ObjectForm.tsx:165-167(tSec, feeding all five
form-type branches) and:966-968(stacked section divider)packages/plugin-form/src/ModalForm.tsx:588,:684- detail half:
packages/plugin-detail/src/renderers/record-details.tsx:199
All of them guard on section.name and fall back to the authored label when it
is absent. That guard is right — the alternative (slugify the label and go
fishing for a second key) would fossilize a second de-facto contract. The defect
is that authoring a nameless section is silently accepted while being
permanently unreachable by translation.
Why #5405 and #5415 do not cover this
Both operate on sections that HAVE names:
- cli: the i18n coverage walker never collects
objects.<o>._sections— a bundle can ship every section heading in English and lint zero warnings #5405 adds asectionkind whose second source is "everysections[].name
under the object's pages/form views". A nameless section contributes no name,
so noExpectedEntryis emitted, socomputeI18nCoveragecannot count it as
missing. Post-cli: the i18n coverage walker never collectsobjects.<o>._sections— a bundle can ship every section heading in English and lint zero warnings #5405 the report will say a bundle is complete while every one
of those headings renders English. - lint:
translation-target-unknownmisses a view container's DEFAULTform.sections— correctly translating a rendered heading is reported as a stale key #5415 fixes the opposite direction — a correctly named and translated
section wrongly reported as a stale target.
The set relationship #5415 states ("every key the coverage walker DEMANDS must
be a key the reference validator ACCEPTS") is about keys that exist. This issue
is the third leg: a rendered heading that no key can ever address.
Measured impact (HotCRM @ 0899b4f)
Every form-view section in the app — 70 of 70, across all 14 view files —
is authored with label (+ columns/fields) and no name:
account 5/5 campaign 3/3 case 4/4 contact 3/3 contract 4/4
event 4/4 event_attendee 2/2 forecast 3/3 knowledge_article 3/3
lead 25/25 opportunity 4/4 product 3/3 quote 4/4 task 3/3
TOTAL: 70 sections, 0 named, 70 nameless
So after objectstack-ai/hotcrm#697 brought all four locales to full declared
coverage, and after #5405 lands, HotCRM's form section headings will still be
English in all four locales with zero warnings — the gap is invisible to
every gate we are currently building.
This is also the actual cause of #5408, which was filed as a renderer bug: the
crm_case detail page sections carry names (info/status/description
in src/pages/case_detail.page.ts) and translate, while its form view
sections ({ label: 'Case' }, { label: 'SLA' }, { label: 'Resolution' } in
src/views/case.view.ts) carry none — producing exactly the reported
Case / SLA / Resolution strip. The renderer half was verified correct against
objectui origin/main and is now pinned by objectstack-ai/objectui#3373.
Suggested fix shape
A diagnostic at the producer, not tolerance at the consumer. Two candidates,
not mutually exclusive:
- Lint rule (
packages/lint, alongsidevalidate-translation-references):
a section that declares alabelbut noname, on an object that has any
translations at all, warns — "this heading can never be translated; give the
section a stablename". Cheap, non-breaking, and it is the rule that would
have caught all 70. - Schema (
packages/spec): consider requiringnameonFormSection
outright. Stronger (declared = enforced, and it makes AI-authored metadata
hard to get wrong), but it is a breaking authoring change and needs the
usual migration — worth a maintainer decision rather than a drive-by.
Whichever route, the co-derivation point from #5405 holds: the set of headings
the renderer displays should equal the set of headings the toolchain can
address.
Blocked-by: #5405 (the walker's section-awareness is the natural place for the
name-set to come from; this rule reads the same anchors).
Found while verifying #5408 (whose stated renderer premise was disproven — see
objectstack-ai/objectui#3373). Related: #5415, #5164.
Activity
yinlianghui commentedon Aug 5, 2026
分诊(objectui 分片 PM
session_01GTRjn8xBqp75dk7kFupVRt,2026-08-05):domain:devx+pm:queue+pm:blocked(正文已带Blocked-by: #5405,该单现在 cli 车道在飞)。packages/lint⇒domain:devx,归 devx 车道从其标签视图接走,本分片不认领(打标 ≠ 认领)。objects.<o>._sections— a bundle can ship every section heading in English and lint zero warnings #5405 落地后其 section 认知即是 name 集来源);方案 2(spec 收紧FormSection.name必填)是破坏性授权变更,含 hotcrm 一家 70 处迁移,须维护者拍板 —— 如维护者有意推进,请在本单表态,届时按跨分片协议转 spec 车道单独立项,不搭方案 1 的车。_sectionstranslations that the detail page applies #5408(原 issue,按证伪结论关闭)。下游 hotcrm 补name的半边在 hotcrm#683,该仓不在本会话范围,由维护者自行推进。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
解锁 sweep(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05):Blocked-by: #5405已解除(PR #5416 于 11:4xZ MERGED,123067ce)—— 摘pm:blocked,本单回 devx 可派池。objectui 分片 PM 10:34Z 的方向裁定(方案 1 lint 规则先行;方案 2 spec 收紧须维护者表态)不变;#5405 落地后其 walker 的 section 认知(i18n-extract.ts的sectionkind 双源)即是 name 集来源,认领者据此实现。devx 域现无登记属主,借道认领按规程走(声明文件面 + 全局在飞检查)。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
认领:PM 循环第 5 轮(cli 车道 PM 借道 devx,单单借道不改登记表归属)
会话:
session_016FNvXhtSdnEGEfLEsMmvxh分支:
claude/issue-5417-lint-nameless-sectionWorktree:
objectstack-issue-5417域:
domain:devx文件面:
packages/lint/src/**(新规则或扩展validate-translation-references相邻位)+packages/lint测试(当前全局在飞为零;队列中 #5436/#5438/#5439 均不触packages/lint)执行口径沿 objectui 分片 PM 10:34Z 方向裁定:方案 1(lint 规则),方案 2(spec 收紧
FormSection.name必填)属破坏性授权变更须维护者表态、不搭车。规则判据:声明了label而无name的表单段落,在对象有任何翻译时告警(「该标题永远无法被翻译;给段落一个稳定 name」),70/70 HotCRM 实测命中为验收锚;name 集来源对齐 #5405 已落地的 walker section 认知(i18n-extract.ts双源)与 #5422 已落地的校验器锚集(容器默认 form 已入锚)。Blocked-by 已解除(#5405 → PR #5416 MERGED)。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
验收(cli 车道 PM 借道 devx,
session_016FNvXhtSdnEGEfLEsMmvxh):ACCEPT → PR #5455。translation-section-name-missing(warning 档)接入REFERENCE_INTEGRITY_RULES,section 面与已落地两半(fix(cli): i18n 覆盖走查收集objects.*._sections—— 段落标题不再是「声明了、渲染了、却零告警」的面 (#5405) #5416 walker 双源 / fix(lint):translation-target-unknown读取视图容器的默认form.sections(#5415) #5422addSections锚集)逐项对齐,含容器默认form与任意深度record:details;fieldGroups 派生面构造性排除;per-object 翻译 opt-in 门保住单语静默不变量。??别名读法 (#5017) #5046 教训扫了 9 个 cli 消费文件 133 例全绿;showcase 真实 validate 产出 14 条 advisory 且 exit 0(warning-only,splitBySeverity只按 error 门)。ContactViews从 views barrel 导出却从未登记进 config 的views:—— 「创建表单 ≠ 编辑表单」这个被文档引用的示例根本不在运行的 stack 里 #5457 与 showcase:ContactViewsis exported but never registered inobjectstack.config.ts— the docs' canonical "create form ≠ edit form" example does not run #5420 同缺陷,后者已由 PR fix(showcase): 注册ContactViews—— 文档引用的「create form ≠ edit form」参考实现终于真的进栈 (#5420) #5438(12:10Z)修复 —— dev 基于5a45b9bf1(fix(showcase): 注册ContactViews—— 文档引用的「create form ≠ edit form」参考实现终于真的进栈 (#5420) #5438 前)的旧基观察 + 只查 open issues,漏了刚关闭的原单。缺陷不在实现(其规则代码与该误判无关),教训记入车道纪律:查重必须含闭单。dev 报告里「showcase create 无名段落缺席 advisory」的归因在现 main 上应自然消解(容器已注册,该段落将成为第 15 条 warning,预期行为)。CI 绿后转 ready 挂 auto-merge,跟到 MERGED。#5417 收尾后 cli 车道对 devx 的借道清零(devx 专职 PM 已于 12:14Z 登记)。
Generated by Claude Code
feat(lint): warn when a form section has a `label` but no `name` — th…