Repository navigation
Agent pane: inbox rows share the tool rows' icon column; a sender's mark is its real harness - #30652
Conversation
…ark is its real harness
Leo, 2026-11-01: "i wanted this to be left aligned with the other tool calls", and on the
folded group: "let's just make this look better".
- A folded inbox group ("N messages from M sessions") is now a tool row: the sender's harness
mark (several senders: the messages glyph) in the tool rows' icon column, their 22px height,
gap and type, the count as the summary with the senders muted, and the chevron after the label
shown only on hover, focus or while open. Opened, its threads start at the tool rows' text x.
- A sender's mark comes from the listed chat's harness, else the fromHarness acpmux bound,
else the neutral agent glyph. It is never guessed from the sender's name: a Codex lane
called claude-* drew Claude's mark (cmux#30247). Inbox threads read fromHarness.
- Gallery: agent-pane.inbox-notice icon-column (shipped) and two head versions
(group-chevron, group-count) beside lines and card.
- Tests: inbox-row-icon-column.test.ts (Chromium, light and dark) and
inbox-sender-mark.test.tsx.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-06adbde0c46733e12100
|
Owned by an agent session · session |
There was a problem hiding this comment.
2 issues found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="webviews/test/inbox-sender-mark.test.tsx">
<violation number="1" location="webviews/test/inbox-sender-mark.test.tsx:140">
P2: This mixed-sender assertion does not verify the messages glyph: `marks()` classifies every SVG as `"neutral"`, so an incorrect icon would still pass. Assert the icon’s `data-icon` value directly.</violation>
</file>
<file name="webviews/src/agent-session/acpmux/model.ts">
<violation number="1" location="webviews/src/agent-session/acpmux/model.ts:1659">
P2: Changing the inbox look does not invalidate the virtual layout, so this grouped predicate is not applied to existing offscreen rows immediately. Switching between a folded look and `lines`/`card` can leave stale heights and cause virtualization to mount or position rows at the wrong offsets; make the layout subscribe to the inbox-look change or pass a look version into its memo dependencies.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| await render({ | ||
| threads: [thread("grid-lane", { fromSession: "s-claude" }), thread("claude-x", { threadId: "pr:3" })], | ||
| }); | ||
| expect(marks(".cv-inbox__head > .cv-tool__icon")).toEqual(["neutral"]); |
There was a problem hiding this comment.
P2: This mixed-sender assertion does not verify the messages glyph: marks() classifies every SVG as "neutral", so an incorrect icon would still pass. Assert the icon’s data-icon value directly.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/inbox-sender-mark.test.tsx, line 140:
<comment>This mixed-sender assertion does not verify the messages glyph: `marks()` classifies every SVG as `"neutral"`, so an incorrect icon would still pass. Assert the icon’s `data-icon` value directly.</comment>
<file context>
@@ -0,0 +1,141 @@
+ await render({
+ threads: [thread("grid-lane", { fromSession: "s-claude" }), thread("claude-x", { threadId: "pr:3" })],
+ });
+ expect(marks(".cv-inbox__head > .cv-tool__icon")).toEqual(["neutral"]);
+});
</file context>
| if (grouped && !messageOpened(sessionId, row.id)) return finish(line + MESSAGE_GAP); | ||
| // The group's head is a tool row (22px) in 2px margins (InboxNoticeCard.css .cv-inbox--group). | ||
| const head = 2 + 22 + 2; | ||
| const grouped = threads.length > 1 && foldsThreads(inboxNoticeLook()); |
There was a problem hiding this comment.
P2: Changing the inbox look does not invalidate the virtual layout, so this grouped predicate is not applied to existing offscreen rows immediately. Switching between a folded look and lines/card can leave stale heights and cause virtualization to mount or position rows at the wrong offsets; make the layout subscribe to the inbox-look change or pass a look version into its memo dependencies.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/model.ts, line 1659:
<comment>Changing the inbox look does not invalidate the virtual layout, so this grouped predicate is not applied to existing offscreen rows immediately. Switching between a folded look and `lines`/`card` can leave stale heights and cause virtualization to mount or position rows at the wrong offsets; make the layout subscribe to the inbox-look change or pass a look version into its memo dependencies.</comment>
<file context>
@@ -1654,11 +1654,13 @@ function measuredRowHeight(
- if (grouped && !messageOpened(sessionId, row.id)) return finish(line + MESSAGE_GAP);
+ // The group's head is a tool row (22px) in 2px margins (InboxNoticeCard.css .cv-inbox--group).
+ const head = 2 + 22 + 2;
+ const grouped = threads.length > 1 && foldsThreads(inboxNoticeLook());
+ if (grouped && !messageOpened(sessionId, row.id)) return finish(head + MESSAGE_GAP);
const { lineHeight } = metrics();
</file context>
…lign-harness-icon # Conflicts: # webviews/src/agent-session/acpmux/conversation/InboxNotice.gallery.ts # webviews/src/agent-session/acpmux/conversation/InboxNoticeCard.tsx # webviews/src/agent-session/acpmux/conversation/IncomingMessageCard.tsx
|
Review (codex, router-review): SHIP at ea98d18 Reviewer: codex gpt-6.1-sol xhigh, fast tier. Follow-ups: 1. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at ea98d18 Visual verdict: no images; Leo tries the build
Follow-ups:
|
Leo, 2026-11-01, on "2 messages from 1 session": "let's just make this look better". On the new base the groups he sees are the waiting group (PendingMessagesCard) and a delivered inbox batch (LaneNoticeBatch), not the legacy InboxNoticeCard group. All three now share MessageGroupHead: a tool row with the sender's harness mark (several senders: the messages glyph) in the icon column, the count as the summary, the senders muted, and the chevron after them, shown on hover. acpmux's fromHarness now reaches the batch's received lines. The row estimate follows the 22px head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lign-harness-icon
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Passes: CI passes on CI passes on Written by red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on c17c8da to compare; do not merge until green; see lane-rules Shipped in:
|
|
Found 7 test failures on Blacksmith runners: Failures
|
|
Review (codex, router-review): SHIP at a5104be Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at a5104be Visual verdict: All 16 available after screenshots match their before images. The changed inbox-group states are absent; Leo tries the build.
No blocking correctness issue found. Full tests were not rerun: Bun and dependencies are unavailable in this box. Follow-ups:
|
…lign-harness-icon # Conflicts: # webviews/src/agent-session/acpmux/model.ts
|
Review (codex, router-review): SHIP at 06543de Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at 06543de Visual verdict: no images; Leo tries the build
Follow-ups:
|
…lign-harness-icon # Conflicts: # webviews/src/agent-session/acpmux/conversation/PendingMessagesCard.css # webviews/src/agent-session/acpmux/model.ts
|
Review (codex, router-review): SHIP at b5d10b4 Reviewer: codex gpt-6-astra high, fast tier. Follow-ups: 1. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at b5d10b4 Visual verdict: no images; Leo tries the build
Follow-ups:
|
#29965's transcript-row-pitch-browser test caught the report batch head ("N reviews ended") 4px right of the icon column: raising LaneNoticeBatch.css's toggle selectors with :not() let its inset beat the one-line row rules. Keep base's selectors and zero the inset and hover plate on the tool-row head alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lign-harness-icon
|
Review (codex, router-review): SHIP at 661da86 Reviewer: codex gpt-6.1-sol xhigh, fast tier. Follow-ups: 2. Each lands as an issue in this repo that links this receipt; the lane that opened the PR fixes it forward. SHIP at 661da86 Visual verdict: no images; Leo tries the build
Syntax parsing and focused harness-propagation checks passed. Bun and browser tests were unavailable because the runtime and dependencies are absent. No blocking findings. Follow-ups:
|
…eed run Base 762fda7 (after #30652 and #30194) adds center-line violations to the folded-run, queued-from-agent, hover-fade and incoming-message states; the base replay cannot excuse them until base has the checker, so they join the baseline rows from gallery-health run 41322226213. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a
…30256) * gallery health: gate layout shift on load and every play step (element boxes per frame) WIP: baseline seeded in a following commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: shift scenarios play Codex folds and the debug load_seed history; document the shift gate Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery health: check the design specs' geometry rules from the DOM of every state Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery-matrix: write shift rows from the worst seeding run A state that shifts in some runs got a 0 row when rows were written from the least run, and would then fail unrelated PRs on its flaky runs. Review follow-ups 2 and 3 on #30250. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: older-history waits on a boolean (typecheck) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery-matrix: seed shift-baseline.json from two gallery-health runs Rows from the worst of #30250's two full gallery-health runs (0ac1691 and a17daa5): 2763 states, 561 with a non-zero row. A state at 0 now fails on any shift; the rest fail past their row by a quarter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: a wait step never fails a play; gallery health scores its shift The webview suite found that measuring waitFor as a step made existing plays fail on what they wait for: the header PR button arriving (header-tools), the mention list opening (composer-mention), the composer controls settling (narrow-layouts). A wait now goes unjudged in judgeStep, for shift, anchor moves, long frames and settle. Its shift is still measured and scored against the state's row in gallery health's shift baseline. Test: bun test test/gallery-shift.test.ts. The new case fails on the previous head and passes here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: say a wait step still gets the popup-layer check Review follow-up on #30250. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: smooth zero-row shift limit, copy-proof violation keys, listboxes only in popups Three review follow-ups on #30256, fixed before the geometry baseline is seeded so its keys do not bake them in: - Every shift row's limit now adds LIMIT_SLACK (0.0005), a 0 row's included. A 0 row was ten times stricter than a tiny row, at the level where frame timing alone scores. - Violation keys use the row id, data-id, data-value, value or aria-label before an element's text, so a copy-only PR does not rename a listed violation. Plain generated ids are never used. - A listbox counts as a menu only inside a popover or dialog, so pane-wide list panels do not trip menu-fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery-matrix: reseed shift rows from three runs, seed geometry rows Shift rows are rebuilt from the worst of three full gallery-health runs: the two on #30250 and this PR's run at 92c5bb5 on base 593b25f. That gives 2843 states, 608 of them non-zero. Base moved after the first seed, and one flaky state, model-picker#quick-search-field-opencode (0.0024 to 0.0081 across renders), came out as this PR's own red. Geometry rows come from that run: 2841 states, 345 with listed violations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * Gallery geometry baseline: add the violations base gained since the seed run Base 762fda7 (after #30652 and #30194) adds center-line violations to the folded-run, queued-from-agent, hover-fade and incoming-message states; the base replay cannot excuse them until base has the checker, so they join the baseline rows from gallery-health run 41322226213. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * Shift baseline: motion.sync-list#inserts-from-second-client row 0.0059 The insert from a second client animates the list rows into place; three seed runs scored 0, gallery-health run 41327725064 scored 0.0059 on the Replay click. A real insert moves rows, so its row is that run's score. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * Gallery baselines: seed shift rows from the worst of five full runs Full renders (this PR changes scripts/gallery-matrix) kept turning up states that shift in some runs and in every attempt of that run (guest-page.waiting#decided, artifact-panel#svg, settings-menus#customized), so three seed runs were not enough. Shift rows are rebuilt from scratch as the worst score of the three seed runs plus gallery-health runs 41322226213 and 41335560293; geometry rows gain the 3 keys the last run saw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ays) (#30265) * gallery health: gate layout shift on load and every play step (element boxes per frame) WIP: baseline seeded in a following commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: shift scenarios play Codex folds and the debug load_seed history; document the shift gate Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery health: check the design specs' geometry rules from the DOM of every state Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: real-shaped recorded Claude and Codex chats (anonymized replays) Leo, 2026-11-01: "how about like the apparatuses for improving ui verification? let's examine what we can do better for our workflows". anonymize-recording.ts turns an acpmux session recording into a fixture with none of its words (same lengths, line breaks and punctuation; fake ids, fixed epoch). agent-pane.recorded-chats replays the #30176 Claude turn and a real Codex turn steered by agent inbox messages through the pane's own client, so gallery health's shift and geometry checks see real-shaped chats. Tests: bun test test/gallery-anonymize-recording.test.ts (2 pass). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery-matrix: write shift rows from the worst seeding run A state that shifts in some runs got a 0 row when rows were written from the least run, and would then fail unrelated PRs on its flaky runs. Review follow-ups 2 and 3 on #30250. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: older-history waits on a boolean (typecheck) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery-matrix: seed shift-baseline.json from two gallery-health runs Rows from the worst of #30250's two full gallery-health runs (0ac1691 and a17daa5): 2763 states, 561 with a non-zero row. A state at 0 now fails on any shift; the rest fail past their row by a quarter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: a wait step never fails a play; gallery health scores its shift The webview suite found that measuring waitFor as a step made existing plays fail on what they wait for: the header PR button arriving (header-tools), the mention list opening (composer-mention), the composer controls settling (narrow-layouts). A wait now goes unjudged in judgeStep, for shift, anchor moves, long frames and settle. Its shift is still measured and scored against the state's row in gallery health's shift baseline. Test: bun test test/gallery-shift.test.ts. The new case fails on the previous head and passes here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: say a wait step still gets the popup-layer check Review follow-up on #30250. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery: smooth zero-row shift limit, copy-proof violation keys, listboxes only in popups Three review follow-ups on #30256, fixed before the geometry baseline is seeded so its keys do not bake them in: - Every shift row's limit now adds LIMIT_SLACK (0.0005), a 0 row's included. A 0 row was ten times stricter than a tiny row, at the level where frame timing alone scores. - Violation keys use the row id, data-id, data-value, value or aria-label before an element's text, so a copy-only PR does not rename a listed violation. Plain generated ids are never used. - A listbox counts as a menu only inside a popover or dialog, so pane-wide list panels do not trip menu-fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * gallery-matrix: reseed shift rows from three runs, seed geometry rows Shift rows are rebuilt from the worst of three full gallery-health runs: the two on #30250 and this PR's run at 92c5bb5 on base 593b25f. That gives 2843 states, 608 of them non-zero. Base moved after the first seed, and one flaky state, model-picker#quick-search-field-opencode (0.0024 to 0.0081 across renders), came out as this PR's own red. Geometry rows come from that run: 2841 states, 345 with listed violations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * Gallery geometry baseline: add the violations base gained since the seed run Base 762fda7 (after #30652 and #30194) adds center-line violations to the folded-run, queued-from-agent, hover-fade and incoming-message states; the base replay cannot excuse them until base has the checker, so they join the baseline rows from gallery-health run 41322226213. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * Shift baseline: motion.sync-list#inserts-from-second-client row 0.0059 The insert from a second client animates the list rows into place; three seed runs scored 0, gallery-health run 41327725064 scored 0.0059 on the Replay click. A real insert moves rows, so its row is that run's score. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * Gallery baselines: seed shift rows from the worst of five full runs Full renders (this PR changes scripts/gallery-matrix) kept turning up states that shift in some runs and in every attempt of that run (guest-page.waiting#decided, artifact-panel#svg, settings-menus#customized), so three seed runs were not enough. Shift rows are rebuilt from scratch as the worst score of the three seed runs plus gallery-health runs 41322226213 and 41335560293; geometry rows gain the 3 keys the last run saw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a * anonymize-recording: keep each event's kind in its typed output The scrubbed rest is typed through Omit of an index-signature type, which drops the required kind, so the merge with base failed the webviews type check (TS2741). The kind is a protocol word the scrubber keeps; set it from the event. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-e1bbe8a486fbacd68f4a --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…line Leo, 2026-10-27, on a lane's message in the transcript: "Is this, like, from another machine? But even if they're from another machine, what's going on here?" The sender's harness mark and family relation already landed (#30652, #30247); the machine was only in the name's tooltip. The line now reads "review-lane · studio-mac", the host muted and first to give way when the line is short. This Mac's senders name none. Test: test/inbox-sender-mark.test.tsx (fails on base, passes here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-905a639018a674280824
…line (#31716) Leo, 2026-10-27, on a lane's message in the transcript: "Is this, like, from another machine? But even if they're from another machine, what's going on here?" The sender's harness mark and family relation already landed (#30652, #30247); the machine was only in the name's tooltip. The line now reads "review-lane · studio-mac", the host muted and first to give way when the line is short. This Mac's senders name none. Test: test/inbox-sender-mark.test.tsx (fails on base, passes here). Agent-Session: https://cmux.com/deeplink/agent?id=aid-905a639018a674280824 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo, 2026-11-01, on an inbox message line in the transcript: "i wanted this to be left aligned with the other tool calls". On the folded message group ("2 messages from 1 session") under a stack of tool rows: "let's just make this look better".
What changed
Every folded group of messages from other sessions now has a tool-row head. On base these groups are drawn by three components:
PendingMessagesCard("N messages from M sessions", the row Leo named);LaneNoticeBatch("N inbox threads");InboxNoticeCardgroup.Each had a bare chevron as its leading glyph, a 26px line, and words 1.5px right of the tool rows'. All three now share
MessageGroupHead.tsx/.css, which is a tool row (.cv-tool):agent.chat). There is no leading chevron.cv-pending__toggle,cv-lane-batch__toggle). A report batch ("N reviews ended") keeps its own head. The row estimate (model.ts) follows the 22px heads.A sender's mark is its real harness, never a guess from its name.
SenderMark(fromIncomingMessageCard.tsx, shared by received lines, inbox lines and the group heads) takes the listed chat's harness, else thefromHarnessacpmux bound. With neither, it draws the neutral agent glyph. Before, it fell back to a brand looked up from the sender's name, so an unlisted Codex lane calledclaude-…drew Claude's mark. The notice'sfromHarnessnow reaches the delivered batch's received lines (laneReport.ts,laneNoticeBatches.ts). The root cause is that acpmux outbox sends bind nofromSessionId/fromHarness. That fix belongs in acpmux and is filed as #30247.Single inbox line. On base its glyph center and title x already equal the tool rows' (#29124 folded #28796's alignment). The new browser test pins that, so it stays aligned among tool rows.
Not changed: tool rows themselves, the status rows between replies (#29124) and subagent rows (#29276). Each row's content, colours and glass are kept.
Gallery
agent-pane.inbox-noticehas new versions. Each shows, among tool runs: a received line, an unlistedclaude-…sender (neutral glyph), a delivered one-sender group, a delivered several-sender group, and the waiting "2 messages from 1 session".icon-column: shipped. The chevron shows on hover.icon-column-look-chevron: the chevron always shown.icon-column-look-count: the count alone, with senders in the tooltip.icon-column-open: the several-sender group opened.The existing
look-lines-*andlook-card-*versions stay beside them. I pickedicon-column: it matches the tool rows exactly, and the always-on chevron repeats a control on every row.Tests
webviews/test/inbox-row-icon-column.test.ts(Chromium, light and dark): every received line's and group head's glyph center and title x equal a tool row's (0.5px). Each group head's height, icon-to-word gap and type size equal a tool row's, and its chevron is hidden at rest and shown on hover.PendingMessagesCard/LaneNoticeBatchat the same gallery: the delivered batches' glyph is at 32px vs the tool rows' 28, their title at 46.5px vs 42.5, and they are 26px tall vs 22. The waiting group's title is at 44px vs 42.5, its gap 8px vs 6.5, and it is 26px tall.webviews/test/inbox-sender-mark.test.tsx: a Claude sender (listed, or bound byfromHarness) gets the Claude mark. A listed Codex chat namedclaude-sr2-fleet-mesh-2gets OpenAI's. An unknownclaude-xsender gets the neutral glyph. A one-sender group gets its mark and a mixed group the messages glyph. Red on base (3 of 5 failed), green after.transcript-icon-column,incoming-sender-chip,lane-notice-card,incoming-message-disclosure-browser,agent-pane-suggested-tasks,InboxNoticeCard.test.tsx,check:piecesandtsc. All ran on the fleet throughcmux-ci test.Spec: design/chat-transcript.md "One icon column". The inbox-row rule is added in a leo-workspace PR that cites this one.
Risk: low. The change is limited to the three message-group heads' markup and CSS, the row estimate for those heads, and the sender-mark fallback. A sender whose name alone used to pick a brand now shows the neutral glyph until acpmux binds its harness (#30247).
🤖 Generated with Claude Code
Agent session: agent session