Window the retained-tail redraw path to the cursor's reach

Attribution (findings log 2026-07-03): main's onPtyData consumed ~93% of
the event loop under an agent-TUI flood, and the dominant term was
appendNormalizedToMultilineTailBuffer + finalizeRetainedTerminalRows
materializing ~2x tail-length row objects plus a per-row trailing-space
regex on every chunk — 0.888ms/chunk at the 2,000-line cap, on every
Claude-Code-shaped frame (cursor-up + erase-below).

The multiline algorithm now runs on a suffix window sized by the chunk's
maximum upward cursor excursion (plus the inherited redraw cursor and a
safety margin); the untouched prefix is shared by reference with a cheap
last-char trailing-space check to match the reference trim. Pathological
full-height cursor-ups fall back to the unwindowed implementation, which
is kept verbatim and exported as the reference for the 500-case
differential fuzz (retained-tail-redraw-window.equivalence.test.ts).

Micro-bench at a full 2,000-line tail: 0.888 -> 0.073 ms/chunk (12x).
1,415 runtime tests green, typecheck clean.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-07-02 22:54:42 -04:00
co-authored by Orca
parent 59316c40bc
commit 4e08a28cdf
2 changed files with 187 additions and 0 deletions
+97
View File
@@ -22277,6 +22277,30 @@ function trimTerminalLineRight(line: string): string {
return end === line.length ? line : line.slice(0, end) return end === line.length ? line : line.slice(0, end)
} }
// Why a window: the unwindowed implementation below materializes a row object
// per retained tail line and finalize re-allocates + regex-trims every row —
// O(tail) per chunk (~0.9ms at the 2,000-line cap), measured at ~93% of the
// main-process event loop under an agent-TUI flood (findings log 2026-07-03).
// A redraw can only touch rows the cursor can reach, so run the algorithm on
// a suffix window sized by the chunk's maximum upward cursor excursion and
// share the untouched prefix by reference. Equality with the unwindowed
// implementation is fuzz-verified in
// retained-tail-redraw-window.equivalence.test.ts.
const REDRAW_WINDOW_SAFETY_ROWS = 8
function maxUpwardCursorReach(
normalizedChunk: string,
previousRedrawCursor: RetainedTailRedrawCursor | null
): number {
let reach = previousRedrawCursor ? previousRedrawCursor.rowFromEnd : 0
const cursorUpPattern = /\x1b\[(\d*)(?:;[\d;]*)?A/g
let match: RegExpExecArray | null
while ((match = cursorUpPattern.exec(normalizedChunk)) !== null) {
reach += match[1] ? Number.parseInt(match[1], 10) : 1
}
return reach
}
function appendNormalizedToMultilineTailBuffer( function appendNormalizedToMultilineTailBuffer(
previousLines: string[], previousLines: string[],
boundedPreviousPartialLine: string, boundedPreviousPartialLine: string,
@@ -22289,6 +22313,79 @@ function appendNormalizedToMultilineTailBuffer(
redrawCursor: RetainedTailRedrawCursor | null redrawCursor: RetainedTailRedrawCursor | null
truncated: boolean truncated: boolean
newCompleteLines: number newCompleteLines: number
} {
const windowRows =
maxUpwardCursorReach(normalizedChunk, previousRedrawCursor) + REDRAW_WINDOW_SAFETY_ROWS
if (windowRows >= previousLines.length) {
return appendNormalizedToMultilineTailBufferUnwindowed(
previousLines,
boundedPreviousPartialLine,
normalizedChunk,
previousPartialWasCapped,
previousRedrawCursor
)
}
const prefixLength = previousLines.length - windowRows
const suffix = previousLines.slice(prefixLength)
const windowed = appendNormalizedToMultilineTailBufferUnwindowed(
suffix,
boundedPreviousPartialLine,
normalizedChunk,
previousPartialWasCapped,
previousRedrawCursor
)
let lines = previousLines.slice(0, prefixLength)
// Why: the unwindowed finalize trims trailing spaces/tabs on every row; the
// shared prefix must match without paying a regex per untouched row.
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index]!
const lastChar = line.charCodeAt(line.length - 1)
if (lastChar === 32 || lastChar === 9) {
lines[index] = line.replace(/[ \t]+$/g, '')
}
}
for (const line of windowed.lines) {
lines.push(line)
}
let truncated = windowed.truncated
if (lines.length > MAX_TAIL_LINES) {
lines = lines.slice(lines.length - MAX_TAIL_LINES)
truncated = true
}
let totalChars = windowed.partialLine.length
for (const line of lines) {
totalChars += line.length
}
let dropCount = 0
while (dropCount < lines.length && totalChars > MAX_TAIL_CHARS) {
totalChars -= lines[dropCount]!.length
dropCount += 1
}
if (dropCount > 0) {
lines = lines.slice(dropCount)
truncated = true
}
return {
lines,
partialLine: windowed.partialLine,
redrawCursor: windowed.redrawCursor,
truncated,
newCompleteLines: windowed.newCompleteLines
}
}
export function appendNormalizedToMultilineTailBufferUnwindowed(
previousLines: string[],
boundedPreviousPartialLine: string,
normalizedChunk: string,
previousPartialWasCapped: boolean,
previousRedrawCursor: RetainedTailRedrawCursor | null
): {
lines: string[]
partialLine: string
redrawCursor: RetainedTailRedrawCursor | null
truncated: boolean
newCompleteLines: number
} { } {
const rows: RetainedTerminalRow[] = [ const rows: RetainedTerminalRow[] = [
...previousLines.map((line) => ({ text: line, completed: true })), ...previousLines.map((line) => ({ text: line, completed: true })),
@@ -0,0 +1,90 @@
import { describe, expect, it } from 'vitest'
import {
appendNormalizedToTailBuffer,
appendNormalizedToMultilineTailBufferUnwindowed
} from './orca-runtime'
// Differential guard for the windowed redraw tail path: the public
// appendNormalizedToTailBuffer routes vertical-control chunks through a
// suffix-windowed wrapper (findings log 2026-07-03 — the unwindowed path was
// O(tail) per chunk and dominated main's event loop under agent-TUI floods).
// This fuzz asserts the windowed result is byte-identical to the reference
// implementation across randomized tails and redraw chunks.
function mulberry32(seed: number): () => number {
let a = seed >>> 0
return () => {
a = (a + 0x6d2b79f5) | 0
let t = Math.imul(a ^ (a >>> 15), 1 | a)
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
function randomTail(rng: () => number, maxLines: number): string[] {
const count = Math.floor(rng() * maxLines)
return Array.from({ length: count }, (_, i) => {
const base = `line ${i} ${'x'.repeat(Math.floor(rng() * 40))}`
// Trailing whitespace included deliberately: the reference implementation
// trims every row on each call, so the windowed prefix must match.
return rng() < 0.3 ? `${base} ` : base
})
}
function randomRedrawChunk(rng: () => number): string {
const parts: string[] = []
const ops = 1 + Math.floor(rng() * 12)
for (let i = 0; i < ops; i++) {
const roll = rng()
if (roll < 0.2) {
parts.push(`\x1b[${1 + Math.floor(rng() * 12)}A`)
} else if (roll < 0.3) {
parts.push(`\x1b[${Math.floor(rng() * 3)}J`)
} else if (roll < 0.4) {
parts.push(`\x1b[${Math.floor(rng() * 3)}K`)
} else if (roll < 0.5) {
parts.push('\r')
} else if (roll < 0.6) {
parts.push(`\x1b[${1 + Math.floor(rng() * 30)}G`)
} else if (roll < 0.7) {
parts.push('\n')
} else if (roll < 0.75) {
parts.push('')
} else {
parts.push(`text${Math.floor(rng() * 100)} ${'y'.repeat(Math.floor(rng() * 20))}`)
}
}
return parts.join('')
}
describe('windowed redraw tail equivalence', () => {
it('matches the unwindowed reference across 500 randomized cases', () => {
const rng = mulberry32(42)
for (let round = 0; round < 500; round++) {
const tail = randomTail(rng, round % 5 === 0 ? 2100 : 300)
const partial = rng() < 0.5 ? `partial ${'z'.repeat(Math.floor(rng() * 30))}` : ''
const redrawCursor =
rng() < 0.3 ? { rowFromEnd: Math.floor(rng() * 20), column: Math.floor(rng() * 40) } : null
// Why the guaranteed cursor-up: the public function routes to the
// multiline (windowed) path only for vertical-control chunks; chunks
// without one take the single-line fast path, which is out of scope.
const chunk = `\x1b[${1 + Math.floor(rng() * 4)}A${randomRedrawChunk(rng)}`
const actual = appendNormalizedToTailBuffer(tail, partial, chunk, redrawCursor)
// Reference path over the full tail.
const expected = appendNormalizedToMultilineTailBufferUnwindowed(
tail,
partial.slice(-4000),
chunk,
partial.length > 4000,
redrawCursor
)
expect(actual.lines, `round ${round} lines`).toEqual(expected.lines)
expect(actual.partialLine, `round ${round} partial`).toBe(expected.partialLine)
expect(actual.redrawCursor, `round ${round} cursor`).toEqual(expected.redrawCursor)
expect(actual.truncated, `round ${round} truncated`).toBe(expected.truncated)
expect(actual.newCompleteLines, `round ${round} newLines`).toBe(expected.newCompleteLines)
}
})
})