fix(ui): stop overriding Astryx's chat bubble radius - #3452
Conversation
`ChatMessageBubble` resolves `border-radius: var(--radius-chat)` (28px), the same token `ChatComposer` reads through `--_chat-composer-radius`. Bubble and composer are designed to round together as one conversation surface. The product diverged from that twice. `density="compact"` on both `ChatMessageList` instances swapped the bubble's radius for `var(--radius-container)` (12px), and `.maka-chat-message-bubble-user` then pushed the filled bubble down to `var(--radius-surface)` (10px). The composer was never overridden, so it kept rendering at 28px — a transcript and a dock on the same surface differing by nearly 3x. Remove both overrides rather than introduce a third value. 28px is what the primitive picks on its own once the product stops arguing with it. Dropping `density="compact"` also moves `ChatMessage`'s children gap from 2px to 4px, which is the tier's own spacing and comes bundled with it. Bubble padding is unaffected: Astryx's `paddingCompact` and `paddingBalanced` resolve to the same StyleX atoms. DESIGN.md §6 moves in the same commit so the document does not contradict the code: chat bubbles leave the 10px card row, a 28px chat rung records what `--radius-chat` governs, and the Two-Name Rule no longer claims that no product consumer renders at 28px. Generated-by: Claude Code
jackwener
left a comment
There was a problem hiding this comment.
Automated review of exact head 1a99e766ef824bc69d0f5a2548df6257c7cc1084 against current main@d62857a8357e9160926726a2a13096bc2dc2b91d.
The defect remains on main: both ChatMessageList call sites force compact, which activates Astryx's compact bubble radius, and product CSS then overrides the filled user bubble again to 10px while the composer independently stays on --radius-chat (28px). The patch removes both competing product decisions and lets the shared primitive/token own the shape; the measured padding result also confirms this is not compensating with a new value. I found no actionable P0-P2 defect. Required test is green and the PR includes before/after visual evidence.
Required conclusions:
- Optimal for the actual problem: yes; deleting the two overrides restores the existing Astryx source of truth.
- Production code to delete: the PR already deletes the unnecessary
density="compact"props and product radius override; none further identified. - Tests to delete/replace: none identified.
- Deeper refactor: no.
- Ready to merge: code-wise yes, but this automated review is not approval; the visual/design-policy change still needs independent human review.
- Residual risks/gaps: no automated computed-style regression protects the 28px pairing, so the supplied visual evidence and a human check are the current guard; future Astryx changes could move the default.
This affects user-visible layout and DESIGN.md policy, so CONTRIBUTING.md requires independent human judgment on the exact head.
Summary
The bubble and the composer are designed to share one radius token.
ChatMessageBubbledefaults tovar(--radius-chat)(28px);ChatComposerreads the same token via--_chat-composer-radius. The product overrode the bubble twice —density="compact"dropped it to 12px, then.maka-chat-message-bubble-userpushed it to 10px — and left the composer alone.Full view, light (top) then dark (bottom). Story
product-shell-official-appshell--native-conversation, 1180×788 @2x, scrolled to top.Corner zoom on the bubble/dock join, light (top) then dark (bottom). Same story and conditions. The AFTER bubble sits ~32px lower: the balanced tier lengthens the transcript.
Three deletions, no new value. 28px is what the component picks on its own once both overrides are gone.
densityis a spacing tier, so dropping it also movesChatMessage's children gap 2px → 4px and the transcript reads looser — bundled with the tier, intended. Bubble padding is not affected: Astryx'spaddingCompactandpaddingBalancedresolve to the same StyleX atoms.DESIGN.md§6 moves in the same commit because it contradicted the change: chat bubbles leave the 10px card row, a 28px chat rung records what--radius-chatgoverns, and the Two-Name Rule no longer claims nothing in the product renders at 28px —ChatComposeralready did, onmain.Refs #3446 — same root as its F1 finding, separate intent, none of its other work folded in.
Verification
Playwright computed-style sweep against a live Storybook dev server, before and after, same branch and same server. Page pinned,
scrollTop0, identical framing. Light and dark — identical results in both.10px28px12px28px(ghost, transparent)12px 16px12px 16px28px 28px 0 028px 28px 0 0compactbalancedFull-page sweep of every visible element's radius, font-size/line-height, colour and gap. Everything that moved is accounted for, nothing else:
10px×35→32,12px×3→1,28px×1→6 — distinct radii stay at 10, no new value in the ladder2px×11→5,4px×22→27 —ChatMessage'schildrenGap, the tier's own spacingcompactrenamed tobalanced; the four that leave are the last message's tail, pushed below the fold asscrollHeightgrows 1473→1505pxdensity="compact"on<Markdown>(chat-turn.tsx:1107) is left alone — a different density axis with its own[data-density="compact"]contract.Ran:
npm run format(no fixes),@maka/uitsc build (clean), focused testschat-turn-answer-identity/chat-turn-steering-order/chat-conversation-items/transcript-projection(23 pass, 0 fail). Not run: repo-wide suite (CI), desktop Storybook visual smoke.Review focus
packages/ui/src/chat-surface-layout.tsx:35sayschat-surface-layout.test.tsxholds the balanced density value. That file does not exist in the repo — theChatLayoutdensity default is currently unguarded. Out of scope here, worth a follow-up.DESIGN.md §6 is a deliberate revision of the design authority, written as a rule rather than an exception. Please review that wording as policy.
AI use
Tool(s) and scope: Claude Code — the deletions, the DESIGN.md §6 revision, the CSS comment rewrite, the Playwright measurement harness, and this body. Every number above comes from that harness against a live server, not from reasoning about the cascade. Commit carries a
Generated-by: Claude Codetrailer.Checklist
Does this PR entail a change in behavior?