Moved from objectstack-ai/objectstack#17264 by the triage seat (session_01KYzNJPin9Ar4oMMkSh4S9h), under the ruling on objectstack-ai/objectstack#17250 (letter A — a card lives in the repo its fix lands in) and the maintainer's 2026-09-20 approval of the hybrid split.
Recreated rather than transferred because GitHub's issue transfer exists only in GraphQL (POST /graphql answers 403 from a Claude Code session) and the REST API has no transfer endpoint (404) — measured, not assumed.
⛔ Nothing in the original text below was changed except two mechanical edits the cross-repo rule requires: bare #N references were qualified to objectstack-ai/objectstack#N so they keep pointing where they pointed, and (where present) the Blocked-by: objectstack-ai/objectstack#17250 line was dropped — that blocker was 「don't work this until we know which repo owns it」, and this move is the answer to it.
Original filer: zhuangjianguo, 2026-09-10T01:16:42Z. The source card is closed duplicate pointing here.
Found in a browser dogfood pass on objectstack-ai/hotclm (hotclm#45), on @objectstack/* 17.4.0. Filed at the destination per that repo's AGENTS.md — Platform gaps: report, never patch. ⛔ Not triaged: no domain:*, no priority, no assignee.
This is the one that stops the consuming app being demonstrable at all: the action it blocks is that product's primary user action (launch a contract), and there is no other path to it in the UI.
Symptom
An action declares a params entry that is a lookup backed by an object (clm_contract_type). The console renders it as a plain text box:
- 0 options offered, no dropdown, no typeahead.
- No request for the referenced object appears on the wire at all — nothing for
clm_contract_type in the network log while the dialog is open. The picker is not failing to load; it is never attempted.
- The field is
required, so with no way to choose a value, the dialog cannot be submitted.
The proof that only the picker is broken
The flow behind the action is fine. Driving it directly with an id pasted in:
POST /api/v1/automation/contract_intake/trigger { … contract_type: "<pasted id>" … }
→ 200
⇒ The action, the flow, its validation and its writes all work. The single missing piece is the control that would let a human supply the value. A user cannot paste an internal id, so for a user the feature does not exist.
Version boundary — this used to work, and the regression is documented in the consuming app
hotclm's own flow source carries a comment annotated (measured on 17.3.0) stating that field-backed pickers render in the action dialog. On 17.4.0 that is no longer true. The consuming repo has now been bitten five or six times by (measured) annotations that were correct when written and were silently invalidated by a later platform change — this is one of them, and it is the most expensive so far.
⚠️ ⛔ Not established here: whether the break is in the console's param renderer, in the metadata the server serves for action params, or in the contract between them. The consuming app cannot tell from outside, and ⛔ this card must not be read as blaming the renderer. Establish which side dropped the field's object binding before fixing either. A useful first reading is what /api/v1/meta/app (or the action-metadata route) actually serves for that param on 17.4.0 versus 17.3.0 — if the object binding is absent there, the renderer is innocent.
Reproduce
git clone https://github.com/objectstack-ai/hotclm && cd hotclm
pnpm install # resolves @objectstack/* 17.4.0
pnpm demo
# sign in at /_console/, reach the contract register, press the launch/intake action
# observe: the Contract Type param is a text box; no clm_contract_type request is made
Expected
A params entry bound to an object renders a picker that queries that object, exactly as the same field does on a record form — where it does work in this same build. A required param with no way to supply a value should be impossible to ship: if the binding cannot be resolved, the dialog should refuse loudly rather than render an unusable text box.
Two more dialog defects from the same pass, filed separately
The same intake dialog is also unreachable for two independent reasons, each its own card: the dialog has no max-height or internal scroll (1162px tall content in a 950px viewport, Submit at y=991, no scrollable ancestor), and the file widget posts a browser blob object where the engine wants a sys_file id string (400 expected string, received object). Any one of the three is enough to block the action; all three are present at once.
Related
hotclm#45 (the dogfood pass) · objectstack-ai/objectstack#5150 (closed, adjacent: a create dialog ignoring a field's defaultValue)
Generated by Claude Code
Generated by Claude Code
Found in a browser dogfood pass on
objectstack-ai/hotclm(hotclm#45), on@objectstack/*17.4.0. Filed at the destination per that repo'sAGENTS.md— Platform gaps: report, never patch. ⛔ Not triaged: nodomain:*, no priority, no assignee.This is the one that stops the consuming app being demonstrable at all: the action it blocks is that product's primary user action (launch a contract), and there is no other path to it in the UI.
Symptom
An action declares a
paramsentry that is a lookup backed by an object (clm_contract_type). The console renders it as a plain text box:clm_contract_typein the network log while the dialog is open. The picker is not failing to load; it is never attempted.required, so with no way to choose a value, the dialog cannot be submitted.The proof that only the picker is broken
The flow behind the action is fine. Driving it directly with an id pasted in:
⇒ The action, the flow, its validation and its writes all work. The single missing piece is the control that would let a human supply the value. A user cannot paste an internal id, so for a user the feature does not exist.
Version boundary — this used to work, and the regression is documented in the consuming app
hotclm's own flow source carries a comment annotated(measured on 17.3.0)stating that field-backed pickers render in the action dialog. On 17.4.0 that is no longer true. The consuming repo has now been bitten five or six times by(measured)annotations that were correct when written and were silently invalidated by a later platform change — this is one of them, and it is the most expensive so far./api/v1/meta/app(or the action-metadata route) actually serves for that param on 17.4.0 versus 17.3.0 — if the object binding is absent there, the renderer is innocent.Reproduce
Expected
A
paramsentry bound to an object renders a picker that queries that object, exactly as the same field does on a record form — where it does work in this same build. A required param with no way to supply a value should be impossible to ship: if the binding cannot be resolved, the dialog should refuse loudly rather than render an unusable text box.Two more dialog defects from the same pass, filed separately
The same intake dialog is also unreachable for two independent reasons, each its own card: the dialog has no max-height or internal scroll (1162px tall content in a 950px viewport, Submit at y=991, no scrollable ancestor), and the file widget posts a browser blob object where the engine wants a
sys_fileid string (400 expected string, received object). Any one of the three is enough to block the action; all three are present at once.Related
hotclm#45 (the dogfood pass) · objectstack-ai/objectstack#5150 (closed, adjacent: a create dialog ignoring a field's
defaultValue)Generated by Claude Code
Generated by Claude Code