Transcript: a turn's inbox notices and received lines are one "Received N messages" row

Merged
TE
3d ago
+764-31

Leo, 2026-11-02, on a turn that stacked "3 inbox threads ", "Received 2 messages" and "2 inbox threads ":

can't we simply just display most of these as recieved x messages and all of them get revealed then we can expand the messages

and on the opened row, whose messages sat about 24px in:

why bother indenting here

What changes

  • One row. Drawn rows that sit next to each other and carry delivered messages from other agents (inbox notices, inbox batches, received lines) become one inbox batch holding every message (laneNoticeBatches.ts receivedRun, in the display projection projectInboxRows). A lane report, a person's message, a waiting message, prose, a tool row or a footer ends the run. The incremental path reuses its rows only while each message keeps the same neighbours.
  • "Received N messages", where N counts messages, not threads. At rest the row shows no session names. Hovering it shows the senders' short names (the part after the last /) through the new hint prop on MessageGroupHead. A message run also counts an inbox notice's messages now, not its threads.
  • A run of received lines alone is no longer a message run (messageRuns.ts). It joins the "Received N messages" row, so a Claude turn no longer draws its own "Received 2 messages" line between two notices. Mixed runs ("Sent 2 messages, ran a command, received a message") fold as before.
  • Level 1. Opening the row shows every message as its own received line: the sender chip (which still opens the sender's chat, per the settled "Session link chip" design) and the first line. There's no indent: each mark sits in the shared icon column and each sender starts on the head's text column (LaneNoticeBatch.css). The row estimate measures those lines at full width (model.ts).
  • Level 2. Opening a message shows its whole text, as before.
  • The waiting group's inbox batches keep their old head text.

Spec: leo-workspace design/chat-transcript.md ("One icon column", "Session link chip", "One-line row pitch": the head is still the 22px one-line row).

Gallery

New entry agent-pane.received-messages (conversation/ReceivedMessages.gallery.ts), shaped like Leo's screenshot:

  • collapsed: one "Received 7 messages" row (closed)
  • level-1: the row opened, 7 un-indented message lines
  • level-2: the first message opened to its whole text

I updated the notes on the agent-pane.inbox-notice variants three and six to match the new head.

Tests

  • webviews/test/received-messages-fold.test.tsx (new, behavioural, written first). It reproduces the screenshot's rows through turnView and projectInboxRows for Claude and Codex and checks for one row holding all 7 messages. It also covers: a footer ending the run, two received lines with no notice gathering, a message run counting messages, and the rendered head ("Received 7 messages", no names, short names in its hover) opening to 7 lines and then to the whole text.
    • Red on base (origin/feat-cmux-next 91c750fb4cc plus this branch's test commit d181375a507): cd webviews && bun test test/received-messages-fold.test.tsx gave 0 pass, 7 fail (base drew laneNoticeBatch[3], messageRun[received 2], laneNoticeBatch[2] and "3 inbox threads" followed by every session name).
    • Green on this head, same command: 7 pass, 0 fail.
  • webviews/test/received-messages-columns-browser.test.ts (new, Chromium on the gallery). Each level-1 message's mark centre x equals the head's icon centre x within ±0.5px, and its sender starts at the head's text x within ±0.5px. It also checks the collapsed row's text and level 2.
  • Updated to the new behaviour: lane-notice-card.test.tsx (head text and hover), pendingMessages.test.ts (notices next to a direct message now project to one row; dedupe unchanged), transcript-spacing-table.test.ts (it finds the inbox row by "Received ").

Observed / Not run

  • Observed: the browser tests ran on the fleet (cmux-ci, Playwright) at 0659956d25df: received-messages-columns-browser, inbox-row-icon-column, transcript-spacing-table, transcript-row-pitch-browser and received-message-fold-browser, 61 pass, 0 fail. At level 1 each message's mark centres at x 28 and its sender starts at x 44, the same as the head's icon (28) and words (44).
  • Observed: the related unit suites pass locally at cda786f6dade, the final head (received-messages-fold, lane-notice-card, lane-notice-batches, pendingMessages, transcript-message-runs, transcript-received-messages and received-line, lane-report). bun run check passed with warnings only, and the prepush gate is clean.
  • Since that browser run, the review asked that a run of received lines holding a lane report or a task line keep its message-run fold, as on base. That change is covered by a unit test. The independent review is SHIP at cda786f6dade.
  • Not run: the full webviews suite; CI covers it. A wide fleet run of the acpmux folder is still going. A bare bun test over many files in one process gave 143 fails in unrelated files (StartedSessionCards, terminal attach, presence), which is the cross-file leak that run-webviews-tests.sh avoids by running one process per file.
  • Not run: a DEV build of the app.
  • Follow-ups from the review: a row that draws nothing between two received rows ends the run, and a lone line's open state resets when it gains a neighbour.

Agent session: agent session

🤖 Generated with Claude Code