Files
orca/src/shared/workspace-session-schema.test.ts
T
Brennan Benson 98e5ea3d5f refactor(tabs): delete the terminal tab's dead adopted-session field (#22557)
* refactor(tabs): delete the terminal tab's dead adopted-session field and every branch that read it

* refactor(tabs): drop the stale adopted-agent comment and pin legacy load on a chat terminal

The comment above the terminal chat-eligibility agent fallback described the
removed adopted-session agent fallback. The legacy load test now puts the
retired key on a chat-mode terminal tab, the only shape that ever carried it.
2026-09-23 17:29:11 -07:00

720 lines
20 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { parseWorkspaceSession } from './workspace-session-schema'
import { MAX_BROWSER_HISTORY_ENTRIES } from './workspace-session-browser-history'
describe('parseWorkspaceSession', () => {
it('accepts a minimal valid session', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {}
})
expect(result.ok).toBe(true)
})
it('preserves external SSH file ownership across session parsing', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
openFilesByWorktree: {
wt: [
{
filePath: '/tmp/external.png',
relativePath: '/tmp/external.png',
worktreeId: 'wt',
language: 'png',
externalSshTargetId: 'ssh-1'
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.openFilesByWorktree?.wt?.[0]?.externalSshTargetId).toBe('ssh-1')
}
})
it('drops an open file with blank external SSH ownership, keeping the session', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
openFilesByWorktree: {
wt: [
{
filePath: '/tmp/external.png',
relativePath: '/tmp/external.png',
worktreeId: 'wt',
language: 'png',
externalSshTargetId: ' '
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.openFilesByWorktree?.wt).toEqual([])
}
})
it('accepts a fully populated session with optional fields', () => {
const result = parseWorkspaceSession({
activeRepoId: 'repo1',
activeWorktreeId: 'repo1::/path/wt1',
activeTabId: 'tab1',
tabsByWorktree: {
'repo1::/path/wt1': [
{
id: 'tab1',
ptyId: 'daemon-session-abc',
worktreeId: 'repo1::/path/wt1',
title: 'bash',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 1_700_000_000_000
}
]
},
terminalLayoutsByTabId: {
tab1: {
root: {
type: 'split',
direction: 'vertical',
first: { type: 'leaf', leafId: 'pane:1' },
second: { type: 'leaf', leafId: 'pane:2' }
},
activeLeafId: 'pane:1',
expandedLeafId: null,
ptyIdsByLeafId: { 'pane:1': 'daemon-session-A' }
}
},
activeWorktreeIdsOnShutdown: ['repo1::/path/wt1']
})
expect(result.ok).toBe(true)
})
it('preserves an isolated browser tab session partition across hydration', () => {
// Regression for #6923: the resolved partition must survive persist→load,
// otherwise a restored isolated tab falls back to the shared default
// partition when the renderer profile mirror is stale at startup.
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
browserTabsByWorktree: {
wt: [
{
id: 'browser-1',
worktreeId: 'wt',
sessionProfileId: 'iso-profile',
sessionPartition: 'persist:orca-browser-session-iso-profile',
url: 'https://example.com',
title: 'Example',
loading: false,
faviconUrl: null,
canGoBack: false,
canGoForward: false,
loadError: null,
createdAt: 1
}
]
}
})
expect(result.ok).toBe(true)
if (!result.ok) {
return
}
expect(result.value.browserTabsByWorktree?.wt?.[0]?.sessionPartition).toBe(
'persist:orca-browser-session-iso-profile'
)
})
it('preserves a valid launchAgent on a terminal tab', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {
wt: [
{
id: 'tab1',
ptyId: null,
worktreeId: 'wt',
title: 'codex',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 1,
launchAgent: 'codex'
}
]
},
terminalLayoutsByTabId: {}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree.wt[0].launchAgent).toBe('codex')
}
})
it('drops an unknown launchAgent without failing the whole session', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {
wt: [
{
id: 'tab1',
ptyId: null,
worktreeId: 'wt',
title: 'bash',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 1,
launchAgent: 'some-retired-agent'
}
]
},
terminalLayoutsByTabId: {}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree.wt[0].launchAgent).toBeUndefined()
}
})
it('drops a tab where ptyId is a number (schema drift) without failing the session', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {
wt: [
{
id: 'tab1',
ptyId: 42,
worktreeId: 'wt',
title: 'bash',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 0
}
]
},
terminalLayoutsByTabId: {}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree.wt).toEqual([])
}
})
it('preserves generated terminal title fields for persistence hydration', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: 'tab1',
tabsByWorktree: {
wt: [
{
id: 'tab1',
ptyId: null,
worktreeId: 'wt',
title: 'Claude working',
defaultTitle: 'Terminal 1',
generatedTitle: 'Refactor auth',
aiVaultTitle: {
agent: 'codex',
sessionId: 'session-1',
title: 'Provider thread name'
},
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 0
}
]
},
terminalLayoutsByTabId: {},
unifiedTabs: {
wt: [
{
id: 'tab1',
entityId: 'tab1',
groupId: 'group1',
worktreeId: 'wt',
executionHostId: 'runtime:host-b',
contentType: 'terminal',
label: 'Claude working',
generatedLabel: 'Refactor auth',
aiVaultTitle: {
agent: 'codex',
sessionId: 'session-1',
title: 'Provider thread name'
},
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 0
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree.wt[0].generatedTitle).toBe('Refactor auth')
expect(result.value.tabsByWorktree.wt[0].aiVaultTitle?.title).toBe('Provider thread name')
expect(result.value.unifiedTabs?.wt[0].generatedLabel).toBe('Refactor auth')
expect(result.value.unifiedTabs?.wt[0].aiVaultTitle?.title).toBe('Provider thread name')
expect(result.value.unifiedTabs?.wt[0].executionHostId).toBe('runtime:host-b')
}
})
it('drops malformed AI Vault titles without rejecting the workspace session', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: 'tab1',
tabsByWorktree: {
wt: [
{
id: 'tab1',
ptyId: null,
worktreeId: 'wt',
title: 'Codex',
aiVaultTitle: { agent: 'future-agent', sessionId: 'session-1', title: 'Name' },
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 0
}
]
},
terminalLayoutsByTabId: {},
unifiedTabs: {
wt: [
{
id: 'tab1',
entityId: 'tab1',
groupId: 'group1',
worktreeId: 'wt',
contentType: 'terminal',
label: 'Codex',
aiVaultTitle: 'malformed',
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 0
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree.wt[0].aiVaultTitle).toBeUndefined()
expect(result.value.unifiedTabs?.wt[0].aiVaultTitle).toBeUndefined()
}
})
it('preserves quick command label fields while accepting older omitted fields', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: 'tab1',
tabsByWorktree: {
wt: [
{
id: 'tab1',
ptyId: null,
worktreeId: 'wt',
title: 'pnpm test',
defaultTitle: 'Terminal 1',
quickCommandLabel: 'Run tests',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 0
},
{
id: 'tab2',
ptyId: null,
worktreeId: 'wt',
title: 'Terminal 2',
customTitle: null,
color: null,
sortOrder: 1,
createdAt: 1
}
]
},
terminalLayoutsByTabId: {},
unifiedTabs: {
wt: [
{
id: 'tab1',
entityId: 'tab1',
groupId: 'group1',
worktreeId: 'wt',
contentType: 'terminal',
label: 'pnpm test',
quickCommandLabel: 'Run tests',
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 0
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree.wt[0].quickCommandLabel).toBe('Run tests')
expect(result.value.tabsByWorktree.wt[1].quickCommandLabel).toBeUndefined()
expect(result.value.unifiedTabs?.wt[0].quickCommandLabel).toBe('Run tests')
}
})
it('rejects a session with missing required top-level fields', () => {
const result = parseWorkspaceSession({
activeRepoId: null
// missing activeWorktreeId, tabsByWorktree, etc.
})
expect(result.ok).toBe(false)
})
it('rejects a truncated JSON object', () => {
const result = parseWorkspaceSession({})
expect(result.ok).toBe(false)
})
it('rejects non-object input (e.g. corrupted file contents)', () => {
expect(parseWorkspaceSession(null).ok).toBe(false)
expect(parseWorkspaceSession('garbage').ok).toBe(false)
expect(parseWorkspaceSession(42).ok).toBe(false)
})
it('drops one truncated tab without discarding other persisted worktrees', () => {
const validTab = {
id: 'tab-good',
ptyId: null,
worktreeId: 'worktree-good',
title: 'Terminal',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 1_700_000_000_000
}
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'worktree-good',
activeTabId: 'tab-good',
tabsByWorktree: {
'worktree-good': [validTab],
'worktree-corrupt': [
{
id: 'tab-truncated',
ptyId: null,
worktreeId: 'worktree-corrupt',
title: 'Terminal',
sortOrder: 0,
generation: 3,
startupCwd: '/workspace'
}
]
},
terminalLayoutsByTabId: {}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.tabsByWorktree).toEqual({
'worktree-good': [validTab],
'worktree-corrupt': []
})
}
})
it('drops bad lastVisitedAtByWorktreeId entries rather than failing the session', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
lastVisitedAtByWorktreeId: {
good: 1_700_000_000_000,
nan: Number.NaN,
infinite: Number.POSITIVE_INFINITY,
negative: -5,
string: 'nope'
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.lastVisitedAtByWorktreeId).toEqual({ good: 1_700_000_000_000 })
}
})
it('accepts default-tab idempotency markers', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
defaultTerminalTabsAppliedByWorktreeId: {
'repo1::/path/wt1': true
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.defaultTerminalTabsAppliedByWorktreeId).toEqual({
'repo1::/path/wt1': true
})
}
})
it('caps oversized browser history while parsing legacy workspace sessions', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: null,
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
browserUrlHistory: Array.from({ length: 500 }, (_, index) => ({
url: `https://example.com/${index}`,
normalizedUrl: `https://example.com/${index}`,
title: `Example ${index}`,
faviconUrl: index === 0 ? 'https://example.com/favicon.ico' : null,
lastVisitedAt: 1_700_000_000_000 - index,
visitCount: 1
}))
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.browserUrlHistory).toHaveLength(MAX_BROWSER_HISTORY_ENTRIES)
expect(result.value.browserUrlHistory?.[0]?.faviconUrl).toBe(
'https://example.com/favicon.ico'
)
expect(result.value.browserUrlHistory?.at(-1)?.url).toBe('https://example.com/199')
}
})
it('preserves a known viewMode on a unified tab', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
unifiedTabs: {
wt: [
{
id: 'tab1',
entityId: 'tab1',
groupId: 'group1',
worktreeId: 'wt',
contentType: 'terminal',
label: 'Claude',
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 0,
viewMode: 'chat'
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.unifiedTabs?.wt[0].viewMode).toBe('chat')
}
})
it('preserves a structured agent session tab and drops the retired adoption key', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: 'session-1',
tabsByWorktree: {},
terminalLayoutsByTabId: {},
unifiedTabs: {
wt: [
{
id: 'session-1',
entityId: 'session-1',
groupId: 'group1',
worktreeId: 'wt',
contentType: 'agent-session',
agentSessionAgent: 'codex',
label: 'Codex Chat',
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 0
},
{
id: 'terminal-1',
entityId: 'terminal-1',
groupId: 'group1',
worktreeId: 'wt',
contentType: 'terminal',
viewMode: 'chat',
// Why: older builds could save this key on a chat-mode terminal; it must keep loading.
structuredSessionId: 'codex-session-1',
label: 'Terminal 1',
customLabel: null,
color: null,
sortOrder: 1,
createdAt: 0
}
]
},
activeTabTypeByWorktree: { wt: 'agent-session' }
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.unifiedTabs?.wt[0]).toMatchObject({
contentType: 'agent-session',
agentSessionAgent: 'codex'
})
expect(result.value.unifiedTabs?.wt[1]).toMatchObject({
contentType: 'terminal',
viewMode: 'chat'
})
expect(result.value.unifiedTabs?.wt[1]).not.toHaveProperty('structuredSessionId')
expect(result.value.activeTabTypeByWorktree?.wt).toBe('agent-session')
}
})
it('degrades an unknown viewMode to the safe default instead of failing parse', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
unifiedTabs: {
wt: [
{
id: 'tab1',
entityId: 'tab1',
groupId: 'group1',
worktreeId: 'wt',
contentType: 'terminal',
label: 'Claude',
customLabel: null,
color: null,
sortOrder: 0,
createdAt: 0,
// A newer build could persist a mode this version doesn't know.
viewMode: 'split-future-mode'
}
]
}
})
// The whole-session parse must still succeed; the unknown mode degrades.
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.unifiedTabs?.wt[0].viewMode).toBe('terminal')
}
})
// Why: z.object strips unlisted keys, so a page row that reaches disk with the remote page
// identity comes back without it — and hydration can only reconstruct the handle it needs to
// reclaim a client-hosted page if both halves of that identity survive the round trip.
it('preserves the remote page identity of a client-hosted browser page', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
browserPagesByWorkspace: {
'workspace-1': [
{
id: 'page-1',
workspaceId: 'workspace-1',
worktreeId: 'wt',
url: 'https://example.com/',
title: 'Example',
loading: false,
faviconUrl: null,
canGoBack: false,
canGoForward: false,
loadError: null,
createdAt: 1,
browserRuntimeEnvironmentId: 'env-1',
remoteBrowserPageId: 'remote-page-1',
remoteBrowserPageClientHosted: true
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value.browserPagesByWorkspace?.['workspace-1']?.[0]).toMatchObject({
remoteBrowserPageId: 'remote-page-1',
remoteBrowserPageClientHosted: true
})
}
})
it('accepts a browser page persisted before the remote page identity existed', () => {
const result = parseWorkspaceSession({
activeRepoId: null,
activeWorktreeId: 'wt',
activeTabId: null,
tabsByWorktree: {},
terminalLayoutsByTabId: {},
browserPagesByWorkspace: {
'workspace-1': [
{
id: 'page-1',
workspaceId: 'workspace-1',
worktreeId: 'wt',
url: 'https://example.com/',
title: 'Example',
loading: false,
faviconUrl: null,
canGoBack: false,
canGoForward: false,
loadError: null,
createdAt: 1
}
]
}
})
expect(result.ok).toBe(true)
if (result.ok) {
const page = result.value.browserPagesByWorkspace?.['workspace-1']?.[0]
expect(page?.id).toBe('page-1')
expect(page?.remoteBrowserPageId).toBeUndefined()
expect(page?.remoteBrowserPageClientHosted).toBeUndefined()
}
})
})