Transcript: a note between tool rows is estimated from its wrapped lines
Fixes #31148 (follow-up from the review of #30400).
model.ts activityStepHeight estimated a note folded between tool rows (turns.ts mergeShortNotes, drawn as .cv-tool-note) as one 20px line plus the 12px note gap above and below. A note that wraps draws taller than that until it is measured, so the scroll height could step once it scrolled into view. The note is now estimated from its text at the row's width with the file's textHeight (a new optional line-height argument gives the note's 20px lines), as replies are. The width is threaded through foldedRunSteps / foldedGroupHeight. Prepared texts are cached and cleared past 256, as the other estimate caches are; only notes are measured, so there is no new per-row or per-token work.
Red/green (rowEstimates.test.ts, new case "a note folded between tool rows is estimated as the lines it wraps to at the column's width"):
- red at the base: https://github.com/manaflow-ai/cmux/actions/runs/41331703851 (24 pass, 1 fail: the wrapped note was estimated at one line)
- green with the fix, plus
bun run check: https://github.com/manaflow-ai/cmux/actions/runs/41332871351
Spec: design/chat-transcript.md is unchanged; the note's drawn rhythm is unchanged, only its estimate.
Related: leo-workspace#1929 (grid.md's copy button 28/6 vs shipped 24/4) was settled in a notes PR; #29639 is #31176.
Risk: small, estimate only (first-layout heights of folded runs with notes).
Agent session: agent session
š¤ Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes the transcript's scroll-height estimate for a note folded between tool rows. The estimate previously assumed a single 20px line, so the scroll height stepped when a wrapping note scrolled into view. The note is now estimated from its flattened text at the column's width on 20px lines, matching how .cv-tool-note draws: white-space: normal collapses newlines and space runs to single spaces. Prepared note texts are cached and cleared past 256 entries, and only notes are measured, so there's no per-row or per-token cost. The new test measures wraps against the model's one-line height so it holds under the base merge's chromeScale.