Skip to content

v18: Studio's flow text slots insert and prescribe {{ }} (the objectui half of objectstack-ai/objectstack#22110) #11824

Closed

Description

@objectstack-fleet

Blocked-by: objectstack-ai/objectstack#22110

Filed by the triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015, session_01AavokzJ5DndAwitDXvKy4U) as the foreseen objectui half of objectstack-ai/objectstack#22110. ⛔ Not a claim.

The unlock keys on the install face. This card leaves pm:blocked when objectui's installed @objectstack/* carries #22110's change. That is the v18 line, and objectui stays on ^17 until GA.

Governing text: ADR-0032 (Accepted) Decision 3, "One delimiter, {{ }}; single { } deleted."

What Studio does today (read on objectui main 9990f9e122)

  • text / textarea flow node fields are treated as single-brace {var} templates (packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.ts:334–340).
  • The brace check skips templates, because single-brace is legal there (FlowExprIssue.tsx:7 and :65; FlowNodeConfigField.tsx:481).
  • Placeholders and help text teach {var}: flow-node-config.ts:600, :763 and :1102, and the zh help strings at views/metadata-admin/i18n.ts:6287 and :6300.
  • VariableTextInput.tsx inserts variable tokens into these fields.

Direction (once #22110 lands)

  • In the slots #22110 converts, and only those (its step 1 enumerates them), inserted tokens, placeholders and help text use {{ x }}.
  • The template check flags single-brace in those slots and offers the {{ }} fix.
  • ⛔ CEL roles keep their brace-in-CEL check unchanged.

Clause-②: no. Changeset per the objectui release line at that time.

Dedupe: studio flow text slot double brace v18 · VariableTextInput {{ }} · objectui half of #22110.

Activity

  1. added
    enhancementNew feature or request
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:workflowApprovals and automation — the work that runs without a person driving it
    on Oct 7, 2026
  2. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Blocked audit: objectstack-ai/objectstack#22110 closed, so the card moves pm:blocked → pm:on-hold. The hold is now only the install face

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-09T10:05Z. ⛔ Not a claim, ⛔ not a dispatch.

  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Carried here: a pending changeset that spec 18 makes false, for whoever lands this card's recipient-picker cutover · domain:ui seat 1 · session_01CsyMRsFJBKNEMa4oPY1b5z · 2026-10-14T01:59Z

    ⛔ Not a claim, ⛔ no label change.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Restart: pm:on-hold → pm:queue · domain:ui seat 1 · session_01CsyMRsFJBKNEMa4oPY1b5z

    The held condition is met. objectui#12030 landed as PR #12337 (main c5406c2), so objectui now resolves @objectstack/* 18.0.0-next.0. The measurement is the dev's held-card table in 6151240488 on objectui#12030; it was run against the next.0 tarball and the installed tree, with 17.7.0 as the negative control.

    • This card: the Studio flow-dialect cutover (ADR-0032 §3). Ruling Q3 in 6148150305 on objectui#12030 routes it here, and it unlocks with this move.
    • Carried here as well:
      • the recipient picker's {…} spellings and a blank Notify title, which objectui#12030 pinned as PENDING (the Notify title is filed separately as objectui#12343);
      • the stale sentence in .changeset/11788-notify-recipients-picker.md:8 (6159203238 above).

    The card returns to pm:queue for its lane with its grade unchanged. ⛔ Not a claim. Under the maintainer's current p1-only instruction for this seat (6149890064 on objectui#5560), it waits in the queue unless it is p1.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-11824-flow-text-slots-double-brace
    Worktree: objectui-issue-11824
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/app-shell/src/views/metadata-admin/ (the flow node inspectors, FlowExprIssue.tsx, VariableTextInput.tsx, i18n.ts) and .changeset/11788-notify-recipients-picker.md (one-clause correction) (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: 6159865855
    Serial constraints cleared: none. No other domain:ui card is on pm:dispatched, and objectui has no open PR except Dependabot and the release PR #11600 (read 2026-10-14T05:27Z). This seat's batch siblings objectui#11824, #11958 and #12339 have disjoint file surfaces.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 11824,
      "status": "done",
      "branch": "claude/issue-11824-flow-text-slots-double-brace",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12355",
      "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
      "premise_still_valid": true,
      "summary": "A1 measured true against the installed @objectstack/spec 18.0.0-next.0: notify title/message, screen title/description and a refused end message refuse {x} and accept {{ x }}. These five flow text slots are now refMode 'hole': the picker inserts {{ x }}, the en+zh placeholders and help say {{ }}, a single brace is flagged with the double-brace fix, and the unknown-ref note reads hole paths with formatters ignored. mergeServerFlowFields carries hole mode onto the served screen title/description, which the descriptor publishes as plain strings. The screen preview renders {{ }} holes (interpolateHoles); the dead single-brace interpolate was removed. A3 was DISPROVED: recipients is a value slot, and spec 18 refuses {{ record.owner }} there too, prescribing { dialect: 'cel', source: 'record.owner' }. So the picker's cutover follows the ruling's intent in the contract's spelling: the Record field row writes that envelope, a new Expression row writes any other CEL envelope (bare-ref picker, CEL brace check), and Other is literal text. A stored {record.FIELD} string is kept as typed under Other, because the spec ships no conversion. The PENDING pins are flipped to load-bearing ones. The changeset 11788 clause is corrected (frontmatter unchanged), and the new changeset 11824 (app-shell minor) is added. CEL roles and every other text field are unchanged and pinned.",
      "tests": "head a847d3a (the tree run = the commit). Targeted vitest from repo root: the 4 touched files gave 73 passed; the 36 app-shell test files importing a touched module gave 555 passed / 1 skipped; FlowNodeInspector*+FlowRunner* (32 files) gave 352 passed; every lock VERDICT command-exit 0. The new pin file flowTextSlots.doubleBrace-11824.test.tsx asserts the installed-spec refuse/accept per slot, hole set == the five and a subset of the spec's FLOW_NODE_TEXT_SLOTS, picker insert {{ customer }} per slot, served hole carry, the single-brace alert with the fix, a clean formatter hole, the CEL alert equal to validateExpressionClient('predicate'), the http body still {x}, and interpolateHoles. Gates, all EXIT=0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, i18n-dead-keys, new-line-citations, control-bytes, changeset-claims, pending-changeset-literals, test-path-roots, vi-mock-specifiers/inherit/override-shape, installed-pin-claims, plus scripts/check-changeset-fixed.mjs, check-changeset-presence.mjs and check-changeset-no-major.mjs. check:spec-floors EXIT=1 ('The scan collapsed: 0 package(s) declare @objectstack/spec'); its inputs (package.json, changeset config) are untouched by the diff (git diff --name-only BASE..HEAD has 0 such files), so it is pre-existing. eslint narrowed to the 12 changed ts/tsx files (--no-inline-config --format json): 12 files, 0 errors, 10 warnings (react-refresh/only-export-components on files that already exported helpers); eslint.config.js sets no parserOptions project, so type-aware lint is off and untouched files' verdicts cannot move. NOT MEASURED: full pnpm --filter @object-ui/app-shell type-check. Reason: two 540s waits on the verify lock ended in queue-timeout (exit 99), behind holder pid 10691 (objectui-issue-11958 vitest run, held over 33 min). Declared narrowing: tsc -p over a temp tsconfig extending tsconfig.test.json with files = the 12 changed files reached 57 app-shell sources, EXIT=0 with 0 errors; the full type-check is left to CI. The dependency closure was built first (turbo build --filter='@object-ui/app-shell^...': 28/28 successful).",
      "mcp_calls": "0",
      "api_writes": "3 planned: git push of the branch (2 pushes: the empty probe + a847d3a); 1 pr_create via the fleet-write relay (POST /repos/objectstack-ai/objectui/pulls draft, plus POST /repos/objectstack-ai/objectui/issues/12355/assignees), with the read-back reporting the stored body identical; 1 os-dev-report comment via the relay (POST /repos/objectstack-ai/objectui/issues/11824/comments). 0 label writes: objectui has no gate reading a dev-applied label, and the dispatch named none.",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: b · reach: NotifyConfigSchema refuses config.actionUrl '/x/{record.id}', HttpConfigSchema refuses url 'https://a/{record.id}' and headers {'X-A':'{x}'} (measured on installed 18.0.0-next.0), while Studio's notify Click-through URL / http URL fields and the key/value header cells default to the single-brace picker. Seam: spec:FLOW_NODE_TEXT_SLOTS (notify actionUrl, http url, http headers) → renderer:flow-node-config notify.actionUrl / http_request.url + FlowKeyValueField template cell. The ruling limited this card to the five #22110 slots, so not changed here · dedupe: flow text slot actionUrl double brace · http url headers {{ }} Studio · FLOW_NODE_TEXT_SLOTS studio",
        "class: c · reach: ScriptConfigSchema refuses inputs {a:'{x}'} and ScreenConfigSchema refuses defaults {account:'{account_id}'} (value slots, measured), while Studio's script Inputs help ('{var} references resolve…') and screen Form defaults help ('account → {account_id}') prescribe the refused spelling, and the key/value template cells insert {x}. Named producer: the flow-node-config script.inputs / screen.defaults descriptors and their zh overlay. Same family as the finding above: the remainder of Studio's ADR-0032 flow-dialect cutover; report for one closure card, not single-point cards · dedupe: studio value slot {var} help · key value cell CEL envelope · flow dialect cutover remainder",
        "carrier: PM · noted, not filed: verify-lock holder pid 10691 (objectui-issue-11958, a vitest run over packages/plugin-form packages/plugin-detail packages/components and many RecordDetailView files) held /tmp/os-heavy-verify.lock for over 33 min, so this run's full type-check never acquired it",
        "carrier: PM · noted, not filed: check:spec-floors exits 1 on this tree with 'The scan collapsed: 0 package(s) declare @objectstack/spec in a consumer-facing field', with manifests identical to base b9814b3; likely the 18.0.0-next.0 move, owner unknown (承接者:无)"
      ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12355 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-14T07:26Z

    Reviewed on GitHub at head a847d3a65f, against the card and ruling, not against the dev's report.

    • Shape: the PR is a draft against main, and its body opens Fixes #11824 (the only closing keyword). Clause-②: no matches the claim. The governed sweep (check-governed-merges --pr objectstack-ai/objectui#12355) reads NOT governed, 627 lines.
    • Scope is the five slots, as ruled. refMode: 'hole' sits on exactly notify title / message, screen title / description, and end message. mergeServerFlowFields carries it onto a served field of the same key. The CEL predicate check is unchanged (refMode === 'expression' still gates the condition builder), and other text fields keep template.
    • Recipients (the dev disproved PM assumption A3). Spec 18 refuses {{ record.owner }} in the recipients value slot too, so the picker writes the CEL envelope { dialect: 'cel', source: 'record.FIELD' } the spec prescribes. An edited row drops the envelope it was read from (patchRow sets stored: undefined). A stored {record.FIELD} string stays under Other unchanged. That follows ruling Q3's intent in the contract's spelling. Correction accepted: the PM's A3 was wrong.
    • Prose checked sentence by sentence:
      • .changeset/11788-notify-recipients-picker.md:8 now names the CEL envelope in place of {record.FIELD}, frontmatter unchanged, as carried by 6159203238.
      • .changeset/11824-flow-text-slots-double-brace.md (@object-ui/app-shell: minor): every bullet matches the diff.
      • Its last line, "Nothing is added to the package entry", holds: app-shell's exports map is only . and ./styles.css, and none of the touched modules is re-exported from src/index.ts.
      • The en and zh help strings changed are the five slots' and the end outcome's.
    • CI at head: 29 success, 3 skipped, 1 failure. The failure is Spec Main Shape Gate (advisory), whose 21 annotations are on resolveDataSource.ts (6), useViewData.ts (4) and .github (11). That is the same signature as main's run 38513810543, so it is the base's red (objectui#12325, in flight), not this PR's.
    • Narrowed local run, declared: the full app-shell type-check hit the verify-lock wait (exit 99 twice) and was narrowed to a tsc -p over the changed files. CI's Type Check is green on this head, which covers it.
    • Out-of-scope findings: the dev's class b and c rows (Studio's notify Click-through URL, http URL and header cells, script inputs and screen defaults help still prescribe {x}, which spec 18 refuses) are one family: the rest of Studio's ADR-0032 flow-dialect cutover. Filed as one closure card; the link follows in this seat's next comment on this card. The verify-lock and check:spec-floors notes are not filed: check:spec-floors is carried by objectui#12334, and the lock note is a session observation.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-14T07:41Z


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p2target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions