- Replaced Reflect.deleteProperty teardown with the descriptor-preserving restoreProperty pattern used by the other ProcessTerminal suites, so real isTTY/setRawMode/columns/rows own-properties survive on TTY hosts and later test files are not poisoned.
The private-CSI reassembly gate and the DA1 swallow were both guarded by
`#da1SentinelOwners.length > 0`, so a Device-Attributes reply that arrived
after the startup capability-probe sentinel FIFO drained fell through to the
input handler and leaked into the composer as literal text (e.g.
`1;22;...;52c`). The extra latency of an SSH/zmx PTY chain makes the race
observable.
`CSI ? ... c` and split private-CSI responses are terminal->host reports,
never keystrokes, so they are now consumed regardless of whether a sentinel
is still outstanding.
Fixes#8542
- Replaced time-based sleeps and polling loops with event-driven promise resolvers and fake timers across agent and tool tests.
- Migrated test suites to share in-memory auth storage and fixtures using lifecycle hooks.
- Updated catalog model definitions, metadata, and configurations.
The deterministic replay oracle only models in-place resize for tmux and
direct HerdR, but an inherited PI_TUI_RESIZE_IN_PLACE=1 makes the runtime
treat every scenario as in-place and desyncs the oracle. Add the key to
the stress env patch so a developer's override cannot leak into replay.
The HerdR flicker fix routed direct HerdR panes onto the in-place
multiplexer resize path, but the randomized render-stress oracle still
modeled them as ED3 replaying direct terminals. The width-epoch ledger
now applies to any in-place-resize scenario (multiplexer + direct HerdR)
via a dedicated resizeRepaintsInPlace trait, keeping HerdR's direct
scrollback semantics intact. Adds a deterministic replay regression
(seed 0xcafed00d, 24 iterations) that fails without the oracle update.
The watchdog discarded every overshoot longer than `sleepMs` (60s) as
system sleep, on the rationale that "the process could not have run JS
during the missed interval". That is true for a suspended process and
false for a CPU-bound wedge, which is exactly the case where JS ran the
whole interval at 100% CPU.
Duration cannot separate the two: both produce an arbitrarily large gap.
Keying the suppression on magnitude therefore dropped the most severe
stalls and kept only the mild ones, so the probe went quiet precisely
when it had something to report. Issue #5372 shows an 82,391ms block that
16.4.8 logged and current builds do not.
Classify by mechanism instead. `cpuNow()` reads process CPU time, and an
over-`sleepMs` gap is suppressed only when the process also burned less
than half of it on CPU. A resumed process shows a gap it did not spend
CPU on; a wedged one shows a gap it spent almost entirely on CPU. The
observed CPU time is included in the log line so a reader can tell which
kind of stall they are looking at.
Refs #5372, #7328, #6145
Direct HerdR panes no longer clear/replay via ED3 on resize; the
scenario description still claimed the old behavior. Aligns the comment
with PR #8433.
Revert the unrelated object-literal reflow bundled into the PR merge,
keeping only the direct-HerdR in-place resize routing, its tests, and
docs. PR #8433 (@roboomp).
Scoped direct Herdr multiplexer behavior to resize repaint selection so explicit transcript replacements continue to clear and replay scrollback.
Added coverage for resize stability and resetDisplay ED3 behavior.
Kept direct Herdr panes on the host-safe in-place resize path so streaming redraws no longer clear and replay pane scrollback.
Updated the resize regression, stress scenario, renderer docs, and changelog.
Fixes#8431
- Remove redundant definedness, null, and type checks across test suites in multiple packages.
- Clean up unused assertions, metadata tests, and obsolete test cases.
- Add good versus bad test filter guidelines and requirements to project documentation.
- The mux pane-growth oracle treated every physical scroll as a logical append, but immutable-history recovery can recommit a corrected suffix after an off-screen mutation without advancing the shadow tape; exempt only changed shared history prefixes.
- The frame-neutral oracle compared prepared rows only; at narrow widths distinct raw rows prepare identically, so the renderer's raw-prefix divergence recovery recommits legitimately. Snapshot raw frames and allow declared transient growth.
- OSC66 spacer preservation intentionally composes six bounded context rows above the resize viewport; assert that exact bound instead of zero above-fold rendering.
Both oracle false positives reproduce identically at the PR head that introduced the harness (4cc9725037); three full randomized stress passes green after the fix.
The resize fast path composed only the visible window, so a blank first row
whose scaled OSC 66 heading had scrolled just above the fold could not be
recognized and was erased, clearing the glyph's lower half until the settle
repaint (a resize flicker into the invisible-placeholder state).
#composeResizeViewport now collects a bounded band of context rows above the
fold (up to the protocol's max reserved-row count) and returns the visible
window preceded by that context in frame order; #emitResizeViewport resolves
each spacer width against the framed array. Add a regression driving a width
drag with the heading one row above the viewport top.
The seam rewrite detected spacer rows in its window-local slice. When a
heading committed in the chunk loop and its reserved row became window[0],
that lookup could not see the heading at frame[windowTop - 1] and erased the
glyph's lower half.
Resolve window spacer widths against full-frame coordinates, matching the
full-paint path. Add a regression where a streamed heading crosses the commit
seam and its spacer is the first visible window row.
The reserved spacer row beneath a scaled heading previously emitted nothing,
so a row reflowing from wider text into that position left stale cells to the
right of the (shorter) glyph — the heading write only covers the glyph's own
columns. Preserve columns [0, glyphWidth) and erase to end of line from there:
the glyph's lower half survives while stale cells are cleared instead of
lingering or scrolling into history.
#isOsc66SpacerRow now returns the glyph width to preserve (#osc66SpacerGlyphWidth,
-1 when not a reserved row); #lineRewriteSequence emits reset + CUF(glyphWidth) +
erase-to-end for those rows.
The "Large Headings" feature renders Markdown H1 at 2x via the Kitty OSC 66
text-sizing protocol; a scale-s heading is s rows tall, so the s-1 blank rows
beneath it hold the multicell glyph's lower half. The render engine gave Kitty
image lines a dedicated re-emit path but had no OSC 66 awareness, so every
repaint through #lineRewriteSequence (incremental diff, full replay, resize
viewport) rewrote those reserved rows as reset + erase-to-end-of-line, clearing
the glyph and leaving reserved-but-invisible space.
Detect reserved rows from the heading's s= scale (#isOsc66SpacerRow) and emit
them untouched across every repaint path, covering all s-1 rows for scale >= 3.
Consolidate isOsc66Line into pi-tui/utils alongside a new osc66MaxScale.
Fixes#8318