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:
- 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.
- 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.
A form section authored with a
labelbut nonameis structurallyuntranslatable —
_sectionsis keyed by section name, so there is no key for abundle to carry. Nothing in the toolchain says so: not the schema (
nameisoptional), not
os lint, and — after #5405 — not the coverage report either,because a walker that emits
sections[].nameemits nothing for a section thathas no name. The heading silently stays in the source locale in every locale,
and coverage reads 100%.
The renderer keys off
name, and correctly soobjectui 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 fiveform-type branches) and
:966-968(stacked section divider)packages/plugin-form/src/ModalForm.tsx:588,:684packages/plugin-detail/src/renderers/record-details.tsx:199All of them guard on
section.nameand fall back to the authored label when itis 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:
objects.<o>._sections— a bundle can ship every section heading in English and lint zero warnings #5405 adds asectionkind whose second source is "everysections[].nameunder the object's pages/form views". A nameless section contributes no name,
so no
ExpectedEntryis emitted, socomputeI18nCoveragecannot count it asmissing. Post-cli: the i18n coverage walker never collects
objects.<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 oneof those headings renders English.
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 translatedsection 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 noname: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_casedetail page sections carry names (info/status/descriptionin
src/pages/case_detail.page.ts) and translate, while its form viewsections (
{ label: 'Case' },{ label: 'SLA' },{ label: 'Resolution' }insrc/views/case.view.ts) carry none — producing exactly the reportedCase / SLA / Resolutionstrip. The renderer half was verified correct againstobjectui
origin/mainand 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:
packages/lint, alongsidevalidate-translation-references):a section that declares a
labelbut noname, on an object that has anytranslations at all, warns — "this heading can never be translated; give the
section a stable
name". Cheap, non-breaking, and it is the rule that wouldhave caught all 70.
packages/spec): consider requiringnameonFormSectionoutright. 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.