Agent chat: no "Worked for 0s"; an empty turn footer takes no line

Merged
TE
16d ago
+150-6

Summary

Leo (2026-10-21) on a turn footer reading "Worked for 0s" with its Pin and age on a full line: "IF WE 0 SECONDS THEN IT DOESNT NEED TO TAKE UP SPACE!?"

  • A turn under a second says no "Worked for" in its footer (footerLabel, conversation/turns.ts). A turn stopped within a second still says "You stopped after 0s", and one whose work folds under "Worked for" says nothing there, as before. 5 s and up are unchanged ("Worked for 5s").
  • A footer with nothing to show at rest (no answer to Copy or Read aloud, no label, not failed: only Pin, Fork and its age, all hover-only) is now empty (isEmptyFooter) and takes no line: its row is the turn gap alone. When the pointer is on the turn, its controls show over that 24px gap (.cv-turn-actions--empty, absolute), so nothing moves. The chat's last footer has only the 8px message gap, too short for the line, so an empty one draws nothing there; the prompt's own hover row has the same Fork and age.
  • The virtualizer's first-layout estimate (model.ts fallbackRowHeight) matches: an empty footer is TURN_GAP (or MESSAGE_GAP when last), with no META_ROW.
  • Footers with an answer keep their reserved hover row, the same pattern as the prompt's hover row from #23769.

Scope: the gap above a "Received message from" row is #23925's (another lane): this PR leaves that row and its alignment alone. It does shrink the empty footer between a prompt and that row by its 24px line. #23843 (merged) changed what folds into "Worked for", not the footer label; no conflict.

Before / after (Linux gallery, synthetic fixtures)

New entries agent-pane.transcript sub-second-turns (at rest) and sub-second-turns-pointed (pointer on the quiet turn's prompt). The before column is the same entry on the base (branch tp/no-zero-second-footer-before, base + this gallery entry only, not for merge):

Measured in the gallery frames (headless Chromium, row heights): before, both sub-second footers were 48 px and read "Worked for 0s"; after, the quiet turn's footer is 24 px (the turn gap alone) with no label, the sub-second answer's footer is 48 px with no label (it keeps its line for Copy), and the 5 s turn still reads "Worked for 5s".

Tests

webviews/src/agent-session/acpmux/conversation/TurnFooter.test.tsx (commit 42384d7 before the fix):

  • 0, 1 and 999 ms turns: no label and no "Worked for" in the rendered footer.
  • A 5 s turn: "Worked for 5s".
  • A stopped sub-second turn still says it stopped; a folded turn's footer says nothing.
  • isEmptyFooter: only hover controls is empty; an answer, a label or a failure is not; the rendered footer carries cv-turn-actions--empty only when empty.
  • Layout: an empty footer between prompts is 24 px (the turn gap), 8 px when last; a footer with an answer stays 48 px.

On the base the new test fails (it imports footerLabel and isEmptyFooter, which do not exist there).

Observed / Not run

  • Not run locally: bun test (cosmic-gray's guard sends tests to CI/fleet). The PR's web CI jobs run it.
  • Gallery compare builds for both branches (URLs above); row heights read from those frames in headless Chromium.
  • Reds on this head are base reds: gallery health (composer#steer-read-hover), cmux-next checks (namespace-type in Swift files and test_ci_swiftpm_build_metrics.py), release-notary and Guard status. The same jobs are red on #23843 and #23769.
  • No Swift changed.

Changelog

  • Fixed: the agent chat no longer shows "Worked for 0s" under a turn that took under a second, and a turn with nothing to copy no longer leaves an empty footer line.

No capture: webview-only change; before/after are the Linux gallery entries above.

Agent session: cosmic-gray

🤖 Generated with Claude Code