web: single-pane terminal overflows the window after a full reload — bottom row pushed below the fold
- Dominant language
- Python
- Stars
- 2
- Forks
- 0
- Avg merge
- 15h 59m
- Merged PRs (30d)
- 9
Description
## Symptom
With a single visible pane, after a full browser reload the pane renders correctly for a brief moment, then the terminal's bottom line pushes down to the **very bottom of the window** — no padding, and the last row(s) are clipped below the fold. Observed on 4.3.6.
The bad state is stable once it settles (it does not self-heal), and it reproduces on reload, so it is not a transient race that resolves itself.
## Two candidate shapes (not yet distinguished)
1. **Grid sized for the wrong box** — the initial fit ran against a taller container than the one that exists after the app chrome (top bar, rail, padding) finished laying out. The emulator keeps more rows than fit-against-the-current-box would produce, and nothing re-fits.
2. **The box itself is wrong** — the card/container grows to full window height, ignoring chrome/padding; the fit is innocently correct for an overflowing box. The "no padding at the very bottom" detail points suspicion here.
Timing note: "fine briefly, then wrong" is consistent with the first fit landing correctly and a re-measure ~0.5s later against a different box. The resize re-assert burst (#174 self-heal) fires at 400/1200/3000 ms after `ready` — it only repeats the last-sent grid to the PTY, so it should not move pixels by itself, but if the first fit ran pre-layout the burst would cement the wrong size.
## How to distinguish
The planned diagnostics snapshot (Settings → Copy diagnostics / `window.__remo.diagnostics()`) separates the two:
- Case 1: `renderer.grid.rows` ≠ `renderer.proposedGrid.rows` (with `fitLoop.lastSkipReason: "unchanged"` indicating the fit loop believes it is done while something resized the emulator behind its back).
- Case 2: `grid == proposedGrid` but `containerPx.bottom > env.viewport.height` — the container's own rect overflows the viewport. (The snapshot captures the **full** bounding rect for exactly this comparison.)
Until that ships, the same facts are reachable manually in devtools: compare the terminal container's `getBoundingClientRect().bottom` against `window.innerHeight`, and count visible rows against what the box height should hold.
## Repro
1. One visible pane (single-pane mode), session attached.
2. Full browser reload.
3. Watch the pane render correctly, then the bottom line push below the window edge within ~a second.
## Suite gap
`npm run test:geometry` (the CI-gating Playwright suite) exists precisely to pin "the terminal grid fits the box that clips it" — jsdom cannot check this. The single-visible-pane + full-reload sequence appears to be a missing case: the suite should load the fixture, wait for settle, and assert both that the container rect stays within the viewport **and** that `rows × cell height` stays within the container, after the re-assert burst window (>3s) has passed.
## Fix ordering
Diagnose before fixing: land the diagnostics snapshot (or do the manual devtools check) to pick case 1 vs case 2, then fix the real one — a blind "call fit again later" patch would mask case 2 while leaving the overflowing box in place.
Contributor guide
Research direction
Start with npm run test:geometry and add the single-visible-pane, full-reload sequence described in the issue. After the re-assert burst has passed, use Settings → Copy diagnostics or the listed devtools checks to distinguish grid sizing from container overflow. Done means the container remains within the viewport and the terminal rows fit inside it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- playwright
- Domain
- frontend, testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100