Blocked-by: objectstack-ai/objectui#9248
The gap
ScreenFieldConfigSchema (@objectstack/spec/automation) is .strict and its entire key set is:
name · label · type · required · options · defaultValue · placeholder · visibleWhen
That is thin enough that two ordinary authoring intents have no expression at all, and both degrade in a way the author only discovers by running the flow or by reading a rejection.
1. A bounded numeric has no bound. max is rejected BY NAME (Unrecognized key(s) on this screen field: max), so it fails os validate rather than quietly doing nothing — good — but there is then no key that expresses the bound. helpText is rejected the same way, even though the console's dialog would render one. The only carriers left are label and placeholder, and placeholder renders only while the input is empty, so a field with a defaultValue surfaces its hint for roughly the moment the user clears the box.
2. A type: 'lookup' screen field cannot name its target object. There is no object / reference_to / referenceTo key, so the picker has nothing to resolve records from. The type is accepted; the affordance is not delivered.
Measured evidence from a downstream app
In objectstack-ai/hotcrm's src/flows/:
quote_generation's discount field must respect crm_quote.discount_within_ceiling, a HARD block with no override. With no max, a rep meets the ceiling by having the quote REFUSED after submitting. The ceiling is interpolated into the label and the placeholder as the only available carriers, and a comment explains at length why there is no max — the comment exists because the schema key does not.
close_case's "Resolved by Article" field is type: 'lookup' with a placeholder reading Knowledge article id, if the KB resolved this case — i.e. the app asks a human to type a record id, because the picker cannot be pointed at crm_knowledge_article. The real picker for the same column lives on the record form; the screen field is a degraded twin of it.
Both are hand-written prose standing in for a missing key, in the reference app other people copy.
Proposal
Widen ScreenFieldConfigSchema for the cases whose runtime already exists:
min / max (and optionally step) on numeric-ish types (number, percent, currency), forwarded into the ScreenSpec the client renders.
helpText, forwarded the same way — the console dialog can already render it.
- A target-object key on
type: 'lookup' so the field resolves a record picker, matching how a lookup is declared everywhere else in the spec.
If any of these should stay out by design, that is a fine answer — but it would be worth saying so in the schema, because today the absence reads as an oversight to an author and gets worked around in prose.
Not a duplicate
Searched the backlog before filing, per the standing cross-repo rule. The only nearby hit is #7486, which is about the public lookup ROUTE resolving a picker target from legacy field spellings — a different surface (a REST route, not the flow screen field schema) and a different failure (a 500, not an unexpressible key).
Filed from hotcrm#1184 phase 2 (comment slimming, src/flows/), where these comments were read block by block and kept because the constraint is real.
Generated by Claude Code
Blocked-by: objectstack-ai/objectui#9248
The gap
ScreenFieldConfigSchema(@objectstack/spec/automation) is.strictand its entire key set is:That is thin enough that two ordinary authoring intents have no expression at all, and both degrade in a way the author only discovers by running the flow or by reading a rejection.
1. A bounded numeric has no bound.
maxis rejected BY NAME (Unrecognized key(s) on this screen field: max), so it failsos validaterather than quietly doing nothing — good — but there is then no key that expresses the bound.helpTextis rejected the same way, even though the console's dialog would render one. The only carriers left arelabelandplaceholder, andplaceholderrenders only while the input is empty, so a field with adefaultValuesurfaces its hint for roughly the moment the user clears the box.2. A
type: 'lookup'screen field cannot name its target object. There is noobject/reference_to/referenceTokey, so the picker has nothing to resolve records from. The type is accepted; the affordance is not delivered.Measured evidence from a downstream app
In
objectstack-ai/hotcrm'ssrc/flows/:quote_generation's discount field must respectcrm_quote.discount_within_ceiling, a HARD block with no override. With nomax, a rep meets the ceiling by having the quote REFUSED after submitting. The ceiling is interpolated into thelabeland theplaceholderas the only available carriers, and a comment explains at length why there is nomax— the comment exists because the schema key does not.close_case's "Resolved by Article" field istype: 'lookup'with aplaceholderreadingKnowledge article id, if the KB resolved this case— i.e. the app asks a human to type a record id, because the picker cannot be pointed atcrm_knowledge_article. The real picker for the same column lives on the record form; the screen field is a degraded twin of it.Both are hand-written prose standing in for a missing key, in the reference app other people copy.
Proposal
Widen
ScreenFieldConfigSchemafor the cases whose runtime already exists:min/max(and optionallystep) on numeric-ish types (number,percent,currency), forwarded into theScreenSpecthe client renders.helpText, forwarded the same way — the console dialog can already render it.type: 'lookup'so the field resolves a record picker, matching how a lookup is declared everywhere else in the spec.If any of these should stay out by design, that is a fine answer — but it would be worth saying so in the schema, because today the absence reads as an oversight to an author and gets worked around in prose.
Not a duplicate
Searched the backlog before filing, per the standing cross-repo rule. The only nearby hit is #7486, which is about the public lookup ROUTE resolving a picker target from legacy field spellings — a different surface (a REST route, not the flow screen field schema) and a different failure (a 500, not an unexpressible key).
Filed from hotcrm#1184 phase 2 (comment slimming,
src/flows/), where these comments were read block by block and kept because the constraint is real.Generated by Claude Code