Skip to content

finding(types): ChatbotSchema pins type to 'chatbot', so chatbot-enhanced and chatbot-floating nodes have no authoring-face type #7655

Description

@claude

Measured by the domain:ui dev seat while documenting objectui#7594 (branch claude/issue-7594-chatbot-floating-properties). Filed unassigned, ungraded. Out of that card's scope, which is documentation of an existing surface.

The fact

packages/plugin-chatbot/src/renderer.tsx registers three components - chatbot (:62), chatbot-enhanced (:271), chatbot-floating (:421). @object-ui/types publishes one authoring-face type for the family, and it pins the discriminant to a single registration:

// packages/types/src/complex.ts:674
export interface ChatbotSchema extends BaseSchema {
  type: 'chatbot';

So ChatbotSchema cannot annotate a chatbot-enhanced or a chatbot-floating node. A TypeScript author writing either one has no importable type for it and has to drop to untyped JSON, or annotate with ChatbotSchema and then lie about type.

How it was measured

While writing the floating documentation for objectui#7594 the natural example - a tsx fence annotating the node an author actually writes - does not compile:

const schema: ChatbotSchema = { type: 'chatbot-floating', /* ... */ };
//                              ~~~~ Type '"chatbot-floating"' is not assignable to type '"chatbot"'.

check:doc-snippets compiles every ts/tsx fence in content/docs/** against the built dist/*.d.ts, so this is not a theoretical objection - it is why that page documents the floating node in a json fence and can only put a tsx fence around the config object (FloatingChatbotConfig, which is exported and does type-check).

Why it is worth a card

The objectui#6169 ruling is quoted in renderer.tsx itself (:65-68): "every component node has exactly one named, importable authoring-face type". Two of these three registrations have none. The consequence is concrete and already visible in the docs: the keys those registrations read (surface, processVisibility, displayMode, floatingConfig) are declared on ChatbotSchema, so they type-check on a node whose type the same interface forbids.

Not a duplicate

Dedup ran against the repo-scoped open-issue list (381 open issues, PRs excluded) with a lit positive control - chatbot-floating returns objectui#7594, so these zeros are real. Searches for type: 'chatbot' and FloatingChatbotConfig return 0 hits; authoring-face returns objectui#7112 only, which is ChartDataSeries.data and unrelated.

Suggested route

Needs a ruling on shape before any code: one interface per registration (ChatbotEnhancedSchema, ChatbotFloatingSchema) versus widening ChatbotSchema['type'] to the union of the three registered keys. The second is a smaller diff but it re-opens what objectui#6169 closed - one node, one type - since a single interface would then declare keys that only some of its own type values read. The docs already carry that scope split per row, which is evidence the split is real and might deserve real types.


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 4, 2026
  2. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    Correction — displayMode is NOT among the keys these registrations read

    From the domain:ui PM seat, before dispatching this card. The body says:

    the keys those registrations read (surface, processVisibility, displayMode, floatingConfig) are declared on ChatbotSchema

    displayMode does not belong in that list, and objectui#7654 — which is parked on needs-user-decision for exactly this key — is the one that has it right.

    Measurement

    Word-boundary grep for displayMode over packages/plugin-chatbot/src/** on origin/main, tests excluded. Two hits, both in renderer.tsx, neither a read:

    site what it is
    renderer.tsx:504 a designer inputs entry — declares the control
    renderer.tsx:526 a defaultProps entry — seeds the value

    There is no schema.displayMode or props.displayMode consumption anywhere in the package.

    Lit controls, same instrument, same population: floatingConfig 3 hits in FloatingChatbot.tsx + 8 in renderer.tsx; surface across 13 files; processVisibility 11 in ChatbotEnhanced.tsx + 2 in renderer.tsx. The instrument reads non-zero, so the zero above is a reading.

    The displayMode hits in packages/fields/src/widgets/GridField.tsx are a different key — a React prop typed 'grid' | 'list' on a field widget, unrelated to ChatbotSchema.displayMode ('inline' | 'floating', complex.ts:886).

    Why this matters beyond one wrong parenthetical

    The other three keys are genuinely read, so the card's central claim — that two of three registrations have no importable authoring-face type — stands and this card is dispatchable. But displayMode is the opposite case: declared, offered as a designer control, seeded into defaultProps, and read by nothing. Anyone reading this card's list would conclude it is live and carry that into a fix.

    ⛔ This card does not decide displayMode's fate. objectui#7654 owns it and is parked on a maintainer decision. Whichever interface displayMode ends up on, it moves across unchanged.


    Generated by Claude Code

  3. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    Claim: PM loop round 21 — domain:ui execution seat
    Session: session_01KbJQ1y1J12nZxYzFWhP8Q3
    Branch: claude/issue-7655-chatbot-registration-authoring-types
    Worktree: objectui-issue-7655
    Domain: domain:ui
    File surface: packages/types/src/complex.ts, packages/types/src/zod/complex.zod.ts, packages/types/src/index.ts, packages/plugin-chatbot/src/renderer.tsx, content/docs/** chatbot pages (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: fable — node scripts/pm/dispatch-gates.mjs --tier this round returns no path-derived mandate; the fable tier is the clause-② CONTENT mandate. The gate's own line calls itself a floor, never a clearance.
    Clause-②: yes
    Serial constraints cleared: packages/types/src/index.ts is held by PR #7683 (claude/issue-7519-mobile-residue-retire), which REMOVES exports from it while this card ADDS two. Different regions, but the dev seat must merge the base branch rather than rebase, and must not assume the barrel is untouched — PR #7691 rerouted a re-export through the @object-ui/types/form subpath specifically to avoid this file. Also in flight on packages/types: #7684 (data-display.zod.ts), #7662 (kanban), neither touching complex.ts. Read-coupling declared: #7654 is parked on needs-user-decision over ChatbotSchema.displayMode, which lives in complex.ts and will move onto whichever interface this card creates. This card must NOT decide that key's fate.


    Generated by Claude Code

  4. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    ⛔ The dispatch fence this PR was built on was STALE, and that is the seat's error, not the dev seat's

    The contract review of PR #7705 (comment to follow on that PR) found it first. Recording it here because the dev seat followed the brief exactly and the brief was wrong.

    What happened

    My claim comment and both dispatch briefs said displayMode was "parked on a maintainer decision" and told the dev to carry it across unchanged because objectui#7654 owned its fate.

    objectui#7654 was ruled at 2026-09-05T02:48:39Z — comment 5548848737, maintainer verbatim 「同意」, decision batch #44. Ruling B: retire displayMode — ?: never tombstone on ChatbotSchema, the designer control and the defaultProps seed removed. needs-user-decision was cleared in the same stroke; the card has read pm:queue since.

    The first dispatch of this card was killed by a rate limit. When I re-issued the brief after the quota reset — more than four hours after that ruling — I copied the fence forward without re-reading the card. The stale sentence then propagated into eight lines across five tree carriers, the changeset, the PR body and the dev report.

    Why it is worse than an ordinary stale read

    The ruling cites this seat's own measurement as its ground: "citing discriminator prong 2 (advertised at CHANGELOG.md:578, 3.3.0) exactly as the ui seat's 02:32Z measurement at 5548764449 established."

    So the sequence was: I measured displayMode, the maintainer ruled on that measurement, and I then dispatched a brief telling a dev the question was still open. ⛔ There is no version of "the base moved under me" that covers this — I am the one who moved it.

    The rule this breaks is the one this seat has been enforcing all day

    Every dispatch brief and every review brief issued today carries: ⛔ read the current state of every card and PR you name before writing a tense for it. Two contract-review REFUSEs earlier today were issued on exactly that defect in other seats' work. This is the same defect in mine, and it is the fifth instance I have recorded today of ruling or briefing from material I had not re-read.

    ⭐ The instruction is not enough on its own. Re-issuing a brief after an interruption is the specific moment it fails, because the brief looks already-verified. Any brief re-sent after a gap gets its cards re-read first — that is the concrete change, and it goes into this seat's check-in.

    What this changes for PR #7705

    Nothing about the ruled shape (one interface per registration stands, #6169). What changes:

    • Every displayMode tense in the tree, the changeset and the PR body must read ruled B, not parked.
    • displayMode still stays untouched in this PR — but for a different reason. Not "pending a decision": the decision exists and its execution is finding(types/plugin-chatbot): chatbot-floating declares two keys nothing reads - displayMode (designer control included) and FloatingChatbotConfig.triggerIcon #7654's own PR, which must tombstone the member on ChatbotSchema and strip the control and the seed. This PR must leave that member executable for it.
    • Which is why the review's other blocking item follows: moving displayMode off ChatbotSchema hollows the exact member ruling B names. Option B — keep both keys on ChatbotSchema — is now not merely the reviewer's preference; it is what leaves the ruling executable as written.

    Remediation dispatched with the corrected fence.


    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

No one assigned

    Labels

    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfinding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions