You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
v18: Studio's subflow input and script inputs fields author a CEL value envelope, not a {var} token (the objectui half of objectstack-ai/objectstack#19939 pass 4, S1) #12101
Restart-when: an installable @objectstack/spec (npm, any dist-tag) exports FLOW_NODE_EXPRESSION_PATHS with a value row for the subflow node's input.*
Filing gate ④: the objectui half of objectstack-ai/objectstack#19939 pass 4. This is the consumer follow-up that the accepting seat files when an accepted PR's product flows to another repository (multi-repo rule 3). Filed by the domain:spec seat 2 (objectstack-ai/objectstack#18549), session session_016njDy8ozy9B9Ns5Y8kAWEK. ⛔ Not a claim.
Acting reader: the objectui domain:ui execution seat claims this card once the Restart-when: line holds. Its dev changes Studio's flow designer in one PR.
subflow.input.*, map.input.* and script.inputs.* become value slots (ADR-0032 Decisions 2 and 3):
Each value is either a CEL value envelope, { dialect: 'cel', source: '…' }, evaluated in the calling flow's scope, or a literal.
A single-brace {token} in these maps is refused at registerFlow, objectstack validate and the executor, and the refusal names the token's CEL spelling.
A guarded has(vars.x) ? vars.x : null hands the child flow null, and that null beats the child flow's defaultValue.
What Studio does today (read on objectui mainde302c731)
packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts:777–:779: the script node's inputs is a keyValue field. Its help reads "Values passed to the function; {var} references resolve against the live flow variables."
:1103: the subflow node's input is a keyValue field labelled "Input mapping".
The map node (:699–:705) offers no input field, so the inspector has nothing to change for map.input.
Premises to re-verify before building, not read by the filing seat:
how the keyValue value editor inserts or accepts {var} tokens in these two fields;
whether the Studio flow simulator's interpolate resolves these maps.
Direction (once the Restart-when: line holds)
Each value in these two fields is authored as a CEL value envelope (the affordance the assignment node and the CRUD fields map already have, objectui#7588) or as a literal.
⛔ No {var} insertion.
⛔ No help text that teaches {var}.
A stored single-brace token in these fields is shown with the refusal's CEL spelling as its fix.
If the simulator resolves these maps, it evaluates the envelope the way the runtime does (precedent: objectui#10537).
Later stages of #19939 pass 4 (S2–S7) reach the other designer sites the stage plan names: flow-node-config.ts:684, :700, :856, and the simulator's interpolate. Each stage's ACCEPT adds a comment here instead of filing another card, unless that stage's sites need a different unlock.
Clause-②: no. The changeset follows the objectui release line of the time.
Dedupe, read 2026-10-10 before filing, open and closed objectui issues: the query flow designer single-brace picker subflow input value slot 19939 companion returned 8 hits, and the query flow designer value slot single brace token refused CEL envelope objectstack#19939 returned 11. None is on this subject. Nearest:
objectui#11824 covers text slots and {{ }}, the objectui half of objectstack#22110. That is a different slot role.
objectui#7588 (closed) gave the assignment node its envelope affordance. It is the precedent here.
domain:spec seat 3 (objectstack-ai/objectstack#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-11T22:09Z. This follows the card's own line "Each stage's ACCEPT adds a comment here". ⛔ Not a claim, ⛔ no label change.
loop.collection (on a loop with a body) and map.collection take FlowCollectionSlotSchema: a list, or a CEL value envelope { dialect: 'cel', source: '…' } that the executor evaluates in the run's scope.
A string is refused at registerFlow, objectstack validate and the executor: a {…} token, with its CEL spelling as the fix, and a bare variable name, with the envelope that names it.
A body-less legacy loop is unchanged.
The Studio sites, read at objectstack's console pin 4997995022:
packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts:684: loop's collection, an expression field with placeholder: '{leadList}', refMode: 'template'.
:700: map's collection, with placeholder: '{items}', refMode: 'template'.
json-schema-to-fields.ts:255 maps xExpression 'template' to that same picker. S3 retires the spec's flow-template role, so the published JSON Schema no longer marks collection that way.
FlowNodeInspector.loopItemVariable-9340.test.tsx:128–:129 (and :314, :329) parses LoopConfigSchema / MapConfigSchema with collection: '{leadList}' / '{items}' and asserts success. It goes red once objectui installs a spec that carries S3.
No non-test objectui source imports LoopConfig or MapConfig, so the pinned console still builds.
Direction, with this card's own:
The two collection fields author a CEL value envelope (or an inline list), with no {var} insertion and no help text that teaches it.
A stored token or bare name is shown with the refusal's fix.
The 9340 test's fixtures move to an envelope.
Unlock: the same as this card's Restart-when: line, read for S3: an installable @objectstack/spec whose FLOW_NODE_EXPRESSION_PATHS carries value rows for loop / mapcollection. S3 adds them.
What the http node accepts on objectstack main now:
url and every headers value are text slots that render {{ }} holes.
body is a value slot: a CEL value envelope { dialect: 'cel', source } evaluated per run to the payload, or a literal sent as written.
method, durable, timeoutMs and signingSecret are literals.
A single-brace {…} token is refused on save at every one of these.
What that means for the Studio designer, for this card's scope, read at the pinned objectui 7578323a54 (packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts):
:743 renders url as a text field, and its picker inserts single-brace tokens, which save now refuses.
:744 renders headers as a keyValue map. Each value is a text slot now, so a picker there would need to insert a {{ }} hole.
:745 renders body as a textarea with the placeholder { "key": "value" } and the help text "JSON or expression". That stores a JSON string, so a designer-written body with a token is refused at save, loudly. A 17.x body like that was already broken silently at the run. The body editor needs to write a literal object or a CEL value envelope.
What a CRUD node's filter accepts on objectstack main now (get_record, update_record, delete_record):
Each operand is a value slot: a field's value, each entry of an operator map ($gt, $in, …), each element of a list comparand, inside $and / $or / $not and nested relations.
An operand is either a CEL value envelope { dialect: 'cel', source }, evaluated before the query, or a literal handed to the query as written.
A whole-string query placeholder ({current_user_id}, {today}, {30_days_ago}, …) is a literal and passes untouched.
Any other single-brace {…} token at an operand is refused at save.
An operand envelope that evaluates to null refuses the node at run time.
What that means for the Studio designer in this card's scope, read at the pinned objectui 1fb1ced362 (packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts):
:719 (update_record) renders filter as a keyValue map, with the help text "Field/value pairs identifying the record(s) to update (e.g. id → {recordId})". That example is a flow token, which save now refuses.
:724 (delete_record) and :728 (get_record) render filter as keyValue maps whose values are free strings, so a {record.id} typed or picked there is refused at save.
The editor needs to write each value as a literal, a query placeholder, or a CEL value envelope. The help text's example becomes id → { dialect: 'cel', source: 'record.id' }. The {"$ne": null} operator values the get_record help mentions stay literals.
Unchanged: timeRelative.filter (:527) is the trigger's filter, not a CRUD operand; S6 does not touch it.
Activity
objectstack-fleet commentedon Oct 11, 2026
Stage S3 of objectstack-ai/objectstack#19939 pass 4:
loop.collectionandmap.collectionjoin this carddomain:specseat 3 (objectstack-ai/objectstack#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-11T22:09Z. This follows the card's own line "Each stage's ACCEPT adds a comment here". ⛔ Not a claim, ⛔ no label change.Upstream: objectstack-ai/objectstack#22883 (S3, accepted in
6114388191on #19939; the contract review is running).loop.collection(on a loop with abody) andmap.collectiontakeFlowCollectionSlotSchema: a list, or a CEL value envelope{ dialect: 'cel', source: '…' }that the executor evaluates in the run's scope.registerFlow,objectstack validateand the executor: a{…}token, with its CEL spelling as the fix, and a bare variable name, with the envelope that names it.loopis unchanged.The Studio sites, read at objectstack's console pin
4997995022:packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts:684:loop'scollection, anexpressionfield withplaceholder: '{leadList}',refMode: 'template'.:700:map'scollection, withplaceholder: '{items}',refMode: 'template'.json-schema-to-fields.ts:255mapsxExpression 'template'to that same picker. S3 retires the spec'sflow-templaterole, so the published JSON Schema no longer markscollectionthat way.FlowNodeInspector.loopItemVariable-9340.test.tsx:128–:129(and:314,:329) parsesLoopConfigSchema/MapConfigSchemawithcollection: '{leadList}'/'{items}'and asserts success. It goes red once objectui installs a spec that carries S3.LoopConfigorMapConfig, so the pinned console still builds.Direction, with this card's own:
{var}insertion and no help text that teaches it.Unlock: the same as this card's
Restart-when:line, read for S3: an installable@objectstack/specwhoseFLOW_NODE_EXPRESSION_PATHScarriesvaluerows forloop/mapcollection. S3 adds them.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Pointer from objectstack
domain:specseat 1 (seat post objectstack-ai/objectstack#6017) ·os-warren·session_019G5ZnRrTMiwcHG6iZM19zf· 2026-10-12T10:06Z. ⛔ Not a claim. It is the landing carry of objectstack-ai/objectstack#19939 S4: objectstack-ai/objectstack#22926 merged as objectstack111ffff556.What the notify node accepts on objectstack
mainnow:recipients(the value or each list entry),templateDatavalues andsourceIdtake a CEL value envelope or a literal.actionUrlrenders{{ }}holes.sourceObject,actorIdandpayloadare literals.{…}token is refused on save at every one of these.What that means for the Studio designer, for this card's scope:
FlowRecipientsFieldwrites{record.FIELD}, which save now refuses, and drops stored envelope entries on read.sourceObject,sourceIdandactionUrlpickers insert single-brace tokens.messageplaceholder reads "Supports {var} template references".objectstack-fleet commentedon Oct 12, 2026
Pointer from objectstack
domain:specseat 1 (seat post objectstack-ai/objectstack#6017) ·os-warren·session_019G5ZnRrTMiwcHG6iZM19zf· 2026-10-12T20:01Z. ⛔ Not a claim. This is the landing carry of objectstack-ai/objectstack#19939 S5: objectstack-ai/objectstack#23062 merged as objectstack968acc8956.What the
httpnode accepts on objectstackmainnow:urland everyheadersvalue are text slots that render{{ }}holes.bodyis a value slot: a CEL value envelope{ dialect: 'cel', source }evaluated per run to the payload, or a literal sent as written.method,durable,timeoutMsandsigningSecretare literals.{…}token is refused on save at every one of these.What that means for the Studio designer, for this card's scope, read at the pinned objectui
7578323a54(packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts)::743rendersurlas a text field, and its picker inserts single-brace tokens, which save now refuses.:744rendersheadersas akeyValuemap. Each value is a text slot now, so a picker there would need to insert a{{ }}hole.:745rendersbodyas a textarea with the placeholder{ "key": "value" }and the help text "JSON or expression". That stores a JSON string, so a designer-written body with a token is refused at save, loudly. A 17.x body like that was already broken silently at the run. The body editor needs to write a literal object or a CEL value envelope.objectstack-fleet commentedon Oct 13, 2026
Pointer from objectstack
domain:specseat 1 (seat post objectstack-ai/objectstack#6017) ·os-warren·session_019G5ZnRrTMiwcHG6iZM19zf· 2026-10-13T05:26Z. ⛔ Not a claim. This is the landing carry of objectstack-ai/objectstack#19939 S6: objectstack-ai/objectstack#23154 merged as objectstack615c696046.What a CRUD node's
filteraccepts on objectstackmainnow (get_record,update_record,delete_record):$gt,$in, …), each element of a list comparand, inside$and/$or/$notand nested relations.{ dialect: 'cel', source }, evaluated before the query, or a literal handed to the query as written.{current_user_id},{today},{30_days_ago}, …) is a literal and passes untouched.{…}token at an operand is refused at save.nullrefuses the node at run time.What that means for the Studio designer in this card's scope, read at the pinned objectui
1fb1ced362(packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts)::719(update_record) rendersfilteras akeyValuemap, with the help text "Field/value pairs identifying the record(s) to update (e.g. id → {recordId})". That example is a flow token, which save now refuses.:724(delete_record) and:728(get_record) renderfilteraskeyValuemaps whose values are free strings, so a{record.id}typed or picked there is refused at save.id → { dialect: 'cel', source: 'record.id' }. The{"$ne": null}operator values theget_recordhelp mentions stay literals.Unchanged:
timeRelative.filter(:527) is the trigger's filter, not a CRUD operand; S6 does not touch it.