Skip to content

finding(plugin-chatbot): chatbot-floating spreads the whole authored node raw and LAST onto its panel — three undeclared keys are live, the authored messages seed overrides the runtime messages (a sent message never renders), and node keys land as DOM attributes #7708

Description

@os-sam

Measured by the domain:ui dev seat during the remediation of objectui#7655 (PR #7705, branch claude/issue-7655-chatbot-registration-authoring-types), after the contract review of that PR (comment 5550439212 on the PR) measured it first. Filed unassigned, ungraded — triage owns routing. Not fixed there: #7705 declares authoring faces and moves no render outcome; fencing this channel is a behaviour change with its own review (below), and declaring the keys would fossilise an accident as contract.

The fact

packages/plugin-chatbot/src/renderer.tsx registers three components. The chatbot and chatbot-enhanced registrations open their rendered element with {...toDomProps(props)} — FIRST, whitelist-filtered — and then write their named props. The chatbot-floating registration does the opposite: it writes its named props onto the FloatingChatbot element and then ends with a raw {...props} spread, LAST. FloatingChatbot forwards the rest of its props (...chatbotProps) onto the panel's ChatbotEnhanced, which spreads its own leftover props onto its root div.

SchemaRenderer (packages/react/src/SchemaRenderer.tsx) strips sixteen metadata keys from the evaluated node and spreads EVERY other authored key as a prop to the registration, then disabled, className, data-obj-id, data-obj-type and the host's own props. So on a chatbot-floating node the whole authored node reaches the panel unfiltered, after the registration's own props. Three consequences, all base-identical (the PR's only edit in that hunk is the disabled line):

  1. Three keys ChatbotFloatingSchema does not declare are live. processVisibility, surface and showAvatars reach the panel's ChatbotEnhanced and change what renders. The named-read census (schema.KEY inside the registration body) correctly reads 0 / 0 / 0 for them on this registration — the instrument counts named reads and cannot see this channel.
  2. The authored messages seed overrides messages={runtimeMessages}. The registration writes the live runtime messages, then the raw spread writes the authored messages array over them. Through the real host, after sending a message on a floating node NEITHER the user message nor the auto-reply renders; the identical send on chatbot-enhanced renders both. A floating chat cannot show anything the user types.
  3. Node keys land as DOM attributes inside the panel. displayMode, systemPrompt and model reach the panel root as attributes (React passes unknown string-valued props through), 1 / 1 / 1 on floating, 0 / 0 / 0 on chatbot-enhanced — the DOM-leak class objectui#4425 describes, on the one registration in this plugin that never closed it.

How it was measured

Through the real SchemaRenderer host (SchemaRendererProvider + SchemaRenderer, the node typed plugin-chatbot:chatbot-floating with floatingConfig.defaultOpen: true, the portal queried on document.body), with a lit/dark pair per key and chatbot-enhanced — whose spread is toDomProps-filtered — as the control. Identical readings on origin/main at 8ad218d58 and on the PR head:

probe chatbot-floating lit / dark chatbot-enhanced lit / dark
showAvatars: true → per-message avatar element 1 / 0 0 / 0 (never forwarded by name; filtered by the whitelist)
surface: 'plain'.max-w-2xl wrappers 2 / 0 2 / 0 (read by name on enhanced — the lit control)
processVisibility: 'debug' → raw tool name shown for a tool result shown / hidden shown / hidden (read by name — lit control)
send ping-user with autoResponse reply pong-reply user NOT shown, reply NOT shown, seed shown both shown, seed shown
displayMode / systemPrompt / model as attributes in the panel 1 / 1 / 1 0 / 0 / 0

Mechanism pinned on the whitelist itself: toDomProps({ showAvatars, surface, processVisibility, className }) keeps className and drops the other three. The three "live keys" readings are pinned as a TRIPWIRE in packages/plugin-chatbot/src/__tests__/renderer.authoring-faces-7655.test.tsx by PR #7705 — a measurement, not a contract, and whichever option below lands flips those pins deliberately. The messages override and the attribute leak are NOT pinned there: pinning a bug as expected behaviour is the wrong shape; the fix owns their tests.

One probe artefact worth recording so nobody re-measures it wrong: a data-trace-id link is NOT a usable processVisibility marker on chatbot-enhanced, because useObjectChat's normalizeMessages rebuilds every seed message with a fixed key set and drops traceId; on floating the raw seed survives (consequence 2 again), so the link appears there and not on the control. The raw-tool-name marker rides toolInvocations, which normalisation keeps, and lights on both.

Why it is worth a card

Consequence 2 is user-visible on every floating chatbot: what the user types never appears in the panel. Consequence 1 makes the published type lie by omission in the opposite direction from objectui#7703 — ChatbotFloatingSchema (PR #7705) declares what the registration reads by name, and the face's docblock says so; an author who reads that showAvatars is not a member of the floating face will still see avatars if they author it. Consequence 3 is objectui#4425's class.

Two options, with costs — not picked here

  • Fence the spread like the two siblings: move it to the head of the element as {...toDomProps(props)}. Closes all three consequences at once and gives the registration one carrier per question. It is a behaviour change on a shipped registration — the three keys go dark on floating nodes (any document authoring them there loses the effect), the panel starts showing sent messages, attributes stop leaking — so @object-ui/plugin-chatbot ships minor with the semantics spelled out, and it needs its own contract review at tier. The three tripwire pins in feat(types): one named authoring-face type per chatbot registration — ChatbotEnhancedSchema and ChatbotFloatingSchema (objectui#7655) #7705's test flip to "dark".
  • Declare the three keys on ChatbotFloatingSchema (with Zod arms on its twin) and keep the spread. Makes the face honest about what reaches the panel today, but fossilises an accidental channel as contract (AGENTS.md #0.1: the fix belongs at the seam that is wrong, not in a declaration that ratifies it), leaves consequences 2 and 3 untouched — the messages override still needs the spread reordered or filtered, so this option cannot stand alone — and every future ChatbotEnhanced prop becomes a silent new member of the floating face.

Whichever is ruled, showAvatars on objectui#7703's list is affected: that card's "read by no registration" is false for this key on this registration through this channel (recorded on #7703).

Not a duplicate

Dedup ran against the repo-scoped open-issue list via REST (384 open issues, PRs excluded) with a lit positive control — chatbot-floating returns objectui#7704, #7703, #7655 and #7654 — so these are readings: toDomProps returns #4425, #6349 and #7444; FloatingChatbot returns #7654 and #2443; runtimeMessages returns #7295 only (per-message avatar keys); "DOM attribute" near "chatbot" returns nothing. objectui#4425 is the adjacent CLASS card — the toDomProps whitelist stopping at packages/fields, with plugin-chatbot listed as "a candidate to measure, not asserted as a defect"; this card is that measurement for one registration, and its sharpest consequence (the messages override) is functional, not a DOM leak. #7654 (displayMode, ruled retired) and #7703 (six unread ChatbotSchema keys) are the neighbouring key-level cards; neither names the spread.

Refs: objectui#7655 (PR #7705) · objectui#4425 · objectui#7703 · objectui#7654 · objectui#7295.

Filed by the domain:ui dev seat, session session_01KbJQ1y1J12nZxYzFWhP8Q3.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingplugin: chatbotpm:queuepriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions