mirror of
https://github.com/stablyai/orca.git
synced 2026-10-29 08:07:18 +00:00
test(terminal): pin the quarantine cap's accepted cost; correct its fresh-shell claims (STA-2373)
The idle-gap test claimed a fresh command is never eaten, but the idle gate cannot release the first quarantined byte, so a command typed inside the cap is dropped in full. Pin that real behavior and the reason the cap stays 5s. A write rejection means the endpoint stopped accepting writes; the daemon respawns only on a daemon-gone error, so a transient socket drop reconnects to the same sessions. Stop asserting reattach always lands on a fresh shell.
This commit is contained in:
@@ -3638,8 +3638,9 @@ export function connectPanePty(
|
|||||||
// cooldown window while typing. Local panes keep the lenient gate.
|
// cooldown window while typing. Local panes keep the lenient gate.
|
||||||
requireAuthoritativeLiveness:
|
requireAuthoritativeLiveness:
|
||||||
Boolean(transport.getConnectionId?.()) || isRemoteRuntimePtyId(undeliverablePtyId),
|
Boolean(transport.getConnectionId?.()) || isRemoteRuntimePtyId(undeliverablePtyId),
|
||||||
// Why only the rejected path: a stalled-pipeline remount reattaches to the
|
// Why only the rejected path: it is the only one whose remount can land on
|
||||||
// same shell, so its half-typed line is still on screen and intact.
|
// a fresh shell. A stalled-pipeline remount always reattaches to the same
|
||||||
|
// shell, so its half-typed line is still on screen and intact.
|
||||||
endpointReplaced: providerRejected
|
endpointReplaced: providerRejected
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ describe('terminal input quarantine', () => {
|
|||||||
expect(isTerminalInputQuarantined(TAB)).toBe(false)
|
expect(isTerminalInputQuarantined(TAB)).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('releases on an idle gap so a fresh command is never eaten', () => {
|
it('releases on an idle gap once a quarantined byte has been seen', () => {
|
||||||
armTerminalInputQuarantine(TAB, 0)
|
armTerminalInputQuarantine(TAB, 0)
|
||||||
// Burst tail, no Enter — the user was still mid-line when the endpoint died.
|
// Burst tail, no Enter — the user was still mid-line when the endpoint died.
|
||||||
expect(shouldDropQuarantinedTerminalInput(TAB, 'c', REATTACH_MS)).toBe(true)
|
expect(shouldDropQuarantinedTerminalInput(TAB, 'c', REATTACH_MS)).toBe(true)
|
||||||
@@ -66,6 +66,22 @@ describe('terminal input quarantine', () => {
|
|||||||
expect(isTerminalInputQuarantined(TAB)).toBe(false)
|
expect(isTerminalInputQuarantined(TAB)).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// The accepted cost of the cap, pinned so it is not "fixed" by shortening it:
|
||||||
|
// over-quarantine is visible (nothing echoes) and recoverable by retyping,
|
||||||
|
// while under-quarantine executes half a command. A tail takes seconds to
|
||||||
|
// type, so a cap short enough to spare this command would cut that tail
|
||||||
|
// mid-line and deliver its remainder to the fresh shell.
|
||||||
|
it('eats a fresh command typed inside the cap, terminator included', () => {
|
||||||
|
armTerminalInputQuarantine(TAB, 0)
|
||||||
|
// No byte yet, so the idle gate cannot release the first keystroke however
|
||||||
|
// long the user waited; from there normal typing never opens a 700ms gap.
|
||||||
|
let at = 1_500
|
||||||
|
for (const char of 'ls -la\r') {
|
||||||
|
expect(shouldDropQuarantinedTerminalInput(TAB, char, at)).toBe(true)
|
||||||
|
at += 150
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('does not let the idle gate fire on the re-attach delay itself', () => {
|
it('does not let the idle gate fire on the re-attach delay itself', () => {
|
||||||
armTerminalInputQuarantine(TAB, 0)
|
armTerminalInputQuarantine(TAB, 0)
|
||||||
// First quarantined byte arrives well past the idle window, because the
|
// First quarantined byte arrives well past the idle window, because the
|
||||||
|
|||||||
@@ -38,10 +38,11 @@ type RecoveryRequest = {
|
|||||||
* registry doesn't own, and treating null as "proceed" would let a
|
* registry doesn't own, and treating null as "proceed" would let a
|
||||||
* disconnected remote pane churn reconnects on every cooldown window. */
|
* disconnected remote pane churn reconnects on every cooldown window. */
|
||||||
requireAuthoritativeLiveness?: boolean
|
requireAuthoritativeLiveness?: boolean
|
||||||
/** The provider rejected the write because its endpoint died, so re-attach
|
/** The provider rejected the write because its endpoint stopped accepting
|
||||||
* lands on a *fresh* shell. Only then is the in-flight line mangled, and
|
* writes, so re-attach MAY land on a *fresh* shell (a respawn; a transient
|
||||||
* only then may input be quarantined — a recovery that keeps the same live
|
* socket drop reconnects to the same sessions). Only this path can mangle the
|
||||||
* shell would have a legitimate command eaten. */
|
* in-flight line, and only it may quarantine input — a recovery that always
|
||||||
|
* keeps the same live shell would have a legitimate command eaten. */
|
||||||
endpointReplaced?: boolean
|
endpointReplaced?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user