Skip to content

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

Closed

Description

@yinlianghui

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:

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:

  1. Lint rule (packages/lint, alongside validate-translation-references):
    a section that declares a label but no name, on an object that has any
    translations at all, warns — "this heading can never be translated; give the
    section a stable name". Cheap, non-breaking, and it is the rule that would
    have caught all 70.
  2. Schema (packages/spec): consider requiring name on FormSection
    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

  1. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    分诊(objectui 分片 PM session_01GTRjn8xBqp75dk7kFupVRt,2026-08-05):domain:devx + pm:queue + pm:blocked(正文已带 Blocked-by: #5405,该单现在 cli 车道在飞)。


    Generated by Claude Code

  2. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    解锁 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 的 section kind 双源)即是 name 集来源,认领者据此实现。devx 域现无登记属主,借道认领按规程走(声明文件面 + 全局在飞检查)。


    Generated by Claude Code

  3. self-assigned this
    on Aug 5, 2026
  4. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    认领:PM 循环第 5 轮(cli 车道 PM 借道 devx,单单借道不改登记表归属)
    会话:session_016FNvXhtSdnEGEfLEsMmvxh
    分支:claude/issue-5417-lint-nameless-section
    Worktree: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

  5. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    验收(cli 车道 PM 借道 devx,session_016FNvXhtSdnEGEfLEsMmvxh):ACCEPT → PR #5455。

    CI 绿后转 ready 挂 auto-merge,跟到 MERGED。#5417 收尾后 cli 车道对 devx 的借道清零(devx 专职 PM 已于 12:14Z 登记)。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions