test: isolate flood restoration and retained provider fixes together

This commit is contained in:
Neil
2026-09-05 22:15:17 -07:00
parent e72b63ec15
commit 8d5247be24
3 changed files with 100 additions and 12 deletions
@@ -0,0 +1,79 @@
import { describe, expect, it, vi } from 'vitest'
import { createRuntime, syncSinglePty } from './orca-runtime-test-fixtures.spec'
describe('hidden-output recovery after provider reattach', () => {
it('uses retained provider modes instead of the pre-attach redraw suffix', async () => {
const runtime = createRuntime()
const serializeProviderBuffer = vi.fn(async () => ({
data: '\x1b[?1049hRetained TUI',
cols: 100,
rows: 30,
seq: 1000,
source: 'headless' as const,
alternateScreen: true
}))
runtime.setPtyController({
write: () => true,
kill: () => true,
getForegroundProcess: async () => null,
serializeProviderBuffer
})
syncSinglePty(runtime, 'pty-1')
runtime.onPtyData('pty-1', '\x1b[HRedraw without the original alternate-screen entry', 60)
runtime.synchronizePtyOutputSequenceFromProvider('pty-1', {
value: 1000,
generation: 'continued'
})
const snapshot = await runtime.serializeHiddenOutputRecoveryBuffer('pty-1', {
scrollbackRows: 5000
})
expect(snapshot).toMatchObject({ data: '\x1b[?1049hRetained TUI', alternateScreen: true })
expect(serializeProviderBuffer).toHaveBeenCalledWith('pty-1', { scrollbackRows: 5000 })
})
it('keeps the renderer fallback for providers without retained snapshots', async () => {
const runtime = createRuntime()
runtime.onPtyData('pty-1', 'partial redraw', 14)
runtime.synchronizePtyOutputSequenceFromProvider('pty-1', {
value: 1000,
generation: 'continued'
})
const serializeBuffer = vi.fn(async () => ({
data: '\x1b[?1049hRenderer TUI',
cols: 100,
rows: 30
}))
runtime.setPtyController({
write: () => true,
kill: () => true,
getForegroundProcess: async () => null,
hasRendererSerializer: () => true,
serializeBuffer
})
await expect(runtime.serializeHiddenOutputRecoveryBuffer('pty-1')).resolves.toMatchObject({
data: '\x1b[?1049hRenderer TUI',
source: 'renderer'
})
})
it('keeps an authoritative main model without polling the provider', async () => {
const runtime = createRuntime()
const serializeProviderBuffer = vi.fn(async () => null)
runtime.setPtyController({
write: () => true,
kill: () => true,
getForegroundProcess: async () => null,
serializeProviderBuffer
})
runtime.onPtyData('pty-1', '\x1b[?1049hLive TUI', 20)
await expect(runtime.serializeHiddenOutputRecoveryBuffer('pty-1')).resolves.toMatchObject({
alternateScreen: true,
source: 'headless'
})
expect(serializeProviderBuffer).not.toHaveBeenCalled()
})
})
@@ -47,6 +47,10 @@ export class OrcaRuntimeWithSerializeMainTerminalBuffer extends OrcaRuntimeWithA
pendingEscapeTailAnsi?: string
terminalOwner?: 'shell'
} | null> {
const restoredSnapshot = await this.serializePreferredRestoredTerminalBuffer(ptyId, opts)
if (restoredSnapshot) {
return restoredSnapshot
}
const headlessSnapshot = await this.serializeHeadlessTerminalBuffer(ptyId, {
...opts,
includeEmpty: true
@@ -23,18 +23,9 @@ export class OrcaRuntimeWithSerializeTerminalBufferFromAvailableState extends Or
kittyKeyboardFlags?: number
terminalOwner?: 'shell'
} | null> {
if (this.providerSnapshotPreferredPtys.has(ptyId)) {
// Why: pre-attach stream bytes only form a suffix of restored state. A
// sequenced provider snapshot safely reconciles live bytes; renderer is
// the fallback when an older provider cannot expose that boundary.
const providerSnapshot = await this.serializeProviderTerminalBuffer(ptyId, opts)
if (providerSnapshot) {
return providerSnapshot
}
const rendererSnapshot = await this.serializeRendererTerminalBuffer(ptyId, opts)
if (rendererSnapshot) {
return rendererSnapshot
}
const restoredSnapshot = await this.serializePreferredRestoredTerminalBuffer(ptyId, opts)
if (restoredSnapshot) {
return restoredSnapshot
}
const headlessSnapshot = await this.serializeHeadlessTerminalBuffer(ptyId, opts)
if (headlessSnapshot) {
@@ -58,6 +49,20 @@ export class OrcaRuntimeWithSerializeTerminalBufferFromAvailableState extends Or
: rendererSnapshot
}
protected async serializePreferredRestoredTerminalBuffer(
ptyId: string,
opts: { scrollbackRows?: number } = {}
) {
if (!this.providerSnapshotPreferredPtys.has(ptyId)) {
return null
}
// Pre-attach bytes are only a suffix; older providers can fall back to the renderer.
return (
(await this.serializeProviderTerminalBuffer(ptyId, opts)) ??
(await this.serializeRendererTerminalBuffer(ptyId, opts))
)
}
async serializeRendererTerminalBuffer(
ptyId: string,
opts: { scrollbackRows?: number } = {}