test(tui): model mux pane growth in the render-stress shadow ledger
- The shadow oracle floored windowTop at the committed seam unconditionally, predicting a top-anchored view with a blank bottom row when a tmux pane grows taller. Real tmux (screen_resize_y) and the harness's emulated terminal pull rows back out of pane history into the grid, and the renderer already rebases its commit seam accordingly (tui.ts pane-growth path); repainting top-anchored there would overwrite the resurrected row. The ledger now mirrors the seam rebase on geometry frames where frameLength - height < committed, keeping the invariant an exact-view check.
- Deterministic repro: darwin-normal-tmux-small seed=0x0ddc0ffe op 24 (resizeHeight 3->4); pre-existing on 7b141199d5, previously masked because the stress suite is skipIf(CI).
This commit is contained in:
@@ -2590,15 +2590,29 @@ class StressDriver {
|
||||
}
|
||||
// Audit and shrink re-anchoring are mirrored at render time (they can
|
||||
// fire on zero-byte frames); the write hook only applies commits.
|
||||
const windowTop = Math.max(this.#shadowCommitted, length - height, 0);
|
||||
this.#shadowWindowTop = windowTop;
|
||||
const tail = Math.max(0, length - height);
|
||||
// Overlays and multiplexer geometry frames freeze commits; a geometry
|
||||
// frame also re-bases the raw prefix at the new width (accepted wrap
|
||||
// drift, mirrored from the engine).
|
||||
if (this.#shadowFrameGeometryChanged) {
|
||||
if (tail < this.#shadowCommitted) {
|
||||
// Pane growth pulls committed rows back out of multiplexer
|
||||
// scrollback into the grid (tmux screen_resize_y takes lines
|
||||
// from pane history when the screen grows; the emulated
|
||||
// terminal does the same). The engine mirrors that by rebasing
|
||||
// its commit seam to the exposed frame tail and force-rewriting
|
||||
// the whole window (tui.ts geometry-growth branch) — un-commit
|
||||
// the resurrected rows here so the ledger agrees.
|
||||
const pulled = this.#shadowCommitted - tail;
|
||||
this.#shadowTape.length = Math.max(0, this.#shadowTape.length - pulled);
|
||||
this.#shadowCommitted = tail;
|
||||
}
|
||||
this.#shadowWindowTop = Math.max(this.#shadowCommitted, tail);
|
||||
this.#shadowRawPrefix = raw.slice(0, this.#shadowCommitted);
|
||||
return;
|
||||
}
|
||||
const windowTop = Math.max(this.#shadowCommitted, tail);
|
||||
this.#shadowWindowTop = windowTop;
|
||||
if (this.#shadowFrameOverlay) return;
|
||||
const chunkTo = Math.max(this.#shadowCommitted, Math.min(length, windowTop));
|
||||
for (let i = this.#shadowCommitted; i < chunkTo; i++) {
|
||||
|
||||
Reference in New Issue
Block a user