fix(cli): first repaint no longer swallowed when monotonic clock is small

time.monotonic() counts from an arbitrary epoch (boot on Linux). Two CLI
repaint throttles used 0.0 as the never-fired sentinel, so on a freshly
booted VM (CI runners, containers) now - 0.0 < min_interval suppressed
the FIRST repaint ever requested:

- _schedule_focus_regain_redraw: min_interval=60 suppressed the first
  focus-regain redraw whenever uptime < 60s — the exact failure in CI
  run 32494557030 (test_focus_regain_redraw_is_rate_limited, both
  attempts red on a fresh runner, green everywhere else).
- _invalidate: same 0.0 sentinel; a first spinner/stream repaint inside
  the first 250ms of uptime was droppable the same way.

Both now use None as the never-fired sentinel. Regression test pins
monotonic()=3.0 with min_interval=60 and asserts the first redraw fires.
This commit is contained in:
Teknium
2026-08-21 09:16:37 -07:00
parent 6467172db9
commit eab377a407
3 changed files with 31 additions and 3 deletions
+12 -2
View File
@@ -90,7 +90,11 @@ class CLITerminalMixin:
if getattr(self, "_terminal_io_broken", False) or getattr(self, "_resize_recovery_pending", False):
return
now = time.monotonic()
if hasattr(self, "_app") and self._app and (now - getattr(self, "_last_invalidate", 0.0)) >= min_interval:
# None sentinel, not 0.0 — monotonic's epoch is arbitrary (boot on Linux), so on
# a fresh VM ``now`` can be < min_interval and a 0.0 sentinel would swallow the
# first repaint (same class as _schedule_focus_regain_redraw below).
last = getattr(self, "_last_invalidate", None)
if hasattr(self, "_app") and self._app and (last is None or now - last >= min_interval):
self._last_invalidate = now
self._app_invalidate(self._app, "invalidate", swallow=False)
@@ -138,7 +142,13 @@ class CLITerminalMixin:
stacks on stale content (#60920, #25337); terminals without it never emit ``CSI I``.
"""
now = time.monotonic()
if now - getattr(self, "_last_focus_regain_redraw", 0.0) < min_interval:
# Sentinel is None, not 0.0: time.monotonic() counts from an arbitrary epoch
# (boot on Linux). On a fresh VM (CI runners, containers) ``now`` can be smaller
# than ``min_interval``, and ``now - 0.0 < min_interval`` would suppress the
# FIRST redraw ever requested (CI run 32494557030: uptime < 60s made the
# min_interval=60 rate-limit test fail both attempts).
last = getattr(self, "_last_focus_regain_redraw", None)
if last is not None and now - last < min_interval:
return
self._last_focus_regain_redraw = now
self._force_full_redraw()