mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test: tighten relay assertions and repair benchmark checks (#33573)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
// Compare repeated per-registration/event NFC normalization with pre-normalized root matchers/event paths for SSH watcher batches.
|
||||
// Model repeated per-root/event normalization versus hoisted root matchers/event paths for SSH watcher batches.
|
||||
// Assert identical routed results before timing and import production normalizer so folding drift cannot invalidate measurement.
|
||||
import assert from 'node:assert/strict'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { createJiti } from 'jiti'
|
||||
|
||||
const REPO_ROOT = fileURLToPath(new URL('../..', import.meta.url))
|
||||
const ITERATIONS = Number(process.env.ORCA_SSH_WATCH_BENCH_ITERATIONS ?? '200')
|
||||
@@ -19,25 +20,15 @@ for (const [name, value] of [
|
||||
}
|
||||
}
|
||||
|
||||
// Recheck production normalization source: if NFC fold/cost changes, benchmark’s assumption no longer holds.
|
||||
const PATH_SOURCE = readFileSync(
|
||||
new URL('../../src/shared/cross-platform-path.ts', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
for (const marker of ['normalize(', 'createNormalizedPathInsideOrEqualMatcher']) {
|
||||
if (!PATH_SOURCE.includes(marker)) {
|
||||
throw new Error(`cross-platform-path.ts no longer contains ${marker}; this benchmark is stale`)
|
||||
}
|
||||
}
|
||||
|
||||
// Import the real normalizer so both arms fold paths exactly as production does.
|
||||
// Jiti resolves the production graph’s extensionless TypeScript imports.
|
||||
const jiti = createJiti(import.meta.url)
|
||||
const {
|
||||
normalizeRuntimePathForComparison,
|
||||
isPathInsideOrEqual,
|
||||
createNormalizedPathInsideOrEqualMatcher
|
||||
} = await import(new URL('../../src/shared/cross-platform-path.ts', import.meta.url).href)
|
||||
} = await jiti.import('../../src/shared/cross-platform-path.ts')
|
||||
|
||||
// Pre-fix: mirrors the original routeSshFilesystemWatchNotification inner loop.
|
||||
// Historical per-pair normalization model.
|
||||
function routeBefore(roots, events, sink) {
|
||||
for (const rootPath of roots) {
|
||||
const matching = events.filter((event) => isPathInsideOrEqual(rootPath, event.absolutePath))
|
||||
@@ -47,7 +38,7 @@ function routeBefore(roots, events, sink) {
|
||||
}
|
||||
}
|
||||
|
||||
// Post-fix: mirrors the current implementation.
|
||||
// Synthetic hoisted-normalization model; this does not invoke the application router.
|
||||
function routeAfter(roots, events, sink) {
|
||||
const normalizedEvents = events.map((event) => ({
|
||||
event,
|
||||
@@ -65,13 +56,14 @@ function routeAfter(roots, events, sink) {
|
||||
}
|
||||
|
||||
// Use real paths: length/segments determine normalization cost, which short synthetic paths understate.
|
||||
const REPO_PATHS = execFileSync('git', ['ls-files'], {
|
||||
const REPO_PATHS = execFileSync('git', ['ls-files', '-z'], {
|
||||
cwd: REPO_ROOT,
|
||||
maxBuffer: 256 * 1024 * 1024
|
||||
})
|
||||
.toString()
|
||||
.split('\n')
|
||||
.split('\0')
|
||||
.filter(Boolean)
|
||||
assert.ok(REPO_PATHS.length > 0, 'Benchmark needs tracked paths')
|
||||
|
||||
// Model multi-worktree host with explorer and base-directory watchers per root.
|
||||
function makeRoots(count) {
|
||||
@@ -93,10 +85,8 @@ function makeEvents(roots, count) {
|
||||
|
||||
function collect(roots, events, route) {
|
||||
const seen = []
|
||||
route(roots, events, (rootPath, matching) =>
|
||||
seen.push(`${rootPath} ${matching.map((event) => event.absolutePath).join(',')}`)
|
||||
)
|
||||
return seen.join('\n')
|
||||
route(roots, events, (rootPath, matching) => seen.push([rootPath, matching]))
|
||||
return seen
|
||||
}
|
||||
|
||||
// Interleave rounds and compare medians to share CPU/load drift; batch ordering alone varied observed win from 6.7x to 23.3x.
|
||||
@@ -145,12 +135,11 @@ for (const [rootCount, eventCount] of [
|
||||
const events = makeEvents(roots, eventCount)
|
||||
const before = collect(roots, events, routeBefore)
|
||||
const after = collect(roots, events, routeAfter)
|
||||
if (before !== after) {
|
||||
throw new Error(`routing differs at ${rootCount} roots x ${eventCount} events`)
|
||||
}
|
||||
if (!before.includes(' ')) {
|
||||
throw new Error(`fixture routed nothing at ${rootCount} roots x ${eventCount} events`)
|
||||
}
|
||||
assert.deepEqual(after, before, `routing differs at ${rootCount} roots x ${eventCount} events`)
|
||||
assert.ok(
|
||||
before.length > 0,
|
||||
`fixture routed nothing at ${rootCount} roots x ${eventCount} events`
|
||||
)
|
||||
const { beforeMs, afterMs } = measureInterleaved(roots, events)
|
||||
console.log(
|
||||
`${pad(rootCount, 6)} ${pad(eventCount, 7)} ${pad(`${beforeMs.toFixed(3)} ms`, 11)} ${pad(`${afterMs.toFixed(3)} ms`, 11)} ${pad(`${(beforeMs / afterMs).toFixed(1)}x`, 9)}`
|
||||
@@ -158,5 +147,5 @@ for (const [rootCount, eventCount] of [
|
||||
}
|
||||
|
||||
console.log(
|
||||
'\nThis times routing only. The saving scales with roots x events, so it is small\nfor a single-worktree session and largest during a remote checkout storm, which\nis exactly when the main process is already busy.'
|
||||
'\nThis times synthetic routing models with production path normalization.\nIt excludes application dispatch, relay transport, and filesystem work.'
|
||||
)
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
#!/usr/bin/env node
|
||||
// Compare replay signal’s old CSI scan with shipped 256KB-tail/shared-regex path; assert equivalence before timing deterministic seeded payloads.
|
||||
// Also measure Kitty-mode scan unchanged and with slower includes prefilter; run node config/scripts/terminal-reattach-payload-scan-benchmark.mjs.
|
||||
import assert from 'node:assert/strict'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { CSI_SEQUENCE_PATTERN } from '../../src/shared/ansi-escape-sequences.ts'
|
||||
import { TerminalKittyKeyboardModeTracker } from '../../src/shared/terminal-kitty-keyboard-mode-tracker.ts'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { createJiti } from 'jiti'
|
||||
|
||||
const jiti = createJiti(import.meta.url, {
|
||||
alias: { '@': fileURLToPath(new URL('../../src/renderer/src', import.meta.url)) }
|
||||
})
|
||||
const { CSI_SEQUENCE_PATTERN } = await jiti.import('../../src/shared/ansi-escape-sequences.ts')
|
||||
const { TerminalKittyKeyboardModeTracker } = await jiti.import(
|
||||
'../../src/shared/terminal-kitty-keyboard-mode-tracker.ts'
|
||||
)
|
||||
const { hasCursorAgentReattachPayloadScreenSignal: signalSuffixRegex } = await jiti.import(
|
||||
'../../src/renderer/src/components/terminal-pane/pty-connection/cursor-agent-reattach-screen.ts'
|
||||
)
|
||||
|
||||
const ROUNDS = Number(process.env.ORCA_REATTACH_SCAN_BENCH_ROUNDS ?? '7')
|
||||
const MIN_ITERATION_MS = 120
|
||||
@@ -86,7 +98,7 @@ function buildPayloads() {
|
||||
]
|
||||
}
|
||||
|
||||
// Baseline: verbatim copy of pty-connection.ts:448 (not exported).
|
||||
// Historical full-payload CSI character scan for comparison.
|
||||
function stripBaseline(data) {
|
||||
let normalized = ''
|
||||
let index = 0
|
||||
@@ -112,13 +124,9 @@ const stripRegex = (data) => data.replace(CSI_SEQUENCE_PATTERN, '')
|
||||
|
||||
const HEADER = 'Cursor Agent'
|
||||
const TAIL_CHARS = 5000
|
||||
// Mirrors CURSOR_AGENT_REATTACH_SCAN_TAIL_LIMIT_CHARS in pty-connection.ts.
|
||||
const SUFFIX_RAW_CHARS = 256 * 1024
|
||||
|
||||
const signalBaseline = (data) => hasSignal(stripBaseline(data))
|
||||
const signalRegex = (data) => hasSignal(stripRegex(data))
|
||||
const signalSuffixRegex = (data) =>
|
||||
hasSignal(stripRegex(data.length > SUFFIX_RAW_CHARS ? data.slice(-SUFFIX_RAW_CHARS) : data))
|
||||
|
||||
function hasSignal(normalized) {
|
||||
const headerIndex = normalized.lastIndexOf(HEADER)
|
||||
@@ -197,12 +205,13 @@ const kittyScan = (data) => {
|
||||
}
|
||||
// The includes() introducer pre-filter a daemon-side mode scan would use.
|
||||
const kittyGated = (data) => {
|
||||
if (!data.includes('\x1b[?') && !data.includes('\x1bc') && !data.includes('\x9b')) {
|
||||
if (!data.includes('\x1b[') && !data.includes('\x1bc') && !data.includes('\x9b')) {
|
||||
return 0
|
||||
}
|
||||
return kittyScan(data)
|
||||
}
|
||||
for (const { name, data } of payloads) {
|
||||
assert.equal(kittyGated(data), kittyScan(data), `Kitty gate disagrees on ${name}`)
|
||||
console.log(
|
||||
`${pad(name, 36)} ${pad(kb(data), 8)} ${pad(measure(kittyScan, data).toFixed(3), 11)} ${pad(measure(kittyGated, data).toFixed(3), 15)}`
|
||||
)
|
||||
@@ -212,19 +221,22 @@ for (const { name, data } of payloads) {
|
||||
const liveChunk = buildColoredScrollback(4 * 1024, 5).replaceAll('\x1b', '')
|
||||
const introducerRows = [
|
||||
['4KB live chunk, no escapes', liveChunk],
|
||||
['4KB live chunk, \\x1b[?25l present', `${liveChunk}\x1b[?25l`]
|
||||
['4KB live chunk, \\x1b[?25l present', `${liveChunk}\x1b[?25l`],
|
||||
['4KB live chunk, Kitty flags 3', `${liveChunk}\x1b[>3u`],
|
||||
['4KB live chunk, Kitty flags 7', `${liveChunk}\x1b[=7u`]
|
||||
]
|
||||
console.log(
|
||||
`\n${pad('payload', 36)} ${pad('size', 8)} ${pad('scanReplay', 11)} ${pad('+includes gate', 15)}`
|
||||
)
|
||||
for (const [name, data] of introducerRows) {
|
||||
assert.equal(kittyGated(data), kittyScan(data), `Kitty gate disagrees on ${name}`)
|
||||
console.log(
|
||||
`${pad(name, 36)} ${pad(kb(data), 8)} ${pad(measure(kittyScan, data).toFixed(3), 11)} ${pad(measure(kittyGated, data).toFixed(3), 15)}`
|
||||
)
|
||||
}
|
||||
|
||||
console.log(
|
||||
'\nSnapshot/replay payloads always contain \\x1b[?, so the includes() gate never fires on\nthe reattach path — it only helps the live per-chunk path.'
|
||||
'\nThese replay fixtures contain CSI escapes, so the includes() gate never skips\ntheir scan. The live plain-output row measures the no-escape fast path.'
|
||||
)
|
||||
|
||||
// Time xterm on identical bytes as reference cost for deciding whether scan optimization matters.
|
||||
|
||||
@@ -11,6 +11,13 @@ describe('relay phone outer protocol', () => {
|
||||
leaseExpiresAt: 1
|
||||
}).success
|
||||
).toBe(true)
|
||||
expect(
|
||||
RelayPhoneHelloSchema.safeParse({
|
||||
type: 'relay-hello',
|
||||
ok: false,
|
||||
code: 4404
|
||||
}).success
|
||||
).toBe(true)
|
||||
expect(
|
||||
RelayPhoneHelloSchema.safeParse({
|
||||
type: 'relay-hello',
|
||||
|
||||
@@ -5,8 +5,14 @@ import { parseServerShareAddress } from './server-share-address'
|
||||
describe('parseServerShareAddress', () => {
|
||||
it('accepts a bare hostname or IP', () => {
|
||||
expect(parseServerShareAddress('my-host')).toEqual({ ok: true, value: 'my-host' })
|
||||
expect(parseServerShareAddress('my-mac.tail-abcd.ts.net').ok).toBe(true)
|
||||
expect(parseServerShareAddress('192.168.1.50').ok).toBe(true)
|
||||
expect(parseServerShareAddress('my-mac.tail-abcd.ts.net')).toEqual({
|
||||
ok: true,
|
||||
value: 'my-mac.tail-abcd.ts.net'
|
||||
})
|
||||
expect(parseServerShareAddress('192.168.1.50')).toEqual({
|
||||
ok: true,
|
||||
value: '192.168.1.50'
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects empty, whitespace-containing, and malformed input', () => {
|
||||
|
||||
@@ -2,10 +2,6 @@ import { describe, expect, it } from 'vitest'
|
||||
import { tabHasLivePty } from './tab-has-live-pty'
|
||||
|
||||
describe('tabHasLivePty', () => {
|
||||
it('returns false for an empty map', () => {
|
||||
expect(tabHasLivePty({}, 'tab-1')).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false for a missing tab id', () => {
|
||||
expect(tabHasLivePty({ 'other-tab': ['pty-1'] }, 'tab-1')).toBe(false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user