DECSTBM scroll-region experiment (tengu_marlin_porch) corrupts inline TUI on wide panes / multi-line statuslines
Summary
A server-gated rendering experiment (statsig gate tengu_marlin_porch, the DECSTBM scroll-region path) corrupts the inline TUI: the input caret renders in the wrong spot from session start, and as the conversation grows past one screen, whole rows/frames duplicate and stack downward. The duplication is present in the terminal's actual cell grid (verified by capturing the grid), so it's Claude Code's emitted output — not a display-only artifact.
The only thing that resolves it is disabling statsig gate-fetching entirely (CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1), which makes all gates fall back to defaults. There is no way to disable just this one experiment.
Environment
- Claude Code 2.1.165 and 2.1.168 (native binary) — both reproduce
- OS: Linux (Arch)
- Terminal: WezTerm
20260331-040028. Also reproduces over plain SSH from Windows Terminal — so it is not terminal-specific. - Pane width: 255 columns (very wide)
- A multi-line custom
statusLineoftype: "command"is configured (also reproduces with a single-line statusline)
Symptoms
- Input caret parked in the chat/output region instead of the input box, from the first frame.
- As the session scrolls past one screen, rows duplicate (e.g. the statusline and
-- INSERT --line appear 2–3× in the grid) and frames stack downward. Ctrl+L(full repaint) clears it momentarily; it re-accrues on subsequent incremental repaints.
Root cause (narrowed by elimination)
The relevant gate is tengu_marlin_porch (DECSTBM scroll-region; j$("tengu_marlin_porch", false)), enabled for this account's cohort. The only fix is CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 (stops gate-fetching → defaults).
Ruled out, each tested independently:
- CC version (2.1.165 and 2.1.168 both break)
- Terminal (WezTerm and Windows-Terminal-over-SSH both break)
- Shell init / prompt
- Statusline height (single-line still breaks)
- OTEL telemetry (telemetry off + gate-fetching on still breaks)
- Per-gate env overrides:
CLAUDE_CODE_NATIVE_CURSOR,CLAUDE_CODE_DECSTBM,CLAUDE_CODE_DISABLE_VIRTUAL_SCROLL— none disable it. NotablyCLAUDE_CODE_DECSTBMis read via a truthy parse that can only force the feature on; there is no force-off value (if (eH(env.CLAUDE_CODE_DECSTBM)) return enabled=true; return gate("tengu_marlin_porch", false)). TERM_PROGRAMblanking (terminal is in the advanced-terminal allowlist, but removing detection still breaks)
Requests
- Fix the DECSTBM scroll-region path for wide panes (≥255 cols) and/or multi-line command statuslines — incremental repaint lands on the wrong rows, leaving duplicates that accumulate as the session scrolls.
- Provide a per-experiment opt-out — e.g. a force-OFF value for
CLAUDE_CODE_DECSTBM, or a settings key. Right now the only off-switch isCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, which is an umbrella that also disables telemetry and every other gate-dependent feature, so there's no way to disable just the broken rendering experiment.
Repro
- Wide terminal (~255 cols), a
type: "command"statusline. - Use an interactive session past one screen of scrollback.
- Caret is misplaced immediately; rows duplicate as it scrolls.
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1makes it disappear.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗