The real scroll-smear cause, and why the previous fix could not work.
A floating dialog draws a small box over a static background: the frame
around it and the box's own border are identical frame-to-frame, so
prompt_toolkit's differential renderer never rewrites them. Its paint is
relative-positioned (cursor_forward/backward from pt's own assumed
column, advanced by pt's own width model). A glyph the terminal renders
wider than pt models — a route graph's braille lanes, node-type marks, a
chart's braille — desyncs the terminal cursor and pushes a stray cell
onto that static frame, where it lingers because pt believes the cell is
unchanged. Full-frame screens masked this: their body redraws wholesale
on scroll, healing the smear itself (the map scrubs only its static edge).
The prior attempt (822db52) filled pt's cached frame with a sentinel to
force an in-place rewrite. But that keeps previous_screen non-null, so pt
never takes the erase_down + cursor-reset-to-origin branch — it repaints
the same desynced garbage. Only dropping the cached frame triggers the
full erase_down that blanks the terminal and re-syncs the cursor. It also
only covered three route-graph screens, missing scrolled result windows.
Fix, structural rather than per-screen: when a scroll/movement action
reaches a screen that is floating over a backdrop, drop pt's remembered
frame so the next paint clears the whole terminal and redraws clean. No
smears flag, no geometry — any floating dialog, any wide glyph. This is
the "clear the screen before redraw" the symptom calls for; the cost is
one full repaint per dialog scroll, negligible for a modal box.
Removes the smears flag and _reflush_frame; the map's own edge scrub is
untouched. Full suite: 807 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>