mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-08-03 17:01:15 +08:00
The Windows x64 build job went red on `Verify compiled Windows sidecar startup`, asserting that a loopback request without `CC_HAHA_LOCAL_ACCESS_TOKEN` returns 403 while it returned 200. Nothing about x64 is involved — that step carries `if: matrix.smoke_platform == 'windows' && matrix.arch == 'x64'`, so it is the only job in the whole matrix that runs the smoke at all. Any regression in this area can surface nowhere else. The 200 is correct. `7d2a8a3cd keep loopback trusted without the desktop process token` deliberately made the token additive again: gating every local request behind it turned the Grok OAuth success page, `/preview-fs` links and plain `curl` into 401s, because none of that traffic can ever carry the token. Loopback is trusted on its own; the token is demanded only on the `/api/h5-access` control plane, where another program on the same box must not be able to publish the user's sessions to the network. The assertion, written before that change, was still guarding the path that had been intentionally opened. So the probe moves to the boundary that is actually enforced, and gains a positive assertion — loopback without a token must be 200 — so the additive model is pinned down rather than merely no longer contradicted. Reverting to the pre-`7d2a8a3cd` behaviour now fails the smoke instead of passing it. Three copies of the stale assertion existed; all three are updated. Only the compiled-sidecar smoke runs in CI, but `local-index-benchmark.ts` and its corpus test were already failing the same way for anyone running them locally. The benchmark also cancels the probe response bodies now: an unread body holds its connection open, and that would land in the event-loop delay and RSS samples taken immediately after. Verified with the CI parameters — `bun run build:sidecars` then `CC_HAHA_COMPILED_SIDECAR_SMOKE_STARTS=20 bun run test:compiled-sidecar-smoke`, 8/8 — and by running the benchmark directly, which now reports `loopbackAuth` as 200/403/403/200 with validation intact.
1033 lines
31 KiB
TypeScript
1033 lines
31 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from 'bun:test'
|
|
import { mkdtemp, readFile, readdir, rm, stat } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { basename, join, relative, resolve } from 'node:path'
|
|
import type { LocalIndexCorpusOptions } from './local-index-corpus.js'
|
|
|
|
type CorpusManifest = {
|
|
corpusVersion: number
|
|
seed: number
|
|
options: {
|
|
sessions: number
|
|
entriesPerSession: number
|
|
largeTranscriptBytes: number
|
|
seed: number
|
|
}
|
|
features: {
|
|
duplicateSessionIds: string[]
|
|
malformedCompleteLines: number
|
|
incompleteFinalLines: number
|
|
metadataOnlyAppends: number
|
|
subagentTranscripts: number
|
|
taskNotifications: number
|
|
checkpoints: number
|
|
windowsDriveMetadata: number
|
|
uncMetadata: number
|
|
}
|
|
expected: {
|
|
normalizedSessionOrder: string[]
|
|
totals: {
|
|
mainTranscriptFiles: number
|
|
sourceFiles: number
|
|
visibleMessages: number
|
|
}
|
|
summaries: Array<{
|
|
sourcePath: string
|
|
sessionId: string
|
|
title: string
|
|
createdAt: string
|
|
modifiedAt: string
|
|
messageCount: number
|
|
}>
|
|
activityTotals: {
|
|
sessions: number
|
|
messages: number
|
|
toolCalls: number
|
|
tokens: number
|
|
}
|
|
}
|
|
largeTranscript: {
|
|
sourcePath: string
|
|
requestedBytes: number
|
|
actualBytes: number
|
|
} | null
|
|
sources: Array<{
|
|
path: string
|
|
bytes: number
|
|
sha256: string
|
|
}>
|
|
}
|
|
|
|
const tempDirs: string[] = []
|
|
let originalHome: string | undefined
|
|
let originalConfigDir: string | undefined
|
|
let originalLocalAccessToken: string | undefined
|
|
|
|
async function tempRoot(label: string): Promise<string> {
|
|
const root = await mkdtemp(join(tmpdir(), `cc-haha-${label}-`))
|
|
tempDirs.push(root)
|
|
return root
|
|
}
|
|
|
|
async function createLocalIndexCorpus(options: LocalIndexCorpusOptions) {
|
|
const corpusModule = await import('./local-index-corpus.js')
|
|
return corpusModule.createLocalIndexCorpus(options)
|
|
}
|
|
|
|
function restoreEnvironment(
|
|
name: 'HOME' | 'CLAUDE_CONFIG_DIR' | 'CC_HAHA_LOCAL_ACCESS_TOKEN',
|
|
value: string | undefined,
|
|
): void {
|
|
if (value === undefined) {
|
|
delete process.env[name]
|
|
} else {
|
|
process.env[name] = value
|
|
}
|
|
}
|
|
|
|
beforeEach(async () => {
|
|
originalHome = process.env.HOME
|
|
originalConfigDir = process.env.CLAUDE_CONFIG_DIR
|
|
originalLocalAccessToken = process.env.CC_HAHA_LOCAL_ACCESS_TOKEN
|
|
const environmentRoot = await tempRoot('local-index-test-environment')
|
|
process.env.HOME = join(environmentRoot, 'home')
|
|
process.env.CLAUDE_CONFIG_DIR = join(environmentRoot, 'home', '.claude')
|
|
})
|
|
|
|
afterEach(async () => {
|
|
restoreEnvironment('HOME', originalHome)
|
|
restoreEnvironment('CLAUDE_CONFIG_DIR', originalConfigDir)
|
|
restoreEnvironment('CC_HAHA_LOCAL_ACCESS_TOKEN', originalLocalAccessToken)
|
|
await Promise.all(tempDirs.splice(0).map(
|
|
dir => rm(dir, { recursive: true, force: true }),
|
|
))
|
|
})
|
|
|
|
async function loadManifest(manifestPath: string): Promise<CorpusManifest> {
|
|
return JSON.parse(await readFile(manifestPath, 'utf8')) as CorpusManifest
|
|
}
|
|
|
|
describe('createLocalIndexCorpus', () => {
|
|
it('creates byte-identical seeded manifests and source hashes', async () => {
|
|
const rootA = await tempRoot('local-index-a')
|
|
const rootB = await tempRoot('local-index-b')
|
|
const options = {
|
|
sessions: 12,
|
|
entriesPerSession: 8,
|
|
largeTranscriptBytes: 32 * 1024,
|
|
seed: 41,
|
|
}
|
|
|
|
const corpusA = await createLocalIndexCorpus({ rootDir: rootA, ...options })
|
|
const corpusB = await createLocalIndexCorpus({ rootDir: rootB, ...options })
|
|
|
|
expect(corpusA.configDir).toBe(join(rootA, 'home', '.claude'))
|
|
expect(corpusA.projectsDir).toBe(join(corpusA.configDir, 'projects'))
|
|
expect(corpusA.transcriptPaths).toHaveLength(options.sessions)
|
|
expect(
|
|
corpusA.transcriptPaths.every(file => relative(corpusA.projectsDir, file).startsWith('..') === false),
|
|
).toBe(true)
|
|
expect(await readFile(corpusA.manifestPath)).toEqual(
|
|
await readFile(corpusB.manifestPath),
|
|
)
|
|
|
|
const manifestA = await loadManifest(corpusA.manifestPath)
|
|
const manifestB = await loadManifest(corpusB.manifestPath)
|
|
expect(manifestA.sources).toEqual(manifestB.sources)
|
|
expect(manifestA.seed).toBe(options.seed)
|
|
expect(manifestA.options).toEqual(options)
|
|
expect(manifestA.expected.totals.mainTranscriptFiles).toBe(options.sessions)
|
|
expect(manifestA.expected.summaries).toHaveLength(options.sessions)
|
|
expect(manifestA.expected.normalizedSessionOrder).toHaveLength(options.sessions)
|
|
expect(manifestA.expected.activityTotals).toEqual({
|
|
sessions: 12,
|
|
messages: 36,
|
|
toolCalls: 4,
|
|
tokens: 354,
|
|
})
|
|
expect(manifestA.sources.every(source => /^[a-f0-9]{64}$/.test(source.sha256))).toBe(true)
|
|
expect(JSON.stringify(manifestA)).not.toContain(rootA)
|
|
expect(JSON.stringify(manifestA)).not.toContain(rootB)
|
|
})
|
|
|
|
it('covers privacy-safe compatibility and append fixtures across projects', async () => {
|
|
const root = await tempRoot('local-index-features')
|
|
const corpus = await createLocalIndexCorpus({
|
|
rootDir: root,
|
|
sessions: 12,
|
|
entriesPerSession: 8,
|
|
largeTranscriptBytes: 24 * 1024,
|
|
seed: 20260714,
|
|
})
|
|
const manifest = await loadManifest(corpus.manifestPath)
|
|
const projectDirs = await readdir(corpus.projectsDir)
|
|
const sessionIds = corpus.transcriptPaths.map(file => basename(file, '.jsonl'))
|
|
const sourceText = (
|
|
await Promise.all(manifest.sources.map(source => readFile(join(corpus.configDir, source.path), 'utf8')))
|
|
).join('\n')
|
|
|
|
expect(projectDirs.length).toBeGreaterThanOrEqual(4)
|
|
expect(new Set(sessionIds).size).toBeLessThan(sessionIds.length)
|
|
expect(manifest.features.duplicateSessionIds.length).toBeGreaterThan(0)
|
|
expect(manifest.features).toMatchObject({
|
|
malformedCompleteLines: 1,
|
|
incompleteFinalLines: 1,
|
|
metadataOnlyAppends: 2,
|
|
subagentTranscripts: 2,
|
|
taskNotifications: 2,
|
|
checkpoints: 2,
|
|
windowsDriveMetadata: 1,
|
|
uncMetadata: 1,
|
|
})
|
|
expect(sourceText).toContain('"content":"Synthetic old-shape prompt')
|
|
expect(sourceText).toContain('"content":[{"type":"text","text":"Synthetic current-shape prompt')
|
|
expect(sourceText).toContain('synthetic-malformed-complete-line')
|
|
expect(sourceText).toContain('synthetic-incomplete-final-line')
|
|
expect(sourceText).toContain('"type":"session-meta"')
|
|
expect(sourceText).toContain('"type":"tool_use"')
|
|
expect(sourceText).toContain('"isSidechain":true')
|
|
expect(sourceText).toContain('<task-notification>')
|
|
expect(sourceText).toContain('"type":"file-history-snapshot"')
|
|
expect(sourceText).toContain('C:\\\\Synthetic\\\\Corpus')
|
|
expect(sourceText).toContain('\\\\\\\\synthetic-server\\\\share\\\\corpus')
|
|
})
|
|
|
|
it('streams a configurable large transcript to at least the requested size', async () => {
|
|
const root = await tempRoot('local-index-large')
|
|
const requestedBytes = 96 * 1024
|
|
const corpus = await createLocalIndexCorpus({
|
|
rootDir: root,
|
|
sessions: 8,
|
|
entriesPerSession: 8,
|
|
largeTranscriptBytes: requestedBytes,
|
|
seed: 7,
|
|
})
|
|
const manifest = await loadManifest(corpus.manifestPath)
|
|
|
|
expect(manifest.largeTranscript).not.toBeNull()
|
|
const largeSource = manifest.largeTranscript!
|
|
const largePath = join(corpus.configDir, largeSource.sourcePath)
|
|
const largeStat = await stat(largePath)
|
|
expect(largeSource.requestedBytes).toBe(requestedBytes)
|
|
expect(largeSource.actualBytes).toBe(largeStat.size)
|
|
expect(largeStat.size).toBeGreaterThanOrEqual(requestedBytes)
|
|
expect(await readFile(largePath, 'utf8')).toContain('synthetic-large-record')
|
|
})
|
|
|
|
it('retries controllable short writes until the complete buffer is persisted', async () => {
|
|
const corpusModule = await import('./local-index-corpus.js')
|
|
const writeBufferFully = (
|
|
corpusModule as unknown as {
|
|
writeBufferFully?: (
|
|
writer: {
|
|
write: (
|
|
buffer: Uint8Array,
|
|
offset: number,
|
|
length: number,
|
|
) => Promise<{ bytesWritten: number }>
|
|
},
|
|
buffer: Uint8Array,
|
|
) => Promise<number>
|
|
}
|
|
).writeBufferFully
|
|
expect(typeof writeBufferFully).toBe('function')
|
|
|
|
const chunks: Buffer[] = []
|
|
const requestedLengths: number[] = []
|
|
const writer = {
|
|
async write(buffer: Uint8Array, offset: number, length: number) {
|
|
requestedLengths.push(length)
|
|
const bytesWritten = Math.min(3, length)
|
|
chunks.push(Buffer.from(buffer.subarray(offset, offset + bytesWritten)))
|
|
return { bytesWritten }
|
|
},
|
|
}
|
|
const payload = Buffer.from('short-write-proof')
|
|
|
|
const bytesWritten = await writeBufferFully!(writer, payload)
|
|
|
|
expect(bytesWritten).toBe(payload.length)
|
|
expect(Buffer.concat(chunks)).toEqual(payload)
|
|
expect(requestedLengths).toEqual([17, 14, 11, 8, 5, 2])
|
|
})
|
|
})
|
|
|
|
async function runBenchmarkProcess(args: string[]): Promise<{
|
|
exitCode: number
|
|
stdout: string
|
|
stderr: string
|
|
}> {
|
|
const processHandle = Bun.spawn({
|
|
cmd: [
|
|
process.execPath,
|
|
'run',
|
|
join(import.meta.dir, 'local-index-benchmark.ts'),
|
|
...args,
|
|
],
|
|
cwd: resolve(import.meta.dir, '../..'),
|
|
env: { ...process.env },
|
|
stdout: 'pipe',
|
|
stderr: 'pipe',
|
|
})
|
|
const [exitCode, stdout, stderr] = await Promise.all([
|
|
processHandle.exited,
|
|
new Response(processHandle.stdout).text(),
|
|
new Response(processHandle.stderr).text(),
|
|
])
|
|
return { exitCode, stdout, stderr }
|
|
}
|
|
|
|
describe('local index file benchmark', () => {
|
|
it('enforces real warmup and measured sample deadlines with cleanup', async () => {
|
|
const benchmark = await import('./local-index-benchmark.js') as {
|
|
parseBenchmarkArgs?: (args: string[]) => unknown
|
|
runBenchmark?: (
|
|
options: unknown,
|
|
dependencies?: {
|
|
executeSessionList?: (
|
|
execute: () => Promise<unknown>,
|
|
context: {
|
|
phase: 'warmup' | 'measured'
|
|
index: number
|
|
rootDir: string
|
|
},
|
|
) => Promise<unknown>
|
|
},
|
|
) => Promise<unknown>
|
|
}
|
|
expect(typeof benchmark.parseBenchmarkArgs).toBe('function')
|
|
expect(typeof benchmark.runBenchmark).toBe('function')
|
|
|
|
const originalEnvironment = {
|
|
HOME: process.env.HOME,
|
|
CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR,
|
|
CC_HAHA_LOCAL_INDEX: process.env.CC_HAHA_LOCAL_INDEX,
|
|
}
|
|
for (const expectedPhase of ['warmup', 'measured'] as const) {
|
|
const contexts: Array<{
|
|
phase: 'warmup' | 'measured'
|
|
index: number
|
|
rootDir: string
|
|
}> = []
|
|
const options = benchmark.parseBenchmarkArgs!([
|
|
'--sessions',
|
|
'8',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--runs',
|
|
'3',
|
|
'--warmup-runs',
|
|
expectedPhase === 'warmup' ? '2' : '0',
|
|
'--timeout-ms',
|
|
'5',
|
|
'--seed',
|
|
expectedPhase === 'warmup' ? '79' : '80',
|
|
'--mode',
|
|
'file',
|
|
])
|
|
const startedAt = performance.now()
|
|
let caught: unknown
|
|
try {
|
|
await Promise.race([
|
|
benchmark.runBenchmark!(options, {
|
|
executeSessionList: async (_execute, context) => {
|
|
contexts.push(context)
|
|
return new Promise<never>(() => {})
|
|
},
|
|
}),
|
|
Bun.sleep(500).then(() => {
|
|
throw new Error('benchmark invocation did not exit after sample deadline')
|
|
}),
|
|
])
|
|
} catch (error) {
|
|
caught = error
|
|
}
|
|
|
|
expect(caught).toBeInstanceOf(Error)
|
|
expect((caught as Error).message).toContain(
|
|
`${expectedPhase} sample 1 exceeded 5ms`,
|
|
)
|
|
expect((caught as Error).message).toContain('timeoutCount=1')
|
|
expect(caught).toMatchObject({
|
|
name: 'BenchmarkSampleTimeoutError',
|
|
phase: expectedPhase,
|
|
index: 0,
|
|
timeoutMs: 5,
|
|
timeoutCount: 1,
|
|
})
|
|
expect(performance.now() - startedAt).toBeLessThan(500)
|
|
expect(contexts).toHaveLength(1)
|
|
expect(contexts[0]).toMatchObject({ phase: expectedPhase, index: 0 })
|
|
expect(await stat(contexts[0]!.rootDir).then(() => true, () => false)).toBe(false)
|
|
expect(process.env.HOME).toBe(originalEnvironment.HOME)
|
|
expect(process.env.CLAUDE_CONFIG_DIR).toBe(originalEnvironment.CLAUDE_CONFIG_DIR)
|
|
expect(process.env.CC_HAHA_LOCAL_INDEX).toBe(originalEnvironment.CC_HAHA_LOCAL_INDEX)
|
|
}
|
|
})
|
|
|
|
it('clears completed deadline timers and consumes a rejection after timeout', async () => {
|
|
const benchmark = await import('./local-index-benchmark.js') as {
|
|
runWithSampleDeadline?: <T>(options: {
|
|
execute: () => Promise<T>
|
|
timeoutMs: number
|
|
phase: 'warmup' | 'measured'
|
|
index: number
|
|
setTimer?: typeof setTimeout
|
|
clearTimer?: typeof clearTimeout
|
|
}) => Promise<T>
|
|
}
|
|
expect(typeof benchmark.runWithSampleDeadline).toBe('function')
|
|
|
|
let clearCount = 0
|
|
const completed = await benchmark.runWithSampleDeadline!({
|
|
execute: async () => 'complete',
|
|
timeoutMs: 100,
|
|
phase: 'measured',
|
|
index: 0,
|
|
clearTimer: timer => {
|
|
clearCount += 1
|
|
clearTimeout(timer)
|
|
},
|
|
})
|
|
expect(completed).toBe('complete')
|
|
expect(clearCount).toBe(1)
|
|
|
|
let rejectLate!: (error: Error) => void
|
|
const late = new Promise<never>((_resolve, reject) => {
|
|
rejectLate = reject
|
|
})
|
|
await expect(benchmark.runWithSampleDeadline!({
|
|
execute: () => late,
|
|
timeoutMs: 5,
|
|
phase: 'warmup',
|
|
index: 0,
|
|
})).rejects.toThrow('warmup sample 1 exceeded 5ms')
|
|
rejectLate(new Error('late sample rejection'))
|
|
await Bun.sleep(0)
|
|
|
|
let resolveLate!: (value: string) => void
|
|
const lateResolution = new Promise<string>(resolve => {
|
|
resolveLate = resolve
|
|
})
|
|
await expect(benchmark.runWithSampleDeadline!({
|
|
execute: () => lateResolution,
|
|
timeoutMs: 5,
|
|
phase: 'measured',
|
|
index: 0,
|
|
})).rejects.toThrow('measured sample 1 exceeded 5ms')
|
|
resolveLate('late sample resolution')
|
|
await Bun.sleep(0)
|
|
})
|
|
|
|
it('captures first useful content when its request settles without waiting for ready', async () => {
|
|
const benchmark = await import('./local-index-benchmark.js') as {
|
|
captureStartupResponses?: <TFirst, TReady>(options: {
|
|
firstUsefulRequest: Promise<TFirst>
|
|
readyRequest: Promise<TReady>
|
|
elapsedSinceServerStartMs: () => number
|
|
onFirstUsefulSettled?: (durationMs: number) => void
|
|
}) => Promise<{
|
|
firstUseful: TFirst
|
|
ready: TReady
|
|
firstUsefulDurationMs: number
|
|
}>
|
|
}
|
|
expect(typeof benchmark.captureStartupResponses).toBe('function')
|
|
|
|
let resolveFirstUseful!: (value: string) => void
|
|
let resolveReady!: (value: string) => void
|
|
let elapsedMs = 0
|
|
let capturedBeforeReady: number | undefined
|
|
const firstUsefulRequest = new Promise<string>(resolve => {
|
|
resolveFirstUseful = resolve
|
|
})
|
|
const readyRequest = new Promise<string>(resolve => {
|
|
resolveReady = resolve
|
|
})
|
|
const startup = benchmark.captureStartupResponses!({
|
|
firstUsefulRequest,
|
|
readyRequest,
|
|
elapsedSinceServerStartMs: () => elapsedMs,
|
|
onFirstUsefulSettled: durationMs => {
|
|
capturedBeforeReady = durationMs
|
|
},
|
|
})
|
|
|
|
elapsedMs = 25
|
|
resolveFirstUseful('first')
|
|
await Bun.sleep(0)
|
|
expect(capturedBeforeReady).toBe(25)
|
|
|
|
elapsedMs = 10_000
|
|
resolveReady('ready')
|
|
await expect(startup).resolves.toEqual({
|
|
firstUseful: 'first',
|
|
ready: 'ready',
|
|
firstUsefulDurationMs: 25,
|
|
})
|
|
})
|
|
|
|
it('enforces the real loopback product deadline and still cleans isolated state', async () => {
|
|
await import('../../src/server/index.js')
|
|
await import('../../src/server/services/localIndex/coordinator.js')
|
|
const benchmark = await import('./local-index-benchmark.js') as {
|
|
parseBenchmarkArgs?: (args: string[]) => unknown
|
|
runBenchmark?: (
|
|
options: unknown,
|
|
dependencies?: {
|
|
onProductGatesStart?: (context: { rootDir: string }) => void
|
|
},
|
|
) => Promise<unknown>
|
|
}
|
|
expect(typeof benchmark.parseBenchmarkArgs).toBe('function')
|
|
expect(typeof benchmark.runBenchmark).toBe('function')
|
|
const originalEnvironment = {
|
|
HOME: process.env.HOME,
|
|
CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR,
|
|
CC_HAHA_LOCAL_INDEX: process.env.CC_HAHA_LOCAL_INDEX,
|
|
CC_HAHA_LOCAL_ACCESS_TOKEN: process.env.CC_HAHA_LOCAL_ACCESS_TOKEN,
|
|
}
|
|
process.env.CC_HAHA_LOCAL_ACCESS_TOKEN = 'benchmark-parent-local-access-token'
|
|
const options = benchmark.parseBenchmarkArgs!([
|
|
'--sessions',
|
|
'50',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--runs',
|
|
'1',
|
|
'--warmup-runs',
|
|
'0',
|
|
'--timeout-ms',
|
|
'1',
|
|
'--seed',
|
|
'81',
|
|
'--mode',
|
|
'sqlite',
|
|
])
|
|
let rootDir: string | undefined
|
|
let caught: unknown
|
|
|
|
try {
|
|
await benchmark.runBenchmark!(options, {
|
|
onProductGatesStart: context => {
|
|
rootDir = context.rootDir
|
|
},
|
|
})
|
|
} catch (error) {
|
|
caught = error
|
|
}
|
|
|
|
expect(caught).toMatchObject({
|
|
name: 'ProductGateTimeoutError',
|
|
timeoutMs: 1,
|
|
})
|
|
expect((caught as Error).message).toContain('sqlite product gates exceeded 1ms')
|
|
expect(rootDir).toBeDefined()
|
|
expect(await stat(rootDir!).then(() => true, () => false)).toBe(false)
|
|
expect(process.env.HOME).toBe(originalEnvironment.HOME)
|
|
expect(process.env.CLAUDE_CONFIG_DIR).toBe(originalEnvironment.CLAUDE_CONFIG_DIR)
|
|
expect(process.env.CC_HAHA_LOCAL_INDEX).toBe(originalEnvironment.CC_HAHA_LOCAL_INDEX)
|
|
expect(process.env.CC_HAHA_LOCAL_ACCESS_TOKEN).toBe(
|
|
'benchmark-parent-local-access-token',
|
|
)
|
|
})
|
|
|
|
it('reports an isolated JSON baseline and removes its temporary corpus', async () => {
|
|
const sentinelRoot = process.env.CLAUDE_CONFIG_DIR!
|
|
const { exitCode, stdout, stderr } = await runBenchmarkProcess([
|
|
'--sessions',
|
|
'8',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--large-transcript-bytes',
|
|
`${16 * 1024}`,
|
|
'--runs',
|
|
'1',
|
|
'--warmup-runs',
|
|
'1',
|
|
'--seed',
|
|
'73',
|
|
'--mode',
|
|
'file',
|
|
])
|
|
|
|
expect(exitCode).toBe(0)
|
|
expect(stderr).toBe('')
|
|
const report = JSON.parse(stdout) as {
|
|
schemaVersion: number
|
|
mode: string
|
|
fixture: {
|
|
rootDir: string
|
|
configDir: string
|
|
seed: number
|
|
sessions: number
|
|
corpusFingerprint: string
|
|
kept: boolean
|
|
}
|
|
measurement: {
|
|
warmupRuns: number
|
|
runs: number
|
|
durationMs: { median: number; p95: number; max: number }
|
|
timeoutCount: number
|
|
cpuMs: { user: number; system: number; total: number }
|
|
rssDeltaBytes: number
|
|
io: {
|
|
instrumented: boolean
|
|
filesOpened: number | null
|
|
bytesRead: number | null
|
|
}
|
|
}
|
|
validation: {
|
|
expectedSessions: number
|
|
actualSessions: number
|
|
orderMatches: boolean
|
|
summariesMatch: boolean
|
|
}
|
|
}
|
|
expect(report).toMatchObject({
|
|
schemaVersion: 1,
|
|
mode: 'file',
|
|
fixture: {
|
|
seed: 73,
|
|
sessions: 8,
|
|
kept: false,
|
|
},
|
|
measurement: {
|
|
warmupRuns: 1,
|
|
runs: 1,
|
|
timeoutCount: 0,
|
|
io: {
|
|
instrumented: false,
|
|
filesOpened: null,
|
|
bytesRead: null,
|
|
},
|
|
},
|
|
validation: {
|
|
expectedSessions: 8,
|
|
actualSessions: 8,
|
|
orderMatches: true,
|
|
summariesMatch: true,
|
|
},
|
|
})
|
|
expect(report.fixture.configDir.startsWith(report.fixture.rootDir)).toBe(true)
|
|
expect(report.fixture.configDir).not.toContain(sentinelRoot)
|
|
expect(report.fixture.corpusFingerprint).toMatch(/^[a-f0-9]{64}$/)
|
|
expect(report.measurement.durationMs.median).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.durationMs.p95).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.durationMs.max).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.cpuMs.total).toBeGreaterThanOrEqual(0)
|
|
expect(await stat(report.fixture.rootDir).then(() => true, () => false)).toBe(false)
|
|
})
|
|
|
|
it('keeps an inspectable corpus only when --keep is explicit', async () => {
|
|
const result = await runBenchmarkProcess([
|
|
'--sessions',
|
|
'8',
|
|
'--runs',
|
|
'1',
|
|
'--warmup-runs',
|
|
'0',
|
|
'--seed',
|
|
'74',
|
|
'--mode',
|
|
'file',
|
|
'--keep',
|
|
])
|
|
expect(result.exitCode).toBe(0)
|
|
expect(result.stderr).toBe('')
|
|
const report = JSON.parse(result.stdout) as {
|
|
fixture: {
|
|
rootDir: string
|
|
configDir: string
|
|
manifestPath?: string
|
|
kept: boolean
|
|
}
|
|
}
|
|
const keptRoot = report.fixture.rootDir
|
|
try {
|
|
expect(report.fixture.kept).toBe(true)
|
|
expect(typeof report.fixture.manifestPath).toBe('string')
|
|
expect(await stat(keptRoot).then(() => true, () => false)).toBe(true)
|
|
expect(
|
|
await stat(report.fixture.manifestPath!).then(() => true, () => false),
|
|
).toBe(true)
|
|
expect(report.fixture.manifestPath?.startsWith(keptRoot)).toBe(true)
|
|
} finally {
|
|
await rm(keptRoot, { recursive: true, force: true })
|
|
}
|
|
expect(await stat(keptRoot).then(() => true, () => false)).toBe(false)
|
|
})
|
|
|
|
it('reports bounded incremental IO for the append scenario', async () => {
|
|
const result = await runBenchmarkProcess([
|
|
'--sessions',
|
|
'8',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--scenario',
|
|
'append',
|
|
'--large-transcript-mib',
|
|
'1',
|
|
'--runs',
|
|
'2',
|
|
'--warmup-runs',
|
|
'0',
|
|
'--seed',
|
|
'75',
|
|
'--mode',
|
|
'file',
|
|
])
|
|
|
|
expect(result.exitCode).toBe(0)
|
|
expect(result.stderr).toBe('')
|
|
const report = JSON.parse(result.stdout) as {
|
|
scenario: string
|
|
fixture: {
|
|
largeTranscriptBytes: number
|
|
appendBytes: number
|
|
kept: boolean
|
|
}
|
|
measurement: {
|
|
runs: number
|
|
io: {
|
|
instrumented: boolean
|
|
filesOpened: number
|
|
bytesRead: number
|
|
maxBytesReadPerRun: number
|
|
statCalls: number
|
|
limitBytes: number
|
|
withinLimit: boolean
|
|
}
|
|
}
|
|
validation: {
|
|
changeKind: string
|
|
nextOffsetAdvancedBy: number
|
|
pendingTailBytes: number
|
|
snapshotVerified: boolean
|
|
}
|
|
}
|
|
expect(report).toMatchObject({
|
|
scenario: 'append',
|
|
fixture: {
|
|
largeTranscriptBytes: 1024 * 1024,
|
|
appendBytes: 4096,
|
|
kept: false,
|
|
},
|
|
measurement: {
|
|
runs: 2,
|
|
io: {
|
|
instrumented: true,
|
|
limitBytes: 1024 * 1024,
|
|
withinLimit: true,
|
|
},
|
|
},
|
|
validation: {
|
|
changeKind: 'append',
|
|
nextOffsetAdvancedBy: 4096,
|
|
pendingTailBytes: 0,
|
|
snapshotVerified: true,
|
|
},
|
|
})
|
|
expect(report.measurement.io.filesOpened).toBeGreaterThan(0)
|
|
expect(report.measurement.io.bytesRead).toBeGreaterThanOrEqual(
|
|
report.measurement.io.maxBytesReadPerRun,
|
|
)
|
|
expect(report.measurement.io.statCalls).toBeGreaterThan(0)
|
|
expect(report.measurement.io.maxBytesReadPerRun).toBeLessThanOrEqual(1024 * 1024)
|
|
})
|
|
|
|
it('runs a real shadow backfill and reports zero normalized mismatches', async () => {
|
|
const sentinelRoot = process.env.CLAUDE_CONFIG_DIR!
|
|
const result = await runBenchmarkProcess([
|
|
'--sessions',
|
|
'8',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--runs',
|
|
'1',
|
|
'--warmup-runs',
|
|
'1',
|
|
'--seed',
|
|
'76',
|
|
'--mode',
|
|
'shadow',
|
|
])
|
|
|
|
expect(result.exitCode).toBe(0)
|
|
expect(result.stderr).toBe('')
|
|
const report = JSON.parse(result.stdout) as {
|
|
schemaVersion: number
|
|
mode: string
|
|
scenario: string
|
|
fixture: {
|
|
rootDir: string
|
|
configDir: string
|
|
sessions: number
|
|
kept: boolean
|
|
}
|
|
index: {
|
|
readyDurationMs: number
|
|
status: {
|
|
mode: string
|
|
state: string
|
|
discovered: number
|
|
indexed: number
|
|
degradedSources: number
|
|
lastErrorCode: string | null
|
|
}
|
|
}
|
|
measurement: {
|
|
warmupRuns: number
|
|
runs: number
|
|
durationMs: { median: number; p95: number; max: number }
|
|
}
|
|
validation: {
|
|
expectedSessions: number
|
|
actualSessions: number
|
|
orderMatches: boolean
|
|
summariesMatch: boolean
|
|
comparisonCount: number
|
|
mismatchCount: number
|
|
differenceCount: number
|
|
}
|
|
}
|
|
expect(report).toMatchObject({
|
|
schemaVersion: 1,
|
|
mode: 'shadow',
|
|
scenario: 'baseline',
|
|
fixture: {
|
|
sessions: 8,
|
|
kept: false,
|
|
},
|
|
index: {
|
|
status: {
|
|
mode: 'shadow',
|
|
state: 'ready',
|
|
discovered: 8,
|
|
indexed: 8,
|
|
degradedSources: 0,
|
|
lastErrorCode: null,
|
|
},
|
|
},
|
|
measurement: {
|
|
warmupRuns: 1,
|
|
runs: 1,
|
|
},
|
|
validation: {
|
|
expectedSessions: 8,
|
|
actualSessions: 8,
|
|
orderMatches: true,
|
|
summariesMatch: true,
|
|
comparisonCount: 2,
|
|
mismatchCount: 0,
|
|
differenceCount: 0,
|
|
},
|
|
})
|
|
expect(report.fixture.configDir.startsWith(report.fixture.rootDir)).toBe(true)
|
|
expect(report.fixture.configDir).not.toContain(sentinelRoot)
|
|
expect(report.index.readyDurationMs).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.durationMs.median).toBeGreaterThanOrEqual(0)
|
|
expect(await stat(report.fixture.rootDir).then(() => true, () => false)).toBe(false)
|
|
expect(JSON.stringify(report)).not.toContain(sentinelRoot)
|
|
})
|
|
|
|
it('keeps the shadow corpus and closed SQLite index inspectable with --keep', async () => {
|
|
const result = await runBenchmarkProcess([
|
|
'--sessions',
|
|
'8',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--runs',
|
|
'1',
|
|
'--warmup-runs',
|
|
'0',
|
|
'--seed',
|
|
'77',
|
|
'--mode',
|
|
'shadow',
|
|
'--keep',
|
|
])
|
|
|
|
expect(result.exitCode).toBe(0)
|
|
expect(result.stderr).toBe('')
|
|
const report = JSON.parse(result.stdout) as {
|
|
fixture: {
|
|
rootDir: string
|
|
configDir: string
|
|
manifestPath: string
|
|
kept: boolean
|
|
}
|
|
index: {
|
|
status: { mode: string; state: string; indexed: number }
|
|
}
|
|
validation: {
|
|
mismatchCount: number
|
|
}
|
|
}
|
|
const rootDir = report.fixture.rootDir
|
|
try {
|
|
const manifest = await loadManifest(report.fixture.manifestPath)
|
|
const firstSource = join(report.fixture.configDir, manifest.sources[0]!.path)
|
|
const databasePath = join(
|
|
report.fixture.configDir,
|
|
'cc-haha',
|
|
'db',
|
|
'index-v1.sqlite',
|
|
)
|
|
|
|
expect(report).toMatchObject({
|
|
fixture: { kept: true },
|
|
index: {
|
|
status: { mode: 'shadow', state: 'ready', indexed: 8 },
|
|
},
|
|
validation: { mismatchCount: 0 },
|
|
})
|
|
expect(await stat(rootDir).then(() => true, () => false)).toBe(true)
|
|
expect(await stat(report.fixture.manifestPath).then(() => true, () => false)).toBe(true)
|
|
expect(await stat(firstSource).then(() => true, () => false)).toBe(true)
|
|
expect(await stat(databasePath).then(() => true, () => false)).toBe(true)
|
|
} finally {
|
|
await rm(rootDir, { recursive: true, force: true })
|
|
}
|
|
expect(await stat(rootDir).then(() => true, () => false)).toBe(false)
|
|
})
|
|
|
|
it('runs a real sqlite backfill and reports sidebar-shaped measurements', async () => {
|
|
const result = await runBenchmarkProcess([
|
|
'--sessions',
|
|
'8',
|
|
'--entries-per-session',
|
|
'8',
|
|
'--runs',
|
|
'1',
|
|
'--warmup-runs',
|
|
'1',
|
|
'--seed',
|
|
'78',
|
|
'--mode',
|
|
'sqlite',
|
|
])
|
|
|
|
expect(result.exitCode).toBe(0)
|
|
expect(result.stderr).toBe('')
|
|
const report = JSON.parse(result.stdout) as {
|
|
mode: string
|
|
fixture: { sessions: number; sidebarLimit: number; kept: boolean }
|
|
index: {
|
|
status: { mode: string; state: string; indexed: number }
|
|
}
|
|
measurement: {
|
|
operation: string
|
|
durationMs: { median: number; p95: number; max: number }
|
|
productAppend: {
|
|
measured: boolean
|
|
watcherObserved: boolean
|
|
messageCountDelta: number
|
|
durationMs: number
|
|
}
|
|
sidebarApi: {
|
|
measured: boolean
|
|
limit: number
|
|
rowCount: number
|
|
}
|
|
firstUsefulContent: {
|
|
measured: boolean
|
|
requestedImmediately: boolean
|
|
rowCount: number
|
|
durationMs: number
|
|
}
|
|
foregroundDuringBackfill: {
|
|
measured: boolean
|
|
requestCount: number
|
|
successfulResponseCount: number
|
|
}
|
|
eventLoopDelay: {
|
|
measured: boolean
|
|
sampleCount: number
|
|
p95Ms: number
|
|
p99Ms: number
|
|
maxMs: number
|
|
}
|
|
peakRss: {
|
|
measured: boolean
|
|
sampleCount: number
|
|
peakBytes: number
|
|
}
|
|
loopbackAuth: {
|
|
measured: boolean
|
|
loopbackWithoutTokenStatus: number
|
|
controlPlaneMissingTokenStatus: number
|
|
controlPlaneWrongTokenStatus: number
|
|
controlPlaneCorrectTokenStatus: number
|
|
}
|
|
}
|
|
validation: {
|
|
expectedSessions: number
|
|
actualSessions: number
|
|
orderMatches: boolean
|
|
summariesMatch: boolean
|
|
}
|
|
}
|
|
expect(report).toMatchObject({
|
|
mode: 'sqlite',
|
|
fixture: {
|
|
sessions: 8,
|
|
sidebarLimit: 400,
|
|
kept: false,
|
|
},
|
|
index: {
|
|
status: { mode: 'on', state: 'ready', indexed: 8 },
|
|
},
|
|
measurement: {
|
|
operation: 'sessions-http',
|
|
productAppend: {
|
|
measured: true,
|
|
watcherObserved: true,
|
|
messageCountDelta: 1,
|
|
},
|
|
sidebarApi: {
|
|
measured: true,
|
|
limit: 400,
|
|
rowCount: 8,
|
|
},
|
|
firstUsefulContent: {
|
|
measured: true,
|
|
requestedImmediately: true,
|
|
},
|
|
foregroundDuringBackfill: {
|
|
measured: true,
|
|
},
|
|
eventLoopDelay: { measured: true },
|
|
peakRss: { measured: true },
|
|
loopbackAuth: {
|
|
measured: true,
|
|
loopbackWithoutTokenStatus: 200,
|
|
controlPlaneMissingTokenStatus: 403,
|
|
controlPlaneWrongTokenStatus: 403,
|
|
controlPlaneCorrectTokenStatus: 200,
|
|
},
|
|
},
|
|
validation: {
|
|
expectedSessions: 8,
|
|
actualSessions: 8,
|
|
orderMatches: true,
|
|
summariesMatch: true,
|
|
},
|
|
})
|
|
expect(report.measurement.durationMs.p95).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.productAppend.durationMs).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.firstUsefulContent.rowCount).toBeGreaterThan(0)
|
|
expect(report.measurement.firstUsefulContent.durationMs).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.foregroundDuringBackfill.requestCount).toBeGreaterThan(0)
|
|
expect(report.measurement.foregroundDuringBackfill.successfulResponseCount).toBe(
|
|
report.measurement.foregroundDuringBackfill.requestCount,
|
|
)
|
|
expect(report.measurement.eventLoopDelay.sampleCount).toBeGreaterThan(0)
|
|
expect(report.measurement.eventLoopDelay.p95Ms).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.eventLoopDelay.p99Ms).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.eventLoopDelay.maxMs).toBeGreaterThanOrEqual(0)
|
|
expect(report.measurement.peakRss.sampleCount).toBeGreaterThan(0)
|
|
expect(report.measurement.peakRss.peakBytes).toBeGreaterThan(0)
|
|
})
|
|
})
|