A design-delta note measured the conversation variant against berd's shipping
chat surface and named three divergences that made the focus view read as "not
berd" regardless of how the rest was arranged. This takes all three literally,
on Buzz tokens rather than berd's.
**Agent identity row.** The largest gap: agent prose carried no attribution at
all, so a reply read as unowned body text in a full-cover view. berd labels
every agent turn with a 20px round avatar plus the name at `text-xs`. Added for
the `conversation` variant only — a test asserts the row does not leak into the
other variants, so a failure names the cause instead of printing a markup diff.
**Prompt bubble.** berd's user turn is a soft fill with no border, `px-4 py-2`,
12px radius. berd's `rounded-sm` is 12px on its own scale, not Tailwind's stock
2px, so Buzz's `rounded-xl` is the exact equivalent. The cap moves from
`max-w-[85%]` to a fixed 640px measure mirroring `--chat-user-message-max-width`:
a percentage cap re-wraps the prompt on every resize of the cover, a fixed
measure holds one stable line length.
**Fenced code.** The language moves into a real header row above the frame with
the copy action opposite it, framed at Buzz's `rounded-lg` (`--radius: 0.625rem`,
exactly berd's value).
The markdown renderer is shared with channel messages, so the code recipe is
opt-in through `CodeBlockVariantContext` read at render time. A prop would have
to thread through `createMarkdownComponents`, whose component map must stay
module-stable and whose parsed-node cache keys on a variant string — the same
reason `VideoReviewMarkdownContext` already exists. A context provider renders
no DOM, so `default`/`compactPreview` markup stays byte-identical.
Three defects fixed on top of the restyle, each found by review or a bug pass:
- The code-recipe provider was mounted inside `MessageActivity`, which only
handles assistant items — `UserMessageBubble` returns before it, so a fence
inside a human prompt kept the legacy 16px muted frame nested inside the new
12px bubble. The recipe is a property of the *surface*, not of a role, so the
provider moves up to `AgentSessionTranscriptList`.
- The identity row read the raw `agentAvatarUrl`/`agentName` props, and the
primary channel-opened flow passes `agentAvatarUrl: null` because
`ChannelAgentSessionAgent` carries no avatar field — so every channel-opened
focus session showed initials in the identity row while the header directly
above it showed the real profile avatar. Now resolved profile-first out of the
`profiles` lookup the panel already hands down, with the props kept as
fallback: a locally managed agent can hold an avatar its relay profile never
published.
- `UserAvatar` names itself (`<img alt="${displayName} avatar">` or its
fallback initials) and the identity row puts the same name in visible text
right after it, so assistive tech read the identity twice for every agent
turn. The avatar is wrapped `aria-hidden`, verified in Chromium's real
accessibility tree over CDP (`ignoredReasons: ["ariaHiddenSubtree"]`), not
from DOM attributes. Marked at this call site rather than teaching the shared
`UserAvatar` a decorative mode, which would affect all 45 of its call sites.
The conversation test file had reached 1253 lines, past the 1000-line ceiling.
It slipped the `file-size-check` gate because that script only scans
`.ts`/`.tsx` under `src/features` — the rule in AGENTS.md plainly covers it.
Split into a shared non-test harness module (following the existing
`observedUnreadTestHarness.mjs` precedent, because duplicating the
order-sensitive TZ/locale pins into two files is exactly how they drift) plus
two test files, bodies moved verbatim.
AGENTS.md gains the `assert.ok(x === null)` rule earned here: the
`assert.equal(el, null)` form serializes the matched element and its entire
subtree to build a diff when it fails, which on a real transcript exhausts
memory and kills the runner with SIGKILL after ~100s — a genuine regression
becomes unreadable and looks like an OOM in unrelated code.
Squashed from ss-dev-01/berd-restyle (#6720) at fd2e01799.
Co-authored-by: ss-dev-01 <11939edb7df583f855dbef923f2358f1184538f88ca452e19e7e35e42ad6d796@buzz.block.builderlab.xyz>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>