perf: skip WSL discovery when filtering native-only paths (#20266)

* perf: skip WSL discovery when filtering native-only paths

* fix: skip the AI Vault running-distro probe on WSL-less hosts

- getAiVaultWslHomeDirs, the sibling in the same Promise.all as the
  native-path filter, still spawned wsl.exe unconditionally on win32;
  gate it on the cached installed-distro list so a host with no distro
  performs no probe when only native Codex homes are configured.
- Hosts with a distro installed keep probing from that sibling, so the
  running-distro last-known-good cache is still warmed by the listing
  and a later probe outage falls back to the observed list, not [].
- Add a test against the real wsl module asserting zero wsl.exe spawns
  across the whole listing Promise.all, plus the warmed-cache fallback.

* fix(ai-vault): gate WSL home discovery on the cached distro list, not a probe

`listWslDistrosAsync()` resolves `[]` when the `wsl.exe` probe is rejected, so a
transient failure made `getAiVaultWslHomeDirs()` conclude "no WSL distros" and
skip discovery. That narrowed the allowed-roots set `ai-vault-delete` and
`ai-vault-subagent-list` validate against, wrongly rejecting WSL-hosted paths.

Gate on `hasCachedWslDistros()` / `getCachedWslDistros()` instead: a pure cache
read that only skips discovery once a successful probe has reported zero user
distros. It also never probes, so the AI Vault listing cannot be the first to
cache `[]` and flip a configured distro to "missing" in runtime resolution.

* test(ai-vault): drop the type assertion tripping the casting gate

check-changed-code-quality runs config/oxlint-code-quality-casting.json with
assertionStyle:'never' over changed lines, and `args as string[]` in the new
wsl-probe spy failed it. Narrow through Array.isArray instead, which is also
honest about execFile's argv being optional.

cached-session-list-wsl-probe + cached-session-list: 9/9 pass; tc:node clean;
changed-code quality gate passes.

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
Co-authored-by: Neil <neil@stably.ai>
This commit is contained in:
OrcaWin
2026-09-12 21:18:50 -07:00
committed by GitHub
co-authored by Orca Worker Neil
parent 81c3d188a4
commit 392583caba
7 changed files with 192 additions and 5 deletions
@@ -0,0 +1,110 @@
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type * as childProcess from 'node:child_process'
const { execFileMock, scanAiVaultSessionsInWorker } = vi.hoisted(() => ({
execFileMock: vi.fn(),
scanAiVaultSessionsInWorker: vi.fn()
}))
vi.mock('child_process', async (importOriginal) => ({
...(await importOriginal<typeof childProcess>()),
execFile: execFileMock
}))
vi.mock('./session-scanner-worker-spawn', () => ({
scanAiVaultSessionsInWorker,
resetAiVaultScannerWorkerForTests: vi.fn()
}))
import { _resetWslCachesForTests, _setWslCachesForTests, listWslDistrosAsync } from '../wsl'
import { filterPathsToRunningWslDistrosAsync } from '../wsl-running-path-filter'
import {
configureAiVaultSessionSources,
getAiVaultWslHomeDirs,
listAiVaultSessions,
resetAiVaultSessionListCacheForTests
} from './cached-session-list'
const NATIVE_CODEX_HOME = 'C:\\Users\\ada\\.codex'
const WSL_HOME = '\\\\wsl.localhost\\Ubuntu\\home\\ada'
function wslSpawns(): string[][] {
return execFileMock.mock.calls
.filter(([command]) => command === 'wsl.exe')
.flatMap(([, args]) => (Array.isArray(args) ? [args.map(String)] : []))
}
// Why the real wsl module: the point is the wsl.exe spawn count across the WHOLE
// listing Promise.all, which a per-function mock cannot observe.
describe('AI Vault listing wsl.exe probes', () => {
beforeEach(() => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
resetAiVaultSessionListCacheForTests()
configureAiVaultSessionSources({ getAdditionalCodexHomePaths: () => [NATIVE_CODEX_HOME] })
scanAiVaultSessionsInWorker.mockResolvedValue({ sessions: [], issues: [], scannedAt: 'scan' })
})
afterEach(() => {
execFileMock.mockReset()
_resetWslCachesForTests()
resetAiVaultSessionListCacheForTests()
vi.restoreAllMocks()
})
it('spawns no wsl.exe for native-only codex homes when no distro is installed', async () => {
_setWslCachesForTests({ distros: [] })
await listAiVaultSessions()
expect(wslSpawns()).toEqual([])
expect(scanAiVaultSessionsInWorker).toHaveBeenCalledWith(
expect.objectContaining({
additionalCodexSessionsDirs: [join(NATIVE_CODEX_HOME, 'sessions')],
wslHomeDirs: []
}),
expect.anything()
)
})
it('still probes running distros when one is installed, so a later outage keeps the last-known-good list', async () => {
_setWslCachesForTests({ distros: ['Ubuntu'] })
execFileMock.mockImplementation((_command, args, _options, callback) => {
callback(null, args.includes('--running') ? 'Ubuntu\n' : '/home/ada\n')
})
await listAiVaultSessions()
expect(wslSpawns()).toEqual([
['--list', '--running', '--quiet'],
['-d', 'Ubuntu', '--exec', 'bash', '-c', 'echo $HOME']
])
expect(scanAiVaultSessionsInWorker).toHaveBeenCalledWith(
expect.objectContaining({ wslHomeDirs: [WSL_HOME] }),
expect.anything()
)
execFileMock.mockImplementation((_command, _args, _options, callback) => {
callback(new Error('wsl unavailable'), '')
})
await expect(filterPathsToRunningWslDistrosAsync([`${WSL_HOME}\\.codex`])).resolves.toEqual([
`${WSL_HOME}\\.codex`
])
})
// Why: a rejected `--list --quiet` yields [] without caching. Treating that as "no distro
// installed" would narrow the allowed roots delete/subagent validation trusts.
it('still discovers WSL homes after the installed-distro probe was rejected', async () => {
execFileMock.mockImplementation((_command, args, _options, callback) => {
if (args.includes('--running')) {
callback(null, 'Ubuntu\n')
} else if (args.includes('--list')) {
callback(new Error('wsl.exe transient failure'), '')
} else {
callback(null, '/home/ada\n')
}
})
await expect(listWslDistrosAsync()).resolves.toEqual([])
await expect(getAiVaultWslHomeDirs()).resolves.toEqual([WSL_HOME])
expect(wslSpawns()).toContainEqual(['--list', '--running', '--quiet'])
})
})
@@ -3,10 +3,14 @@ import type { AiVaultListResult } from '../../shared/ai-vault-types'
const {
filterPathsToRunningWslDistrosAsync,
getCachedWslDistros,
hasCachedWslDistros,
listRunningWslHomeDirsAsync,
scanAiVaultSessionsInWorker
} = vi.hoisted(() => ({
filterPathsToRunningWslDistrosAsync: vi.fn(async (paths: readonly string[]) => [...paths]),
getCachedWslDistros: vi.fn((): string[] | null => null),
hasCachedWslDistros: vi.fn(() => false),
listRunningWslHomeDirsAsync: vi.fn().mockResolvedValue([]),
scanAiVaultSessionsInWorker: vi.fn()
}))
@@ -16,6 +20,8 @@ vi.mock('./session-scanner-worker-spawn', () => ({
resetAiVaultScannerWorkerForTests: vi.fn()
}))
vi.mock('../wsl', () => ({
getCachedWslDistros,
hasCachedWslDistros,
listRunningWslHomeDirsAsync
}))
vi.mock('../wsl-running-path-filter', () => ({ filterPathsToRunningWslDistrosAsync }))
@@ -51,6 +57,8 @@ describe('invalidateAiVaultSessionListCache generation guard', () => {
vi.spyOn(process, 'platform', 'get').mockImplementation(() => platform)
resetAiVaultSessionListCacheForTests()
filterPathsToRunningWslDistrosAsync.mockClear()
getCachedWslDistros.mockReset().mockReturnValue(null)
hasCachedWslDistros.mockReset().mockReturnValue(false)
listRunningWslHomeDirsAsync.mockReset().mockResolvedValue([])
scanAiVaultSessionsInWorker.mockReset()
})
@@ -99,6 +107,22 @@ describe('invalidateAiVaultSessionListCache generation guard', () => {
expect(listRunningWslHomeDirsAsync).toHaveBeenCalledTimes(1)
})
it('skips running-distro discovery once a probe has reported no installed WSL distro', async () => {
hasCachedWslDistros.mockReturnValue(true)
getCachedWslDistros.mockReturnValue([])
await expect(getAiVaultWslHomeDirs()).resolves.toEqual([])
expect(listRunningWslHomeDirsAsync).not.toHaveBeenCalled()
})
it('still discovers running distros before any distro probe has succeeded', async () => {
hasCachedWslDistros.mockReturnValue(false)
listRunningWslHomeDirsAsync.mockResolvedValue(['\\\\wsl.localhost\\Ubuntu\\home\\ada'])
await expect(getAiVaultWslHomeDirs()).resolves.toEqual(['\\\\wsl.localhost\\Ubuntu\\home\\ada'])
expect(listRunningWslHomeDirsAsync).toHaveBeenCalledTimes(1)
})
it('skips WSL home discovery off Windows', async () => {
platform = 'linux'
+8 -1
View File
@@ -4,7 +4,7 @@ import {
resetAiVaultScannerBackgroundForTests,
scanAiVaultSessionsInBackground
} from './session-scanner-background'
import { listRunningWslHomeDirsAsync } from '../wsl'
import { getCachedWslDistros, hasCachedWslDistros, listRunningWslHomeDirsAsync } from '../wsl'
import { filterPathsToRunningWslDistrosAsync } from '../wsl-running-path-filter'
import type { AiVaultListArgs, AiVaultListResult } from '../../shared/ai-vault-types'
import { LOCAL_EXECUTION_HOST_ID } from '../../shared/execution-host'
@@ -137,6 +137,13 @@ export async function getAiVaultWslHomeDirs(): Promise<string[]> {
if (process.platform !== 'win32') {
return []
}
// No installed distro can be running: spares WSL-less hosts the running-distro probe.
// Cache read only: a rejected wsl.exe probe yields [] without caching, so it must not
// narrow the WSL roots delete/subagent validation trusts; and probing here would let this
// listing be the first to cache [] and flip a configured distro to "missing".
if (hasCachedWslDistros() && getCachedWslDistros()?.length === 0) {
return []
}
return listRunningWslHomeDirsAsync()
}
@@ -26,7 +26,8 @@ vi.mock('../ai-vault/remote-session-scanner', () => ({
scanRemoteAiVaultSessions: mocks.scanRemoteAiVaultSessions
}))
vi.mock('../wsl', () => ({
listRunningWslHomeDirsAsync: vi.fn().mockResolvedValue([])
listRunningWslHomeDirsAsync: vi.fn().mockResolvedValue([]),
hasCachedWslDistros: vi.fn(() => false)
}))
vi.mock('../wsl-running-path-filter', () => ({
filterPathsToRunningWslDistrosAsync: vi.fn(async (paths: readonly string[]) => [...paths])
+2 -1
View File
@@ -75,7 +75,8 @@ vi.mock('../ai-vault/session-scanner-parse-cache', async (importOriginal) => {
vi.mock('../wsl', () => ({
listRunningWslDistrosAsync: vi.fn().mockResolvedValue([]),
listRunningWslHomeDirsAsync: vi.fn().mockResolvedValue([])
listRunningWslHomeDirsAsync: vi.fn().mockResolvedValue([]),
hasCachedWslDistros: vi.fn(() => false)
}))
vi.mock('../providers/ssh-filesystem-dispatch', () => ({
+43
View File
@@ -0,0 +1,43 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { filterPathsToRunningWslDistrosAsync } from './wsl-running-path-filter'
import { listRunningWslDistrosAsync } from './wsl'
vi.mock('./wsl', () => ({ listRunningWslDistrosAsync: vi.fn() }))
afterEach(() => {
vi.restoreAllMocks()
vi.resetAllMocks()
})
describe('filterPathsToRunningWslDistrosAsync', () => {
it.each([[], ['C:\\Users\\user\\.codex'], ['\\\\server\\share', '/local/path']])(
'does not query WSL for native paths %j',
async (...paths: string[]) => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
const result = await filterPathsToRunningWslDistrosAsync(paths)
expect(result).toEqual(paths)
expect(result).not.toBe(paths)
expect(listRunningWslDistrosAsync).not.toHaveBeenCalled()
}
)
it('still queries running distros for a mixed list and preserves path order', async () => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
vi.mocked(listRunningWslDistrosAsync).mockResolvedValue(['Ubuntu'])
const paths = [
'C:\\local',
'\\\\wsl$\\ubuntu\\home',
'//wsl.localhost/Debian/home',
'D:\\local'
]
expect(await filterPathsToRunningWslDistrosAsync(paths)).toEqual([paths[0], paths[1], paths[3]])
expect(listRunningWslDistrosAsync).toHaveBeenCalledTimes(1)
})
it('does not interpret WSL-shaped paths on a non-Windows host', async () => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('linux')
const paths = ['//wsl.localhost/Ubuntu/home']
expect(await filterPathsToRunningWslDistrosAsync(paths)).toEqual(paths)
expect(listRunningWslDistrosAsync).not.toHaveBeenCalled()
})
})
+3 -2
View File
@@ -1,4 +1,4 @@
import { parseWslUncPath } from '../shared/wsl-paths'
import { isWslUncPath, parseWslUncPath } from '../shared/wsl-paths'
import { listRunningWslDistrosAsync } from './wsl'
export function filterPathsToWslDistros(
@@ -19,5 +19,6 @@ export async function filterPathsToRunningWslDistrosAsync(
if (process.platform !== 'win32') {
return [...paths]
}
return filterPathsToWslDistros(paths, await listRunningWslDistrosAsync())
const runningDistros = paths.some(isWslUncPath) ? await listRunningWslDistrosAsync() : []
return filterPathsToWslDistros(paths, runningDistros)
}