fix: merge web terminal resilience

This commit is contained in:
Developer
2026-07-18 10:32:56 +00:00
8 changed files with 341 additions and 39 deletions
@@ -0,0 +1,30 @@
# Restore Mobile Terminal Scrolling
## Summary
The recent terminal scrollback optimization disabled scrollback for every viewport. Mobile terminal swipe handling still scrolls xterm's normal buffer programmatically, so swipes in normal-buffer tools no longer have retained output to move through.
## Root Cause
`468f342` changed the terminal configuration to `scrollback: 0` globally to prevent stale repaint frames and wheel scrolling on desktop. The mobile touch handler calls `term.scrollLines()` when the normal buffer is active. With zero scrollback, that call has no scrollable history and becomes a no-op.
## Scope
- `apps/web/src/components/features/terminal/terminal.tsx`
- Focused terminal configuration test
## Fix
Retain a bounded xterm scrollback buffer on mobile only (`10000` lines), while leaving desktop at zero scrollback and with wheel sensitivity disabled. Mobile's existing custom touch handler remains responsible for moving through normal-buffer history; alternate-screen swipes continue to send SGR wheel events to the active TUI.
## Acceptance Criteria
- [ ] A mobile terminal with normal-buffer output exceeding one screen scrolls via a vertical swipe.
- [ ] Alternate-screen terminal scrolling continues to use the existing SGR wheel-event path.
- [ ] Desktop keeps zero xterm scrollback and disabled native wheel scrolling, so stale repaint frames do not return.
- [ ] Focused unit test and frontend quality gates pass.
## Related
- `468f342 fix(terminal): hide scrollbar and stop stale-frame wheel scroll for TUI tools`
- `openspec/changes/fix-terminal-container-overflow`
@@ -0,0 +1,9 @@
# Restore Mobile Terminal Scrolling — Tasks
- [x] Add a mobile-specific terminal scrollback limit while preserving zero scrollback on desktop.
- [x] Reinitialize the terminal when the responsive mobile classification changes so its scrollback and touch handler match the active viewport.
- [x] Add focused tests for the responsive scrollback configuration.
- [x] Run the full frontend test suite (89 tests passed after repairing the `ProjectsPage` test setup).
- [x] Run frontend typecheck, lint, focused tests, and production build.
- [ ] Perform mobile normal-buffer and alternate-screen manual QA.
- [ ] Update project maps for changed source files (the map patch tool currently fails with an unsupported `temperature` parameter).
@@ -0,0 +1,35 @@
# Fix Web Terminal Resilience
## Summary
Prevent large browser pastes from blocking flow-control acknowledgements, and prevent stale reconnect callbacks from replacing a healthy terminal WebSocket.
## Problem
The terminal WebSocket handler awaits each PTY write inline. A large paste can wait for the PTY to become writable while the same handler stops receiving acknowledgement messages. If output flow control has paused PTY reads, the acknowledgement that would resume output remains unread, leaving the terminal apparently frozen.
Separately, reconnect timers and visibility callbacks can create a second socket after a connection becomes healthy. The terminal manager then closes the existing session socket, interrupting active input or rendering.
## Scope
- Queue bounded terminal input onto a single ordered writer so the WebSocket receive loop continues handling acknowledgements, resize, reset, and disconnect messages.
- Make browser reconnection single-owner: stale socket callbacks and retry timers MUST NOT replace a current healthy socket.
- Add focused regression tests for the queueing and reconnect behavior.
## Non-goals
- Re-enable desktop normal-buffer scrollback or mouse-wheel scrolling. Desktop continues to use zero scrollback and disabled wheel sensitivity to avoid the known stale TUI-frame regression.
- Change terminal session persistence, authentication, PTY transport, or mobile touch scrolling behavior.
## Risk and rollback
The bounded input queue must preserve input ordering, reject excess input without blocking control messages, and be cancelled when the WebSocket disconnects. Socket ownership checks must not prevent a legitimate reconnect after a real disconnect. Roll back by reverting the backend queue and frontend ownership changes; existing direct PTY input and retry behavior then resumes.
## Acceptance Criteria
- [ ] A blocked PTY write does not prevent the WebSocket handler from processing a subsequent flow-control acknowledgement.
- [ ] Input bytes are still written to the PTY in arrival order, and excess queued input is rejected rather than growing without limit.
- [ ] A stale socket close event or retry callback cannot replace an open current socket.
- [ ] Component cleanup cancels pending reconnect timers and closes the current socket.
- [ ] Desktop scrollback and wheel settings remain unchanged.
- [ ] Focused backend/frontend tests and relevant quality gates pass.
@@ -0,0 +1,27 @@
# Fix Web Terminal Resilience — Tasks
## Review Workload Forecast
| Field | Value |
| ------- | ------- |
| Estimated changed lines | 180280 |
| 400-line budget risk | Low |
| Chained PRs recommended | No |
| Suggested split | Single focused change |
| Delivery strategy | single-pr |
| Chain strategy | feature-branch-chain |
Decision needed before apply: No
Chained PRs recommended: No
Chain strategy: feature-branch-chain
400-line budget risk: Low
## Tasks
- [x] **RED — backend input/control concurrency:** characterize a PTY write that waits for readiness while an acknowledgement is received; prove the acknowledgement is handled without waiting for that write to finish.
- [x] **GREEN — ordered input writer:** move PTY writes behind one cancellable ordered queue/worker while retaining the current public WebSocket message protocol and input ordering.
- [x] **TRIANGULATE — lifecycle:** cover worker cancellation and queued-write failure/disconnect handling.
- [x] **RED — frontend socket ownership:** characterize stale close/retry callbacks after a newer socket has become current.
- [x] **GREEN — reconnect ownership:** ensure only the current socket can update state or schedule a retry; cancel retry timers during cleanup.
- [x] **REFACTOR:** keep the connection lifecycle readable and avoid changing the intentional desktop scrollback configuration.
- [x] **Verify:** run targeted backend and frontend tests, frontend typecheck/lint/build, backend checks practical in the isolated worktree, and inspect diagnostics. (Backend pytest is unavailable locally: no pytest/uv executable; Docker test execution was explicitly declined.)