mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
* perf(persistence): stop double-traversing the persisted session at load normalizeLoadedProfileState is the largest measured startup cost that scales with profile size, and almost all of it is zod-validating the 1.9 MB workspaceSession blob. Two redundant traversals removed, with no change to what is accepted: - The salvage containers wrapped `z.record(z.string(), z.unknown())` / `z.array(z.unknown())` around a transform that re-validates every entry itself, so zod validated and copied each map and array before the real per-entry parse even started. The containers now apply the same guards zod applied (`isPlainObject` plus its enumerable-symbol-key rejection, `Array.isArray`) and walk the input once. - The two recursive layout node schemas were plain unions, so every split node of every restored terminal and tab-group layout re-tried the leaf branch. They discriminate on `type`, which has the same accept and reject set. Cold parse of a 413-worktree / 801-tab profile: 52.5 -> 45.0 ms CPU (-14.3%, median of 25 interleaved processes). Steady state: 9.8 -> 7.1 ms. * test(persistence): pin absence-stays-fatal for the salvaging containers The comment on salvagingArray claimed a bare container in a z.object shape would read a missing key as an absence unless wrapped. Not true on zod 4.5.4: a bare transform sets neither optin nor optout, and handlePropertyResult only swallows an absent key's issues when a field is both. Assert it instead of documenting it, and correct the comment. Also add the .js extension the node16 CLI project needs on the two dynamic imports these tests added, which broke `pnpm tc`.
178 lines
5.7 KiB
TypeScript
178 lines
5.7 KiB
TypeScript
/* Deterministic guard for the validation work the session read boundary does. Counts zod container
|
|
* nodes executed for one fixed payload rather than timing anything, so it cannot flake on a loaded
|
|
* machine. It fails if the salvage combinators go back to letting zod validate-and-copy every map
|
|
* and array before the transform re-walks it, or if the layout unions stop discriminating. */
|
|
import { beforeAll, describe, expect, it } from 'vitest'
|
|
import { z } from 'zod'
|
|
import type { parseWorkspaceSessionSalvaging } from './workspace-session-salvage'
|
|
|
|
let containerRuns = 0
|
|
|
|
// Why: zod's default memoizer is the only hook that sees every container node, so this file swaps
|
|
// it for a counting one. Cycle breaking is what it gives up, and no payload here holds a cycle.
|
|
z.config({
|
|
memoizer: {
|
|
alloc: (_inst: unknown, _payload: unknown, empty: unknown) => empty,
|
|
guard: () => {},
|
|
attach: (inst: {
|
|
_zod: {
|
|
deferred?: (() => void)[]
|
|
parse: (payload: unknown, ctx: unknown) => unknown
|
|
run: unknown
|
|
}
|
|
}) => {
|
|
inst._zod.deferred ??= []
|
|
inst._zod.deferred.push(() => {
|
|
const base = inst._zod.parse
|
|
const wrapped = (payload: unknown, ctx: unknown): unknown => {
|
|
containerRuns += 1
|
|
return base(payload, ctx)
|
|
}
|
|
inst._zod.parse = wrapped
|
|
if (inst._zod.run === base) {
|
|
inst._zod.run = wrapped
|
|
}
|
|
})
|
|
}
|
|
}
|
|
} as never)
|
|
|
|
const WORKTREES = 30
|
|
const TABS_PER_WORKTREE = 4
|
|
|
|
function worktreeId(index: number): string {
|
|
return `repo-${index % 3}::/home/user/w${index}`
|
|
}
|
|
|
|
function terminalTab(id: string, wt: string, sortOrder: number): Record<string, unknown> {
|
|
return {
|
|
id,
|
|
ptyId: null,
|
|
worktreeId: wt,
|
|
title: 'Terminal',
|
|
customTitle: null,
|
|
color: null,
|
|
sortOrder,
|
|
createdAt: 1_700_000_000_000
|
|
}
|
|
}
|
|
|
|
function unifiedTab(id: string, wt: string, sortOrder: number): Record<string, unknown> {
|
|
return {
|
|
id,
|
|
entityId: id,
|
|
groupId: `${wt}:group`,
|
|
worktreeId: wt,
|
|
contentType: 'terminal',
|
|
label: 'Terminal',
|
|
customLabel: null,
|
|
color: null,
|
|
sortOrder,
|
|
createdAt: 1_700_000_000_000
|
|
}
|
|
}
|
|
|
|
/** Fixed shape, no randomness: the count below is only meaningful against a stable payload. */
|
|
function fixedSession(): Record<string, unknown> {
|
|
const tabsByWorktree: Record<string, unknown> = {}
|
|
const unifiedTabs: Record<string, unknown> = {}
|
|
const tabGroups: Record<string, unknown> = {}
|
|
const tabGroupLayouts: Record<string, unknown> = {}
|
|
const terminalLayoutsByTabId: Record<string, unknown> = {}
|
|
const lastVisitedAtByWorktreeId: Record<string, unknown> = {}
|
|
const terminalPtyIncarnationsByPaneKey: Record<string, unknown> = {}
|
|
|
|
for (let w = 0; w < WORKTREES; w += 1) {
|
|
const wt = worktreeId(w)
|
|
const tabs: Record<string, unknown>[] = []
|
|
const unified: Record<string, unknown>[] = []
|
|
for (let t = 0; t < TABS_PER_WORKTREE; t += 1) {
|
|
const id = `tab-${w}-${t}`
|
|
tabs.push(terminalTab(id, wt, t))
|
|
unified.push(unifiedTab(id, wt, t))
|
|
terminalLayoutsByTabId[id] = {
|
|
root: {
|
|
type: 'split',
|
|
direction: 'horizontal',
|
|
first: { type: 'leaf', leafId: `${id}:a` },
|
|
second: {
|
|
type: 'split',
|
|
direction: 'vertical',
|
|
first: { type: 'leaf', leafId: `${id}:b` },
|
|
second: { type: 'leaf', leafId: `${id}:c` },
|
|
ratio: 0.5
|
|
}
|
|
},
|
|
activeLeafId: `${id}:a`,
|
|
expandedLeafId: null,
|
|
ptyIdsByLeafId: { [`${id}:a`]: `pty-${id}` },
|
|
buffersByLeafId: { [`${id}:a`]: 'buffer' },
|
|
scrollbackRefsByLeafId: { [`${id}:a`]: 'ref' },
|
|
titlesByLeafId: { [`${id}:a`]: 'zsh' }
|
|
}
|
|
terminalPtyIncarnationsByPaneKey[`${id}:a`] = `inc-${id}`
|
|
}
|
|
tabsByWorktree[wt] = tabs
|
|
unifiedTabs[wt] = unified
|
|
tabGroups[wt] = [
|
|
{
|
|
id: `${wt}:group`,
|
|
worktreeId: wt,
|
|
activeTabId: `tab-${w}-0`,
|
|
tabOrder: unified.map((tab) => tab.id as string)
|
|
}
|
|
]
|
|
tabGroupLayouts[wt] = {
|
|
type: 'split',
|
|
direction: 'vertical',
|
|
first: { type: 'leaf', groupId: `${wt}:group` },
|
|
second: { type: 'leaf', groupId: `${wt}:group2` }
|
|
}
|
|
lastVisitedAtByWorktreeId[wt] = 1_700_000_000_000 + w
|
|
}
|
|
|
|
return {
|
|
activeRepoId: 'repo-0',
|
|
activeWorktreeId: worktreeId(0),
|
|
activeTabId: 'tab-0-0',
|
|
tabsByWorktree,
|
|
terminalLayoutsByTabId,
|
|
unifiedTabs,
|
|
tabGroups,
|
|
tabGroupLayouts,
|
|
lastVisitedAtByWorktreeId,
|
|
terminalPtyIncarnationsByPaneKey
|
|
}
|
|
}
|
|
|
|
/* Container-node executions for `fixedSession()`, measured on this branch:
|
|
* before this change: 1_958
|
|
* after this change: 1_111
|
|
* The bound sits between the two, so it fails on any return to the pre-pass containers or to a
|
|
* non-discriminated layout union, and tolerates ordinary schema growth. */
|
|
const MAX_CONTAINER_RUNS = 1_400
|
|
|
|
describe('workspace session validation work', () => {
|
|
let parse: typeof parseWorkspaceSessionSalvaging
|
|
|
|
beforeAll(async () => {
|
|
parse = (await import('./workspace-session-salvage.js')).parseWorkspaceSessionSalvaging
|
|
})
|
|
|
|
it('validates the session without a redundant traversal of every map, array and union branch', () => {
|
|
const payload = fixedSession()
|
|
// Why: zod compiles object fast paths on first use, so measure a settled parse.
|
|
parse(payload)
|
|
containerRuns = 0
|
|
const result = parse(payload)
|
|
|
|
expect(result.ok).toBe(true)
|
|
if (result.ok) {
|
|
expect(result.droppedCount).toBe(0)
|
|
expect(Object.keys(result.value.tabsByWorktree)).toHaveLength(WORKTREES)
|
|
}
|
|
expect(containerRuns).toBeGreaterThan(0)
|
|
expect(containerRuns).toBeLessThanOrEqual(MAX_CONTAINER_RUNS)
|
|
})
|
|
})
|