Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion config/build-plugins/plain-node-entry-guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ const WORKER_THREAD_ENTRY_NAMES = [
'stt-worker',
'warp-theme-parser-worker',
'foreign-sqlite-reader-entry',
'session-scanner-worker-entry',
'main-thread-hang-watchdog-entry',
'port-scan-command-worker-entry',
'usage-scan-worker-entry',
Expand Down
1 change: 0 additions & 1 deletion config/knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"src/main/speech/stt-worker.ts",
"src/main/warp-themes/warp-theme-parser-worker.ts",
"src/main/foreign-sqlite-readers/foreign-sqlite-reader-entry.ts",
"src/main/ai-vault/session-scanner-worker-entry.ts",
"src/main/ports/port-scan-command-worker-entry.ts",
"src/main/ipc/parcel-watcher-process-entry.ts",
"src/main/hang-watchdog/main-thread-hang-watchdog-entry.ts",
Expand Down
28 changes: 14 additions & 14 deletions config/reliability-gates.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -12107,18 +12107,18 @@
"https://github.com/stablyai/orca/pull/12778"
],
"invariant": "Typing, focus, terminal switch, workspace switch, visibility resume, resize, render, per-pane liveness, and tab-title synchronization must not call global pty:listSessions or aiVault.listSessions; they must use targeted APIs or cached provider-owned state.",
"oracle": "The current executable slice asserts targeted visibility/first-input liveness, resize re-assertion after visibility resume, light tab/active-state resume, SSH/remote skip behavior, and a closed Resource Manager budget of one readiness seed plus one coalesced inventory read only for unknown spawn IDs. AI Vault title sync deterministically accepts only resolveSessionTitles, batches at most 64 exact identities, serializes worker work, routes requests to the transcript-owning local/SSH/runtime host, and proves zero broad scans for unsupported hosts. The full hot-path oracle still needs instrumentation around raw focus, split focus, workspace switch, render ticks, and high-session PTY fixtures.",
"oracle": "The current executable slice asserts targeted visibility/first-input liveness, resize re-assertion after visibility resume, light tab/active-state resume, SSH/remote skip behavior, and a closed Resource Manager budget of one readiness seed plus one coalesced inventory read only for unknown spawn IDs. AI Vault title sync deterministically accepts only resolveSessionTitles, batches at most 64 exact identities, bounds scanner-service calls at sixteen, routes requests to the transcript-owning local/SSH/runtime host, and proves zero broad scans for unsupported hosts. The full hot-path oracle still needs instrumentation around raw focus, split focus, workspace switch, render ticks, and high-session PTY fixtures.",
"commands": [
"pnpm exec vitest run --config config/vitest.config.ts src/main/ipc/pty-startup-barrier-and-listing.test.ts src/renderer/src/components/status-bar/use-resource-session-inventory.test.tsx src/renderer/src/components/status-bar/resource-session-inventory.test.ts src/renderer/src/components/status-bar/ResourceUsageStatusSegment.session-polling.test.ts",
"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/ai-vault-tab-title-sync.test.ts src/main/ai-vault/session-scanner-worker-client.test.ts src/main/ai-vault/session-title-file-reader.test.ts src/main/ai-vault/session-parse-cache-persistence.test.ts src/main/ipc/ai-vault.test.ts src/main/runtime/rpc/methods/ai-vault.test.ts src/relay/ai-vault-handler.test.ts"
"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/ai-vault-tab-title-sync.test.ts src/main/ai-vault/session-scanner-service-client.test.ts src/main/ai-vault/session-title-file-reader.test.ts src/main/ai-vault/session-parse-cache-persistence.test.ts src/main/ipc/ai-vault.test.ts src/main/runtime/rpc/methods/ai-vault.test.ts src/relay/ai-vault-handler.test.ts"
],
"testFiles": [
"src/main/ipc/pty-startup-barrier-and-listing.test.ts",
"src/renderer/src/components/status-bar/use-resource-session-inventory.test.tsx",
"src/renderer/src/components/status-bar/resource-session-inventory.test.ts",
"src/renderer/src/components/status-bar/ResourceUsageStatusSegment.session-polling.test.ts",
"src/renderer/src/lib/ai-vault-tab-title-sync.test.ts",
"src/main/ai-vault/session-scanner-worker-client.test.ts",
"src/main/ai-vault/session-scanner-service-client.test.ts",
"src/main/ai-vault/session-title-file-reader.test.ts",
"src/main/ai-vault/session-parse-cache-persistence.test.ts",
"src/main/ipc/ai-vault.test.ts",
Expand Down Expand Up @@ -12168,12 +12168,12 @@
]
},
{
"file": "src/main/ai-vault/session-scanner-worker-client.test.ts",
"file": "src/main/ai-vault/session-scanner-service-client.test.ts",
"assertions": [
"full scans and exact-title reads share one serial FIFO worker",
"active cancellation stays serialized and queued work remains bounded",
"worker faults restart queued work and idle time preserves incremental parse state",
"worker disposal rejects retained work and terminates the worker"
"the service waits for ready and runs the cache and interactive lanes independently",
"active and queued calls are bounded together at sixteen",
"cancellation reaches active work and kills a service that ignores it",
"service faults restart queued work under a restart circuit that a forced refresh reopens"
]
},
{
Expand Down Expand Up @@ -12202,13 +12202,13 @@
"summary": "4 files and 358 tests passed, covering readiness seed/recovery, zero interval polling, bounded unknown-spawn reconciliation, concurrent provider starts, exit fencing, cleanup, and out-of-order refresh fencing."
},
{
"date": "2026-08-09",
"date": "2026-10-02",
"runner": "local",
"platform": "macos",
"command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/ai-vault-tab-title-sync.test.ts src/main/ai-vault/session-scanner-worker-client.test.ts src/main/ai-vault/session-title-file-reader.test.ts src/main/ai-vault/session-parse-cache-persistence.test.ts src/main/ipc/ai-vault.test.ts src/main/runtime/rpc/methods/ai-vault.test.ts src/relay/ai-vault-handler.test.ts",
"command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/lib/ai-vault-tab-title-sync.test.ts src/main/ai-vault/session-scanner-service-client.test.ts src/main/ai-vault/session-title-file-reader.test.ts src/main/ai-vault/session-parse-cache-persistence.test.ts src/main/ipc/ai-vault.test.ts src/main/runtime/rpc/methods/ai-vault.test.ts src/relay/ai-vault-handler.test.ts",
"result": "passed",
"durationSeconds": 3.1,
"summary": "The focused run passed 112 tests across 7 files, proving exact-title-only renderer requests, provider-isolated batching, persistent serial worker lifecycle and fault recovery, exact transcript identity, host routing, mixed-version degradation, and zero broad-scan fallback."
"durationSeconds": 5.3,
"summary": "The focused run passed 138 tests across 7 files, proving exact-title-only renderer requests, provider-isolated batching, per-lane scanner-service lifecycle and fault recovery, exact transcript identity, host routing, mixed-version degradation, and zero broad-scan fallback."
}
],
"runtimeBudget": {
Expand All @@ -12221,11 +12221,11 @@
},
"redGreenEvidence": {
"status": "partial",
"evidence": "Tests assert visibility resume prefers targeted hasPty over listSessions, first input after visibility resume calls targeted hasPty once, resize re-assertion after visibility resume uses getSize/resize without listSessions, light tab switches and visible active-state resume avoid listSessions/hasPty/getSize fanout, and the closed Resource Manager performs one readiness seed while known reattach signals and steady time perform no additional reads. For the #12778 regression, title sync no longer receives a listSessions dependency at all: it sends at most 64 exact identities per batch to one serial worker or transcript-owning remote host, and old hosts degrade without broad fallback. Needs broader raw focus/workspace-switch/render/high-session PTY count coverage before promotion."
"evidence": "Tests assert visibility resume prefers targeted hasPty over listSessions, first input after visibility resume calls targeted hasPty once, resize re-assertion after visibility resume uses getSize/resize without listSessions, light tab switches and visible active-state resume avoid listSessions/hasPty/getSize fanout, and the closed Resource Manager performs one readiness seed while known reattach signals and steady time perform no additional reads. For the #12778 regression, title sync no longer receives a listSessions dependency at all: it sends at most 64 exact identities per batch to the local scanner service or transcript-owning remote host, and old hosts degrade without broad fallback. Needs broader raw focus/workspace-switch/render/high-session PTY count coverage before promotion."
},
"performanceBudget": {
"required": true,
"evidence": "This gate is the performance budget for global session listing in hot paths. AI Vault title sync permits zero global scans, at most 64 exact identities per request, one active worker operation, 16 queued operations, four concurrent transcript parses inside the worker, a 4,096-title index, and no worktree-path-triggered refresh. The worker emits the aiVault.scan.worker span with duration and session count for full scans."
"evidence": "This gate is the performance budget for global session listing in hot paths. AI Vault title sync permits zero global scans, at most 64 exact identities per request, one active scanner-service call per lane (cache, interactive), 16 active plus queued calls, four concurrent transcript parses inside the service, a 4,096-title index, and no worktree-path-triggered refresh. The service emits the aiVault.scan.service span with duration and session count for full scans."
},
"promotionCriteria": [
"Add deterministic call-count instrumentation.",
Expand Down
2 changes: 0 additions & 2 deletions config/scripts/ci-shard-timings.json
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,6 @@
"src/main/ai-vault/session-scanner-agent-root-overrides.test.ts": 1121,
"src/main/ai-vault/session-scanner-antigravity-parser.test.ts": 72,
"src/main/ai-vault/session-scanner-antigravity-source.test.ts": 330,
"src/main/ai-vault/session-scanner-background.test.ts": 354,
"src/main/ai-vault/session-scanner-claude-cwd-drift.test.ts": 245,
"src/main/ai-vault/session-scanner-claude-subagent-prune.test.ts": 170,
"src/main/ai-vault/session-scanner-claude-subagents.test.ts": 137,
Expand Down Expand Up @@ -706,7 +705,6 @@
"src/main/ai-vault/session-scanner-timeline.test.ts": 75,
"src/main/ai-vault/session-scanner-unlimited-dedup.test.ts": 3562,
"src/main/ai-vault/session-scanner-values.test.ts": 92,
"src/main/ai-vault/session-scanner-worker-client.test.ts": 48,
"src/main/ai-vault/session-scanner.test.ts": 343,
"src/main/ai-vault/session-sidecar-stat.test.ts": 25,
"src/main/ai-vault/session-title-file-reader-wsl-stall.test.ts": 173,
Expand Down
3 changes: 0 additions & 3 deletions electron.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,6 @@ export const electronViteConfig: UserConfig = {
'foreign-sqlite-reader-entry': resolve(
'src/main/foreign-sqlite-readers/foreign-sqlite-reader-entry.ts'
),
'session-scanner-worker-entry': resolve(
'src/main/ai-vault/session-scanner-worker-entry.ts'
),
'session-scanner-service-entry': resolve(
'src/main/ai-vault/session-scanner-service-entry.ts'
),
Expand Down
16 changes: 8 additions & 8 deletions src/main/ai-vault/cached-session-list-wsl-probe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ 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(() => ({
const { execFileMock, scanAiVaultSessionsInService } = vi.hoisted(() => ({
execFileMock: vi.fn(),
scanAiVaultSessionsInWorker: vi.fn()
scanAiVaultSessionsInService: vi.fn()
}))

vi.mock('child_process', async (importOriginal) => ({
...(await importOriginal<typeof childProcess>()),
execFile: execFileMock
}))
vi.mock('./session-scanner-worker-spawn', () => ({
scanAiVaultSessionsInWorker,
resetAiVaultScannerWorkerForTests: vi.fn()
vi.mock('./session-scanner-service-spawn', async (importOriginal) => ({
...(await importOriginal<object>()),
scanAiVaultSessionsInService
}))
vi.mock('./opencode-wsl-runtime-preparation', () => ({
prepareOpenCodeWslReaders: vi.fn(async () => [])
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('AI Vault listing wsl.exe probes', () => {
vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
resetAiVaultSessionListCacheForTests()
configureAiVaultSessionSources({ getAdditionalCodexHomePaths: () => [NATIVE_CODEX_HOME] })
scanAiVaultSessionsInWorker.mockResolvedValue({ sessions: [], issues: [], scannedAt: 'scan' })
scanAiVaultSessionsInService.mockResolvedValue({ sessions: [], issues: [], scannedAt: 'scan' })
})
afterEach(() => {
execFileMock.mockReset()
Expand All @@ -59,7 +59,7 @@ describe('AI Vault listing wsl.exe probes', () => {
await listAiVaultSessions()

expect(wslSpawns()).toEqual([])
expect(scanAiVaultSessionsInWorker).toHaveBeenCalledWith(
expect(scanAiVaultSessionsInService).toHaveBeenCalledWith(
expect.objectContaining({
additionalCodexSessionsDirs: [join(NATIVE_CODEX_HOME, 'sessions')],
wslHomeDirs: []
Expand All @@ -80,7 +80,7 @@ describe('AI Vault listing wsl.exe probes', () => {
['--list', '--running', '--quiet'],
['-d', 'Ubuntu', '--exec', 'bash', '-c', 'echo $HOME']
])
expect(scanAiVaultSessionsInWorker).toHaveBeenCalledWith(
expect(scanAiVaultSessionsInService).toHaveBeenCalledWith(
expect.objectContaining({ wslHomeDirs: [WSL_HOME] }),
expect.anything()
)
Expand Down
22 changes: 11 additions & 11 deletions src/main/ai-vault/cached-session-list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ const {
getCachedWslDistros,
hasCachedWslDistros,
listRunningWslHomeDirsAsync,
scanAiVaultSessionsInWorker
scanAiVaultSessionsInService
} = 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()
scanAiVaultSessionsInService: vi.fn()
}))

vi.mock('./session-scanner-worker-spawn', () => ({
scanAiVaultSessionsInWorker,
resetAiVaultScannerWorkerForTests: vi.fn()
vi.mock('./session-scanner-service-spawn', async (importOriginal) => ({
...(await importOriginal<object>()),
scanAiVaultSessionsInService
}))
vi.mock('../wsl', () => ({
getCachedWslDistros,
Expand All @@ -43,7 +43,7 @@ function scanResult(scannedAt: string): AiVaultListResult {
// mid-flight.
function deferredScan(): { resolve: (value: AiVaultListResult) => void } {
let resolveFn: (value: AiVaultListResult) => void = () => {}
scanAiVaultSessionsInWorker.mockReturnValueOnce(
scanAiVaultSessionsInService.mockReturnValueOnce(
new Promise<AiVaultListResult>((resolve) => {
resolveFn = resolve
})
Expand All @@ -60,7 +60,7 @@ describe('invalidateAiVaultSessionListCache generation guard', () => {
getCachedWslDistros.mockReset().mockReturnValue(null)
hasCachedWslDistros.mockReset().mockReturnValue(false)
listRunningWslHomeDirsAsync.mockReset().mockResolvedValue([])
scanAiVaultSessionsInWorker.mockReset()
scanAiVaultSessionsInService.mockReset()
})
afterEach(() => {
resetAiVaultSessionListCacheForTests()
Expand All @@ -81,22 +81,22 @@ describe('invalidateAiVaultSessionListCache generation guard', () => {

// A non-force list must re-scan (cache empty) rather than serve A's stale
// result — proof A's late .then() did not repopulate the cache.
scanAiVaultSessionsInWorker.mockResolvedValueOnce(scanResult('scan-B'))
scanAiVaultSessionsInService.mockResolvedValueOnce(scanResult('scan-B'))
const next = await listAiVaultSessions()

expect(next.scannedAt).toBe('scan-B')
expect(scanAiVaultSessionsInWorker).toHaveBeenCalledTimes(2)
expect(scanAiVaultSessionsInService).toHaveBeenCalledTimes(2)
})

it('caches normally when no invalidation interrupts the scan', async () => {
scanAiVaultSessionsInWorker.mockResolvedValueOnce(scanResult('scan-A'))
scanAiVaultSessionsInService.mockResolvedValueOnce(scanResult('scan-A'))
await listAiVaultSessions()

// Second non-force call is a cache hit — no second scan.
const cached = await listAiVaultSessions()

expect(cached.scannedAt).toBe('scan-A')
expect(scanAiVaultSessionsInWorker).toHaveBeenCalledTimes(1)
expect(scanAiVaultSessionsInService).toHaveBeenCalledTimes(1)
expect(listRunningWslHomeDirsAsync).toHaveBeenCalledTimes(1)
})

Expand Down
36 changes: 0 additions & 36 deletions src/main/ai-vault/session-scanner-background.test.ts

This file was deleted.

Loading
Loading