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
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
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):
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.
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.
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.
Measured by the
domain:uidev seat during the remediation of objectui#7655 (PR #7705, branchclaude/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.tsxregisters three components. Thechatbotandchatbot-enhancedregistrations open their rendered element with{...toDomProps(props)}— FIRST, whitelist-filtered — and then write their named props. Thechatbot-floatingregistration does the opposite: it writes its named props onto theFloatingChatbotelement and then ends with a raw{...props}spread, LAST.FloatingChatbotforwards the rest of its props (...chatbotProps) onto the panel'sChatbotEnhanced, 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, thendisabled,className,data-obj-id,data-obj-typeand the host's own props. So on achatbot-floatingnode 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 thedisabledline):ChatbotFloatingSchemadoes not declare are live.processVisibility,surfaceandshowAvatarsreach the panel'sChatbotEnhancedand change what renders. The named-read census (schema.KEYinside the registration body) correctly reads 0 / 0 / 0 for them on this registration — the instrument counts named reads and cannot see this channel.messagesseed overridesmessages={runtimeMessages}. The registration writes the live runtime messages, then the raw spread writes the authoredmessagesarray 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 onchatbot-enhancedrenders both. A floating chat cannot show anything the user types.displayMode,systemPromptandmodelreach the panel root as attributes (React passes unknown string-valued props through), 1 / 1 / 1 on floating, 0 / 0 / 0 onchatbot-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
SchemaRendererhost (SchemaRendererProvider+SchemaRenderer, the node typedplugin-chatbot:chatbot-floatingwithfloatingConfig.defaultOpen: true, the portal queried ondocument.body), with a lit/dark pair per key andchatbot-enhanced— whose spread istoDomProps-filtered — as the control. Identical readings onorigin/mainat8ad218d58and on the PR head:chatbot-floatinglit / darkchatbot-enhancedlit / darkshowAvatars: true→ per-message avatar elementsurface: 'plain'→.max-w-2xlwrappersprocessVisibility: 'debug'→ raw tool name shown for a tool resultping-userwithautoResponsereplypong-replydisplayMode/systemPrompt/modelas attributes in the panelMechanism pinned on the whitelist itself:
toDomProps({ showAvatars, surface, processVisibility, className })keepsclassNameand drops the other three. The three "live keys" readings are pinned as a TRIPWIRE inpackages/plugin-chatbot/src/__tests__/renderer.authoring-faces-7655.test.tsxby PR #7705 — a measurement, not a contract, and whichever option below lands flips those pins deliberately. Themessagesoverride 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-idlink is NOT a usableprocessVisibilitymarker onchatbot-enhanced, becauseuseObjectChat'snormalizeMessagesrebuilds every seed message with a fixed key set and dropstraceId; on floating the raw seed survives (consequence 2 again), so the link appears there and not on the control. The raw-tool-name marker ridestoolInvocations, 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 thatshowAvatarsis 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
{...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-chatbotshipsminorwith 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".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 — themessagesoverride still needs the spread reordered or filtered, so this option cannot stand alone — and every futureChatbotEnhancedprop becomes a silent new member of the floating face.Whichever is ruled,
showAvatarson 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-floatingreturns objectui#7704, #7703, #7655 and #7654 — so these are readings:toDomPropsreturns #4425, #6349 and #7444;FloatingChatbotreturns #7654 and #2443;runtimeMessagesreturns #7295 only (per-message avatar keys); "DOM attribute" near "chatbot" returns nothing. objectui#4425 is the adjacent CLASS card — thetoDomPropswhitelist stopping atpackages/fields, withplugin-chatbotlisted as "a candidate to measure, not asserted as a defect"; this card is that measurement for one registration, and its sharpest consequence (themessagesoverride) is functional, not a DOM leak. #7654 (displayMode, ruled retired) and #7703 (six unreadChatbotSchemakeys) 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:uidev seat, sessionsession_01KbJQ1y1J12nZxYzFWhP8Q3.