fix(agent-chat): keep the composer edge fade compact

Merged
TE
8d ago
+95-22

Jump to latest no longer widens the fading band above the composer from 18px to 56px. The normal short edge keeps text readable while retaining a soft boundary and hiding rows beneath the dock.

Leo, 2026-10-27: "why are you blurring all the way up here?" The apparent blur was a transcript alpha mask. The gallery compares the old 56px band, the selected 18px edge, and no fade at the same 760×700 size. The short edge preserves separation without washing out almost three text lines. The composer and transcript bounds, scroll position, glass, and input behavior remain the same.

The residual small-control audit covered sender chips, Details, Show more, code Copy/Wrap, retry, and pair Resume: their hover paint is local to their controls. The full-width tool/thinking disclosure rows are themselves the controls. The PR-control layout and duplicate Copy are handled separately by #26082 and #26096.

The minimap reserves the same 18px bottom fade as the transcript. Keeping its former 56px clearance shortened the rail by 38px. In a 320px pane, the lower rail boundary now reaches 298px instead of 260px, with the top boundary still 22px; the existing height caps still apply. The CSS/model check now requires equality, and the short-pane geometry tests use the actual fade width.

Repair validation for 1388f0d2d71107999eb8c381e5a02a9b04ed463a: focused remote run 40805012438 passed 38 minimap tests / 258 assertions and 10 edge, wheel and parked-stream tests / 101 assertions, plus full bun run check (2,948-file typecheck). The tested snapshot and final commit have the identical source tree 4fe9657cf7524d8d6f574b6b6aed771c23361ca4; the final scoped gate and diff whitespace check pass. No transcript follow-state or rail height-policy change is included. Existing captures below are explicitly pinned to the earlier fade-only head.

Earlier reconciliation validation at 52c4de8911b6f20886d7152e17df2f9dda51dd5a (base 096c26446c932be59e780f26aba4b0283e7feb68):

  • Focused remote run 40795220219 passed on the exact source tree ac54fbd7bc2f6d3fd189ce3b2dc54a9cae709552: soft edges 1 test / 6 assertions, parked streaming 3 / 41, wheel pass-through 6 / 54 across Chromium and WebKit.
  • bun run check passed, including lint, formatting, protocol checks and typechecking 2,948 files.
  • Scoped prepush-gate.py --base 096c26446c932be59e780f26aba4b0283e7feb68 --head 52c4de8911b6f20886d7152e17df2f9dda51dd5a passed with no new violations; git diff --check passed.
  • App.tsx is byte-identical to the merged base, preserving #26088's renderScroll anchor synchronization and follow-state behavior.
  • Initial combined run 40794305018 returned exit 1 with missing final command verdicts. It is not counted as passing or excused as a base red; the focused recovery above completed all requested suites with explicit per-command exits.

Original implementation validation (historical heads):

  • Red regression commit b919f6c1a05ce83a5c2c35c0c84b6035c7ad160e: the real Chromium alpha-mask probe 30px above the dock reads red-channel 134 (required >240). The same test passes after the fix, including soft-edge and hidden-under-dock assertions.
  • CMUX_BROWSER_TESTS=1 bun test test/agent-pane-soft-edges.test.ts: 1 pass, 6 assertions.
  • CMUX_BROWSER_TESTS=1 bun test test/transcript-parked-stream.test.ts: 3 pass, 41 assertions; parked painted cases show zero jitter, remounts, or false-fade frames.
  • CMUX_BROWSER_TESTS=1 bun test test/agent-pane-wheel-pass-through.test.ts: Chromium 3 pass, 27 assertions; WebKit is not installed locally.
  • bun run check: passes at final head 8530cdb7e6fd579ddb849f63172ae08a2786fc70, including formatting, lint, 2,883-file typecheck, and protocol generation.
  • PR-scoped bun test test/gallery-coverage.test.ts: 6 pass; unrelated base coverage debt prints as warnings.
  • python3 scripts/verify-local.py: unchanged localization debt exceeds the base baseline (identical 91 -> 126); this PR changes no strings or localization files. Other selected checks pass.

Gallery: agent-pane.composer-edge

Fresh fixture captures from head 52c4de8911b6f20886d7152e17df2f9dda51dd5a, base 096c26446c932be59e780f26aba4b0283e7feb68: gallery run 40794611729, artifact gallery-advisory-26370-52c4de8911b6f20886d7152e17df2f9dda51dd5a. All six images render the same 420×700 CSS-pixel viewport at device scale 2 (840×1400 PNG), with scrollTop 1200. Every variant reports exact head/source provenance, passing play steps and zero layout shift. The wide-edge arm reproduces the previous 56px mask on this head; the selected arm uses the production 18px edge. Source: composer-edge fixture.

AppearanceBefore behavior: 56px wide-edge armSelected: 18px production edge
Dark56px edge, dark18px edge, dark
Light56px edge, light18px edge, light

Current no-fade alternative: dark, light. These six images contain synthetic fixture text only and passed the media helper's OCR privacy check. Reference matched: the Codex bottom-docked composer, using a local soft edge; the private reference image is not published.

Preserved historical fixture evidence and its limitations

Gallery: agent-pane.composer-edge, variants wide-edge, short-edge, and no-edge. The six original Chromium capture links are preserved below. These are historical fixture evidence, not a recapture of the reconciled head. The composer stays at (20, 542), 720×94px; scrollTop stays 1200 and the jump control stays at (364, 498), 32×32px in every arm. Reference matched: the Codex bottom-docked composer, using a local edge rather than a wide obscured band. The images below are synthetic cmux gallery fixtures.

Before and after, at the same window size. Inspection during reconciliation found that every file labelled light is byte-identical to its dark counterpart. The short-edge and no-edge captures are also identical at this fixture position. These captures demonstrate the dark wide-to-short change; they do not establish light-mode coverage or visually distinguish the 18px and 0px alternatives.

AppearanceBefore: 56px bandSelected: 18px edge
DarkBefore: wide composer edge, darkAfter: short composer edge, dark
Original light-labelled files (render dark)Before: wide composer edge, lightAfter: short composer edge, light

The no-fade alternative: dark, original light-labelled file, renders dark.

Takes back #22860: this PR intentionally supersedes only #22860's 56px Jump-to-latest fade; Leo's follow-up requires the existing 18px edge so transcript text above the composer remains readable.

Changelog

Fixed: Keep transcript text readable above the composer while Jump to latest is visible.

Review (independent Codex gpt-6-astra high, review_fade_final_26370): SHIP at 1388f0d2d71107999eb8c381e5a02a9b04ed463a

The separate read-only reviewer inspected the entire nine-file final diff, including the 18px rail-model repair from the bare mirror. No concrete blocker was found; primary inspection agrees. This is a different-model subagent review, not a fleet review-box run.

The two earlier head-only CI flags composer-row-steps.test.ts and composer-type-scale.test.ts failed during gallery warmup before executing any tests; they are not excused as base reds. At the preceding 52c4de89 head, run 40801139762 passed type-scale (50 tests); run 40803020790 passed row-steps plus edge tests (16 tests) and minimap tests (28 tests). Final rail-repair run 40805012438 passed 38 minimap tests / 258 assertions and 10 edge, wheel and parked-stream tests / 101 assertions, plus the full web check. Its tested tree 4fe9657cf7524d8d6f574b6b6aed771c23361ca4 equals the final source tree. At a 320px pane, rail room now ends at 298px instead of 260px; 720px rail height remains capped at 662px by the existing 92% maximum. No new App or scroll-follow change. Existing captures precede this rail geometry repair.

Agent session: agent session