Skip to content

objectui: the two selectFirst gate hints join controlling-field names with hardcoded separators — and with two DIFFERENT ones #4026

Description

@os-zhuang

Migrated from objectstack-ai/objectstack#5432 under the file-at-destination ruling (objectstack-ai/objectstack#7167, maintainer 2026-08-10). Originally filed 2026-08-05T11:11:46Z. The full prior thread — including triage rulings and hold/restart conditions — remains on the source issue and MUST be read before acting on this card.


Observation-class finding, noticed while fixing objectstack#5407. Nothing a user hits today with any urgency — it needs a field gated on two or more controlling fields, which is rare — so it carries finding and no pm:queue. Recording it because objectstack-ai/objectstack#5407 has just established the mechanism that fixes it.

objectstack-ai/objectstack#5407 item 4 established that a list separator is a locale property, and added validation.formInvalidJoiner (per-pack: ", " for Latin scripts and Korean, "、" for zh/ja, U+060C + space for Arabic) after measuring Intl.ListFormat and finding its output unusable for a truncated list.

Two other sites join user-visible names with a hardcoded separator, and they do not even agree with each other:

SiteSeparatorSentence
packages/fields/src/widgets/LookupField.tsx", "lookup.selectFirst
packages/components/src/renderers/form/form.tsx (option-field gate)" / "fields.options.selectFirst

Both fill the {{fields}} slot of what is deliberately one shared sentence — the form renderer's own comment says the two callers exist so "the gate can never read differently depending on which side produced it" — yet a field gated on two parents reads Select Account, Owner first from the lookup and 请先选择Account / Owner from the select. Under zh/ja both separators are wrong for the script on top of that.

Suggested fix

Reuse the mechanism objectstack-ai/objectstack#5407 added rather than inventing a second one: either read validation.formInvalidJoiner at both sites, or (if the gate hint wants its own punctuation) add one fields.gateJoiner key across the ten packs. Either way it has to be one key read by both callers — two keys would recreate the divergence the shared sentence exists to prevent.

Note for the implementer: LookupField receives the labels through the dependsOnLabels prop objectstack-ai/objectstack#5407 added, so the joining happens in dependsOnFieldsText there; the form's copy is in the gatedHint memo.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions